Wikilivres frwikibooks https://fr.wikibooks.org/wiki/Accueil MediaWiki 1.47.0-wmf.8 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 Dictionnaire de philosophie/Vérité 0 2700 768755 753983 2026-06-27T05:32:06Z PandaMystique 119061 Bot : ajout du paramètre lecture=oui au modèle {{DicoPhilo}} 768755 wikitext text/x-wiki {{DicoPhilo|Vérité|lecture=oui}} La définition la plus simple de la vérité pourrait être la suivante : ce que nous disons ou pensons est vrai quand ce que nous avons en vue existe vraiment tel que nous le disons ou le pensons. De ce fait, la vérité serait l'image correcte, ou la connaissance, que nous avons de la réalité. :''Organisation de l'article'' : cet article est divisé en deux grandes parties. Dans la première partie, nous avons organisé une réflexion sur la vérité en suivant un fil directeur énoncé ci-dessus. Il nous a semblé préférable de procéder ainsi afin d'éviter de faire un catalogue d'opinions philosophiques et d'offrir un texte structuré qui pourra, s'il atteint son but, donner une idée du travail philosophique que l'on doit fournir dans une dissertation. Le défaut de cette présentation est que cet exposé, même si nous avons pris soin de formuler des points de vue variés et diverses objections, est inévitablement sélectif et orienté. La seconde grande partie vient remédier en partie à ce défaut, en proposant des extraits aussi variés que possibles de textes classiques et en fournissant une liste de sujets de dissertation. == Quelques remarques pour commencer == [[Fichier:Encyclopedie frontispice section 256px.jpg|thumb|200px|La Vérité rayonnante.]] Cette définition de la vérité, que nous plaçons en tête de ce chapitre et que nous allons avoir l'occasion de discuter, soulève de deux types de problèmes. <u><span style="color:green">Premier problème</span></u> : la vérité apparaît comme une qualité que nous attribuons à ce que nous disons ou pensons : cette phrase est vraie, cette idée est vraie, et la vérité n'existe pas à part de ce que nous qualifions de vrai. La question se pose donc de savoir à quoi exactement nous attribuons cette qualité (une phrase ou une idée) et si nous avons raison de penser que la vérité est quelque chose que nous attribuons. <u><span style="color:green">Second problème</span></u> : la vérité n'est attribuée que sous certaines conditions : il faut une idée ou une pensée de quelque chose, et également quelque chose qui existe dont nous avons l'idée et dont nous parlons. Dans ce cas, il y a une relation entre deux termes : la pensée et la réalité, et, en dehors de cette relation, parler de vérité n'a pas de sens. Quelle est alors la nature de cette relation ? comment savons-nous que l'image que nous avons de la réalité est fidèle ? et comment la réalité peut-elle se refléter dans notre esprit en sorte que nous puissions posséder la vérité ? Afin de ne pas alourdir cet article, nous ne donnerons pas de références en notes. Toutes les références utilisées peuvent être retrouvées dans la bibliographie commentée et dans les extraits que nous donnons dans la section ''Textes''. == Qu'est-ce que nous disons être vrai ou faux ? == À quoi donnons-nous la qualité d'être vrai ? Nous avons dès le début supposé que la vérité résidait dans des phrases (ce que nous disons à propos de la réalité) ou des pensées (les idées que nous avons des choses). Nous commencerons par ce problème, sans pourtant avoir répondu à ce stade à la question de savoir ce qu'est la vérité : en examinant dans quels cas nous parlons de vérité, nous parviendrons peut-être à déterminer les usages corrects (s'il y en a) de cette notion, ce qui aura ensuite l'avantage de nous en faciliter la compréhension. === Phrase et proposition === Il nous semble évident que les phrases disent des choses vraies ou fausses, comme nous l'avons supposé dès le début. Cette idée, dans sa généralité, est pourtant fausse. « Va me chercher du pain ! » est une phrase, mais elle n'est ni vraie ni fausse ; c'est un ordre. Il existe ainsi de nombreuses phrases que nous utilisons quotidiennement qui sont dans ce cas : les phrases qui expriment une demande (« pourriez-vous etc. »), un souhait (« je souhaiterais etc. »). Faut-il en conclure que les phrases ne disent rien de vrai ou de faux ? Évidemment non, car certaines phrases sont effectivement vraies ou fausses : « il pleut », « mon bureau est blanc », etc. Pour distinguer ces phrases des autres, nous appellerons « proposition » les phrases qui ont cette qualité de pouvoir être vraie ou fausse. <div style="font-color:#535068; border:solid 1px #A8A8A8; padding:0.5em 1em 0.5em 0.7em; margin:0.5em 0em;"> {|align=center |[[File:Nuvola apps forward arrow.svg|20px]] |<div style="text-align: center;">''Première caractérisation'' : Une proposition est une phrase qui peut être vraie ou fausse.</div> |} </div> Ces propositions, telles que nous les définissons, ne sont pas vraies en elles-mêmes : nous disons qu'elles ''peuvent'' énoncer une vérité ''ou'' une erreur. Cela semble tenir au fait que la proposition énonce quelque chose à propos d'une réalité indépendante de nous : « il pleut » peut être vraie quand je vois qu'il pleut, mais fausse plus tard quand il ne pleut plus. Une proposition prétend donc nous informer sur un état de choses, et elle décrit correctement ou non cet état de choses. Nous pouvons alors énoncer les deux caractéristiques suivantes : <div style="font-color:#535068; border:solid 1px #A8A8A8; padding:0.5em 1em 0.5em 0.7em; margin:0.5em 0em;"> {|align=center |[[File:Nuvola apps forward arrow.svg|20px]] |<div style="text-align: center;">''Deuxième caractérisation'' : Une proposition prétend nous apprendre quelque chose à propos d'un état de choses.</div> |} </div> <div style="font-color:#535068; border:solid 1px #A8A8A8; padding:0.5em 1em 0.5em 0.7em; margin:0.5em 0em;"> {|align=center |[[File:Nuvola apps forward arrow.svg|20px]] |<div style="text-align: center;">''Troisième caractérisation'' : Une proposition est vraie ou fausse selon qu'elle s'accorde ou non avec un état de choses.</div> |} </div> Nous examinerons plus loin ces conditions de la vérité d'une proposition, mais remarquons que le fait d'être vrai semble impliquer la possibilité d'être faux. Une proposition ne peut-elle pourtant pas toujours être vraie ? Sans doute, si elle exprime une réalité qui est toujours comme nous en parlons. Mais le monde extérieur est changeant, et cela laisse peu d'espoir de trouver des propositions toujours vraies. Pourtant, il est une sorte de proposition qui semble posséder cette qualité : ce sont les propositions mathématiques. En effet, de quelque manière qu'on l'envisage, 2 + 2 = 4 est toujours vraie. Seulement, les propositions mathématiques ne parlent pas des objets du monde extérieur ; quel genre de réalités peuvent être les objets mathématiques est une question difficile que nous n'aborderons pas ici. Contentons-nous de dire qu'il y a des propositions qui portent sur le monde extérieur et qu'elles sont vraies ou fausses, et qu'il y en a d'autres qui portent peut-être sur autre chose et qu'elles semblent pouvoir être toujours vraies. Cependant, si nous regardons d'un peu plus près ces rapports différents à la vérité et à la fausseté, nous sommes amenés à nous demander s'il ne faut pas distinguer des propositions de ''nature'' différente. En effet, dans le premier cas, la vérité (ou la fausseté) dépend d'un lien avec la réalité : « il pleut » reflète ou non le fait qu'il pleut. Mais que reflète « 2 + 2 = 4 » ? Loin d'avoir besoin d'une réalité empirique pour être vraie, cette phrase paraît être vraie en vertu de la définition des signes qu'elle contient, ou de ce que veulent dire ses termes et ses symboles et de la manière dont nous les utilisons (« 2 », « + », « = »). Nous n'allons pas tout de suite examiner ce problème, afin de poursuivre notre enquête sur ce que nous disons être vrai ou faux. Retenons pour le moment qu'il y a à l'évidence différents genres de phrases (les propositions) que nous disons êtres vrais ou faux, et que ces propositions ne sont sans doute pas vraies ou fausses pour les mêmes raisons et dans les mêmes conditions. Enfin, nous devons considérer le type de réalité qu'est la proposition, afin de savoir exactement ce que nous qualifions de vrai ou de faux. Nous avons dit que la proposition est phrase. Elle se présente en effet comme telle. Considérons cependant les deux phrases suivantes : # « il pleut », et : # « es regnet ». Nous avons là deux phrases distinctes, la première en Français, la seconde traduisant la première en Allemand. Ce sont toutes deux des propositions, puisqu'elles portent sur un état de choses et qu'elles peuvent être vraies ou fausses. Admettons qu'elles portent sur le ''même'' état de choses (c'est le même phénomène météorologique qui est décrit, au même endroit, au même moment). Il faut alors en conclure que ces deux phrases différentes sont en fait ''une seule et même'' proposition, et qu'une proposition n'est pas simplement un certain type de phrases composées de signes déterminés (lettres, mots associés par des règles de grammaire), puisqu'elle peut être traduite en différentes langues en restant la même proposition. Il y a donc des phrases qui sont des propositions, mais la proposition n'est pas à proprement parler une phrase déterminée. Qu'est-ce alors qu'une proposition ? Si nous regardons nos deux exemples, nous pourrions dire qu'elles expriment toutes deux la même ''idée'' à propos d'une certaine réalité. La proposition ne serait-elle pas alors une certaine sorte d'idée ou de réalité mentale que nous pouvons exprimer de manière sensible, par des signes écrits ou des sons ? Il nous faut, pour tenter d'y répondre, examiner ce que nous entendons par ce terme d'« idée ». === Nos idées === [[File:Qualia of colour.jpg|right|250px]] J'ai par exemple l'idée qu'il pleut et il se trouve qu'il pleut. Il nous semblent ainsi évident que nos idées sont vraies ou fausses, et, dans ce cas, nous pensons à des idées que nous pouvons énoncer, comme nous l'avons dit ci-dessus, sous la forme de phrases. La proposition, vraie ou fausse, serait donc une sorte d'idée située ''dans'' notre tête, donc une réalité mentale, et la phrase serait l'expression sensible d'une idée ou d'un certain genre d'idées nommé « proposition ». Mais, comme dans le cas de la phrase, ce n'est peut-être pas une généralité que l'idée peut être vraie ou fausse. Nous devons chercher s'il y a des idées qui auraient, contrairement à d'autres, la particularité d'être des propositions parce qu'elles peuvent être vraies ou fausses. Mais nous parlons d'idée à propos de toutes sortes de réalités mentales, ce qui ne facilite pas notre recherche. Appelons « idée » toutes les représentations, images, pensées, qui peuvent nous venir à l'esprit. Parmi ces idées, nous en trouvons dont nous pourrions peut-être dire qu'elles ne sont ni vraies ni fausses : nos rêveries, par exemple, même si nous pourrions dire qu'elles sont fausses car elles ne correspondent à aucune réalité, ne sont toutefois imaginées par nous que pour le plaisir et pour elles-mêmes, et non dans le but d'être vraies. Toutes les images que nous formons semblent ainsi faites que nous puissions les tenir pour vraies ou fausses, sans qu'un tel jugement soit cependant nécessaire : je peux simplement me représenter une chose (réelle ou pas) sans rien affirmer de sa réalité. Cette dernière caractéristique nous suggère qu'il pourrait en être ainsi à propos des propositions : si une proposition est l'expression sensible d'une idée qui peut être vraie et fausse, mais que cette idée peut être pensée sans rien affirmer de la vérité ou de la fausseté de son contenu, une proposition ne pourrait-elle pas être aussi une simple assertion n'impliquant aucun ''jugement de vérité ?'' Dans ce cas, bien que la proposition puisse être vraie ou fausse, un acte de l'esprit, le ''jugement'', doit s'ajouter à elle pour que nous puissions déterminer sa vérité ou sa fausseté. Nous reviendrons plus loin sur cette question. Pour le moment, considérons nos idées en général ; par définition, toute idée représente quelque chose (nous avons toujours l'idée ''de quelque chose'', la notion d'idée en elle-même est dépourvue de sens). De ce fait, toute idée peut être vraie ou fausse. Quand, par une phrase, j'exprime un souhait qui n'est ni vrai ni faux, l'idée que j'ai de ce souhait semble bien devoir être vrai ou faux. Néanmoins il ne s'agit pas de l'énoncé du souhait en lui-même, mais de la réalité de ce souhait et de ce que je souhaite, car je peux me tromper sur ce que je souhaite vraiment. Et il en va de même des objets du désir, de la volonté, etc. Toutefois, dire que ce type de réalités peut être vrai ou faux est sujet à discussion, car il faut par exemple faire appel à un terme caché (ce que je souhaite vraiment quand je me trompe sur mes aspirations véritables) pour qualifier un souhait de faux, ce qui ne contribue pas à clarifier le problème. Cependant, parmi nos idées, nous en trouvons qui sont manifestement liées en elle-même à un jugement de vérité : ce sont l'opinion, la croyance, le savoir, la certitude, la foi, etc. ; toutes ces idées contiennent en effet des affirmations sur l'existence et la manière dont existent certains objets, et il semble bien que la vérité et la fausseté de ces affirmations constituent une partie importante de la manière dont nous pouvons les décrire et les comprendre. Il serait ainsi absurde de dire à la fois : « je sais ou je crois qu'il pleut » et « j'ai l'idée qu'il pleut, mais je n'affirme rien quant à la réalité que représente cette idée ». Nous avons donc là clairement des réalités mentales auxquelles nous pouvons attribuer la vérité et la fausseté. Mais il est aussi évident que ce n'est pas de la même manière que nous attribuons ces qualités à chacune d'entre elles. Examinons brièvement ce point. *<u><span style="color:red">l'opinion</span></u> : nous exprimons ordinairement des opinions à tout propos, et toutes ces opinions ne sont pas fondées de la même manière, mais peuvent être justifiés par des motifs extrêmement variés : des on-dits, des préférences irréfléchies, l'habitude, les traditions, etc. L'opinion est ainsi une sorte de jugements subjectifs qui s'accommodent de l'ignorance et des préjugés, mais que nous revendiquons cependant parfois comme ''nos'' opinions. Elle a donc un caractère subjectif très marqué, et cela se traduit par des degrés subjectifs de certitude que nous exprimons par des termes psychologiques : « je suis persuadé, convaincu que ». *<u><span style="color:red">la croyance</span></u> : dans le langage de tous les jours, la croyance se distingue assez peu de l'opinion : « je pense que », « je crois que », « mon avis est que », expriment également des opinions et des croyances que nous tenons pour vraies, quoique leur justification soit très vague. Pourtant, dans certains cas, le mot « croyance » semble bien insister sur le fait que nous tenions une proposition pour vraie en mettant plus en avant l'objet ou le contenu d'un jugement que ne le fait l'opinion, plutôt centrée quant à elle sur l'individu qui s'exprime. La croyance semble alors correspondre à un état de certitude plus objectif. À l'évidence, pourtant, ce n'est pas toujours vrai, car nous disons « je crois en Dieu », en désignant un objet dont l'existence objective est difficile à attester. Néanmoins, dans ce cas, on parle plutôt de ''foi'', et la certitude que cette foi exprime est appelée un acte de foi. *<u><span style="color:red">la connaissance</span></u>, le savoir : toutes nos connaissances sont des croyances. Nous pouvons par exemple croire que la vitesse est la distance divisée par le temps. Cette croyance est un savoir si elle décrit correctement la réalité sur laquelle elle porte. Puisque l'idée de connaissance fausse est une contradiction, nous pouvons dire que la connaissance est toujours vraie. Nous voyons par là un lien entre vérité et connaissance : chercher ce qu'est la vérité, cela peut bien être également se demander ce qui fait qu'une pensée est une connaissance (et pas simplement une croyance ou une opinion). Ces quelques remarques nous permettent de faire une importante distinction : l'opinion, la croyance, le savoir, etc. ont un ''contenu objectif'', c'est-à-dire qu'ils désignent un certain fait, à tort ou à raison ; mais ils font également l'objet d'un ''état du sujet'' (la conviction par exemple). Or, quand une personne énonce un jugement et que nous souhaitons éprouver la vérité ou la fausseté de ce jugement, la question de savoir dans quel état se trouve la personne est sans pertinence. Ainsi, si Pierre affirme qu'il est convaincu que Marie l'aime, nous avons un état de conviction de Pierre et un contenu de sa conviction : # Pierre est convaincu que Marie l'aime ; # Marie aime Pierre. L'examen de la vérité de la conviction de Pierre ne portera pas sur la proposition 1, mais sur la 2. Autrement dit, la vérité et la fausseté de ce qu'énonce un individu sont indépendantes de l'état dans lequel il se trouve, et la proposition que nous avons à examiner est l'énoncé du contenu de la conviction, de la croyance, etc. Nous pouvons maintenant réviser notre idée de ce qu'est une proposition. Nous avons vu que la proposition n'est pas une phrase. Mais elle n'est pas non plus simplement une idée. Selon la distinction que nous venons de faire, nous devons dire que la proposition est le contenu d'une croyance, en donnant à ce terme de croyance un sens large (comme une opinion ou un savoir). Et c'est ce contenu que nous tenons pour vrai ou faux. === Sensation et perception === {{Loupe|Philosophie/Perception}} [[Fichier:Mond-vergleich.svg|right|290px]] Lorsque nous avons abordé les idées, nous avons du mal à distinguer celles qui peuvent être exprimées par des propositions vraies ou fausses de ces mêmes idées considérées comme ''contenu''. Aussi, une autre catégorie de réalités que nous pourrions qualifier de vraies ou de fausses sont les réalités mêmes dont nous parlons et auxquelles nous pensons, c'est-à-dire le contenu de nos propositions et de nos idées, désignant tous les objets des sens, ainsi que ces réalités plus difficiles à saisir que sont nos passions, nos sentiments, nos volontés, nos pensées, etc. À première vue, toutes ces réalités, même si nous disons vrai à leur propos, ne sont pas vraies en elles-mêmes. ''Un arbre, ce rouge, la colère, vouloir marcher'' ne sont pas des réalités vraies, mais simplement des réalités : elles existent, et c'est le fait qu'elles existent qui nous permet de dire des vérités à leur propos si nous en parlons en les décrivant comme elles sont. Pourtant, ne sommes-nous pas victimes d'illusions des sens ? Dans ce cas, ce sont bien les sens qui se trompent. Or, s'ils se trompent, c'est qu'ils sont dans l'erreur, et s'ils sont dans l'erreur, c'est que, habituellement, ils sont dans le vrai. Les données que nous fournissent nos sens seraient donc vraies en ce sens que les sens nous offrent une image correcte de la réalité et ils seraient dans l'erreur dans le cas contraire. Cette conception est discutable. En effet, nous avons vu que, pour qu'il y ait vérité, il faut une relation entre une réalité et quelque chose qui décrit cette réalité. Il faudrait donc que les sens nous donnent à la fois une intuition d'une réalité et l'image de cette réalité. Mais ce que nous appelons sensation, c'est justement cette intuition de la réalité par les sens, tandis que l'image de la réalité est une représentation, c'est-à-dire que c'est l'idée que nous avons d'une réalité et cette idée est le fait de l'esprit. Il n'en reste pas moins, pourriez-vous objecter, que nous parlons d'illusions des sens, et c'est pourquoi ce sont les sens qui se trompent et une sensation peut être vraies ou fausses. La preuve en est que, de loin, je vois ronde une tour carrée, et il y a ainsi mille exemples qui démontrent que ce sont les sens qui se trompent en nous donnant à voir ce qui n'existe pas. Donc, quand ils ne se trompent pas, les sens sont véridiques. Mais cette objection repose sur une confusion entre l'impression sensible que nous avons de certaines formes, et les jugements que nous formulons à leur propos. En effet, tant que, voyant au loin une forme qui ressemble à une tour ronde, je ne juge pas que ce que je vois est une tour réellement ronde, je ne suis pas dans l'erreur, et mes sens, qui ne m'offre que la vision d'une forme, ne me disent rien sur la réalité de ce que je vois. Ainsi les sens ne sont-ils ni vrais ni faux : :« [...] en général [Les sens] ne mentent pas. C’est ce que nous faisons de leur témoignage qui y met le mensonge, par exemple le mensonge de l’unité, le mensonge de la réalité, de la substance, de la durée... » Friedrich Nietzsche, ''Le Crépuscule des idoles'', « La "raison" dans la philosophie ». Cette thèse, défendue par des philosophes aussi différents qu'Épicure et Nietzsche, ne semble toutefois pas si facile à soutenir. Si vous avez regardé l'illustration située au début de cette section, vous avez vu deux ronds oranges de taille différente. En réalité, ces ronds sont identiques. Bien que vous le sachiez maintenant, vous continuez cependant à voir un cercle plus grand que l'autre, et cela, votre vue vous le montre et donc se trompe. Si nous disons avec Nietzsche que c'est ce que nous faisons des témoignages des sens qui y introduit l'erreur, comment pourrions-nous comprendre que l'erreur peut s'y trouver avant même que nous jugions par la raison de certaines propriétés des choses (comme sa forme ou ses dimensions), et même après ? bien plus, comment expliquer que des opérations aussi complexes que la comparaison puisse se trouver dans ces témoignages ? [[Fichier:Duck-Rabbit illusion.jpg|left|200px]] Nous pourrions alors distinguer deux choses pour tenter de voir plus clair dans ce problème : la sensation considérée en elle-même (cette couleur, cette forme, etc.), que nous pourrions définir comme l'ensemble des impressions brutes — voire originelles, qui se présentent à nous avant toute mise en ordre de quelque nature qu'elle soit ; et un autre type de sensations, élaborées à partir des premières, sensations par lesquelles nous voyons, touchons, supposons, etc., ''des objets possédant certaines qualités'', avant même de formuler une proposition à l'aide de nos facultés intellectuelles. Ces dernières sensations contiennent alors manifestement des jugements, qui échappent à notre raison, sur les qualités des choses et sur l'existence même des choses, comme nous pouvons en faire l'expérience dans les illusions d'optique ; afin de les distinguer des premières, nous les appellerons des ''perceptions.'' Ces perceptions peuvent-elles être considérées comme des propositions, au sens que nous avons donné plus haut à ce mot, et peut-on les placer au même rang que nos croyances et leurs contenus ? Ce que nous voulons savoir, c'est si les perceptions peuvent légitimement être dites vraies ou fausses. === Bilan === Tentons à présent de reprendre de manière synthétique l'ensemble de nos réflexions. Nous avons établi que nous disons vrais ou faux des jugements, et que nous pouvons exprimer ces jugements (qu'il s'agisse d'idées ou de perceptions) par une forme particulière de phrases que nous nommons ''propositions''. Ces jugements sont des mises en relations de réalités, comme la relation entre un objet et une qualité ou entre deux objets. Elles doivent en outre être tenues pour réelles ou niées et être comparées à ce sur quoi elles portent, c'est-à-dire qu'elles doivent être l'objet de nos croyances, opinions, savoirs, etc. Cependant, si nous faisons un bilan de nos réflexions d'après les différentes manières que nous avons vues pour une proposition d'être vraie (ou fausse), nous trouvons qu'il y a deux sortes de propositions : les propositions qui portent sur le monde extérieur et les propositions vraies en vertu des symboles qui les composent. Nous pouvons alors conclure cette partie en citant ces paroles du philosophe Alfred Ayer : :« [...] je divise toutes les propositions authentiques en deux classes : celles qui [...] concernent les "relations d'idées" et celles qui concernent les "matières de fait" (''matter of fact''). La première classe comprend les propositions ''a priori'' de la logique et des mathématiques pures, que je ne considère comme nécessaires et certaines, que parce qu'elles sont analytiques. Je maintiens, en effet, que la raison pour laquelle ces propositions ne peuvent être démenties par l'expérience, est qu'elles ne font aucune assertion au sujet du monde empirique, mais indiquent simplement notre détermination d'user de symboles d'une certaine manière. Par contre, les propositions empiriques concernant les matières de fait, je soutiens qu'elles sont des hypothèses qui peuvent être probables, mais jamais certaines. Et en exposant la méthode de leur validation, je prétends aussi élucider la nature de la vérité. » ''Langage, vérité et logique'', « Préface » La question de la nature de la vérité se ramène donc à la question de la méthode de validation de nos propositions : par quels moyens, procédés ou méthodes établissons-nous que nos propositions sont vraies ? À partir de nos remarques sur la nature de la proposition, voyons donc comment nous pouvons maintenant tenter d'élucider ce qu'est la vérité. == Quelle est la nature de la vérité ? == [[File:What_is_truth.jpg|thumb|right|"Qu'est-ce que la vérité ?" Le Christ et Pilate. Nikolaï Gay (1831–1894)]] À présent que nous avons passé en revue les réalités (propositions, idées telles que la croyance et l'opinion, perceptions) susceptibles de se voir attribuer la qualité de vérité, voyons dans quelles conditions nous sommes justifiés à faire une telle attribution. Ce que nous cherchons, ce sont en particulier des critères pour nous guider afin de pouvoir reconnaître une proposition et une pensée vraie (et donc également celles qui sont fausses). C'est en cela que nous faisons consister la ''nature'' de la vérité, c'est-à-dire que nous ne cherchons pas une réalité qui existerait à part et que nous nommerions ''Vérité'', mais des règles pour bien juger, et, le cas échéant, pour atteindre la plus grande certitude possible. === L'adéquation === ==== Définition ==== Commençons par l'idée que nous avons déjà largement esquissée, à savoir que la vérité est la qualité d'une proposition ou d'une pensée qui énonce une réalité telle qu'elle est. Dans cette conception de la vérité, nous avons une relation entre deux termes : une pensée que nous formulons par une proposition et une réalité sur laquelle porte cette proposition. Par exemple, si je dis : « Le chat est sur le tapis », ma proposition porte sur une réalité composée d'un chat et d'un tapis qui sont entre eux dans un certain rapport. Cette réalité n'est donc pas un objet isolé (comme « chat » ou « tapis »), mais un fait composé de deux objets dans une certaine relation (« être sur »). Cette composition se traduit dans ma proposition par un ''jugement'' qui énonce cette relation. En conséquence, nous pouvons supposer que la vérité d'une proposition est la correspondance entre un jugement que l'on énonce et une relation entre plusieurs objets, correspondance que l'on constate dans l'expérience (je vois le chat qui est sur le tapis). <div align="center"><div style="margin-top:4px; margin-bottom:4px; padding: 7px; background-color: #FFFF99; border: 3px solid #FFCC00; width:95%;"> <div style="font-size:12pt; font-weight:bold; border-bottom:1px solid #FFCC00;"><div style="text-align: center;">'''Définition 1'''</div></div> <div style="text-align: center;">Une proposition (un jugement, une croyance, une pensée, etc.) est vraie si, ''et seulement si'', elle correspond à un fait.</div> </div></div> <u><span style="color:red">Objections</span></u> : #Il semble néanmoins y avoir des cas qui ne correspondent pas à cette définition. Par exemple, si, voyant un arbre, je constate qu'il y a un arbre, il ne semble pas que ma proposition soit un jugement, mais qu'elle soit le simple constat de l'existence d'un objet, et ce constat est vrai (ou faux). Toutefois, au témoignage de mes sens (je vois une certaine forme colorée d'une certaine manière), s'ajoute mon affirmation que ce que je vois est un arbre et que cet arbre existe. Aussi peut-on penser que le prétendu constat intuitif est en réalité un jugement, et qu'il est conforme à la définition que nous avons donnée de la vérité comme adéquation. #Cette définition semble exclure ces propositions dont nous avons vu qu'elles paraissent être toujours vraies, comme les propositions des mathématiques. Nous aborderons ce problème dans la section suivante sur la vérité formelle. <u><span style="color:green">Remarque</span></u> : La conception de la vérité comme adéquation suppose que nous puissions vérifier les jugements que nous énonçons en constatant que ceux-ci reflètent bien la réalité dont nous parlons. Nous avons donc un rôle actif dans l'établissement de la vérité. Elle n'apparaît pas d'elle-même, mais est le résultat d'un jugement qui est dans mon esprit et d'une confrontation de ce résultat avec une vérification empirique. Par cette vérification, je dois pouvoir constater que ma proposition reflète bien la réalité : le fait dont je parle existe-t-il ou non ? existe-t-il tel que j'en parle, ou autrement ? <u>Problématique</u> : La question se pose de savoir ce qu'il faut entendre par « reflètent ». En philosophie, on emploie, plutôt que le mot « refléter », les termes de « correspondance » ou d' « adéquation » que nous avons eu déjà l'occasion d'employer. Qu'entendons-nous alors par ces deux termes ? À première vue, la réponse est simple : toute proposition serait une idée que nous avons à l'esprit et il suffirait de la comparer avec le témoignage de nos sens pour nous assurer de sa fidélité. Ainsi l'adéquation (ou la correspondance) est-elle une relation de ressemblance entre ce que nous jugeons et ce sur quoi nous jugeons. ==== Ressemblance/correspondance ==== [[File:Mirror baby.jpg|right|260px|Se reconnaît-il ?]] Cette conception pose plusieurs problèmes. Tout d'abord, lorsque nous parlons de ressemblance, il ne semble pas que nous ne fassions autre chose que de répéter l'idée même d'adéquation : être adéquat, c'est ressembler, mais ressembler, c'est être adéquat. Aussi l'idée de ressemblance demeure-t-elle mystérieuse. Et elle devient encore plus obscure si l'on cherche à comprendre de quelle manière un jugement pourrait ressembler à la réalité sur laquelle il porte. Nos propositions sont formées de mots (signes ou sons), alors que les réalités que ces mots désignent sont des objets physiques ou psychiques d'une autre sorte. Il n'y a de toute évidence aucune ressemblance entre les mots et les choses que les mots désignent. On pourrait dire alors (comme nous avons eu déjà l'occasion de le dire) que les propositions traduisent des images qui sont dans notre esprit, et que ce sont ces images qui sont formées fidèlement ou non sur le modèle des réalités extérieures. Ainsi Wittgenstein dit en ce sens : :« La totalité des pensées vraies est l'image du monde. » (''Tractatus logico-philosophicus'', 3.01) Nos idées vraies sont une peinture fidèle du monde, et, ajoute-t-il « une pensée peut être exprimée dans une proposition en sorte que les éléments du signe propositionnel correspondent aux objets de la pensée. » (3.2) Puisque ces objets de la pensée exprimés par la proposition sont eux-mêmes des images (vraies ou fausses) du monde, il en résulte qu'une proposition peut être ou non adéquate aux réalités que nous percevons. C'est une idée assez vraisemblable, car chacun peut faire l'expérience de cette imagerie mentale ; par exemple, le rêve pourrait venir renforcer cet argument, car dans cet état, nous prenons des images produites par notre esprit pour la réalité. C'est donc bien que nos images mentales ont quelque chose en commun avec la réalité et que nous pouvons les comparer. Bien que nous puissions nous demander ''comment'' des images ressemblant à la réalité sont produites en général dans notre esprit, nous pouvons constater que c'est le cas. Cependant, cet argument ne fait que reculer le problème. En effet, c'est toujours à l'aide de mots que nous exprimons nos images mentales (« ... que les éléments du signe propositionnel correspondent aux objets de la pensée » dit Wittgenstein) ; or, il faut bien que ces mots expriment convenablement ces images, et donc leur soient adéquats, autrement dit, leur ressemblent. On pourrait alors faire remarquer que cette volonté de faire ressembler une proposition (croyance, idée, etc.) avec un fait repose sur une confusion. La proposition n'a en effet pas pour but de peindre un fait, mais d'en décrire la structure en reliant des objets et des propriétés entre eux. Il n'y a dès lors pas à chercher une ressemblance comme ''reflet'', mais une correspondance terme à terme entre une proposition et le fait sur lequel elle porte : Proposition : Un oiseau chante | | | | Fait : « Un oiseau chante » On peut donc proposer cette seconde définition : <div align="center"><div style="margin-top:4px; margin-bottom:4px; padding: 7px; background-color: #FFFF99; border: 3px solid #FFCC00; width:95%;"> <div style="font-size:12pt; font-weight:bold; border-bottom:1px solid #FFCC00;"><div style="text-align: center;">'''Définition 2'''</div></div> <div style="text-align: center;">Une proposition (un jugement, une croyance, une pensée, etc.) est vraie si, ''et seulement si'', sa structure correspond à la structure d'un fait.</div> </div></div> ==== Le problème du jugement ==== Une autre difficulté apparaît quand nous considérons cette fois les éléments contenus dans les propositions vraies ou fausses que nous formulons, en estimant que ces propositions doivent correspondre (ou non) aux choses sur lesquelles elles portent. Admettons qu'une image mentale puisse effectivement être exprimée adéquatement par une proposition (je vois dans ma tête que le chat est sur le tapis), le jugement de relation que nous formulons ne paraît pourtant pas pouvoir être contenue dans celle-ci, car l'image que nous avons à l'esprit n'est que la reproduction du témoignage de nos sens et c'est le jugement que nous portons qui introduit une relation qui ne nous est pas donnée par l'expérience. Prenons pour le montrer plus nettement un exemple un peu plus compliqué. Si une boule de billard vient en frapper une autre et la mettre en mouvement, nous pouvons formuler cette proposition que la première est cause du mouvement de la seconde. Nous avons donc, conformément à notre théorie de la vérité comme adéquation, deux objets en relation, relation que nous exprimons par une proposition qui énonce ce lien, ici un lien de causalité. La question que nous posons est : où se trouve, dans la réalité et dans l'idée que nous en avons, cette relation de causalité ? Nous ne la trouvons pas, car tout ce que nous voyons ce sont deux objets et deux mouvements ''successifs'', mais la causalité elle-même, nous ne la voyons nulle part, si ce n'est dans notre jugement lui-même. Or, s'il en est ainsi, notre jugement, qui énonce la réalité d'une relation (la causalité), porte sur une relation dont nous ne pouvons montrer l'existence. '''Sauf si nous pouvons faire une démonstration d'une réalité qu'on ne voit pas.''' Cette mise en défaut de la théorie de la vérité comme adéquation ne se limite pas à ce cas. Prenons l'exemple des lois scientifiques. Selon une conception très simplifiée de la science, les lois forment des théories décrivant et prédisant des phénomènes. Par conséquent, il nous suffit de vérifier dans l'expérience que la description ou la prédiction d'une théorie est fidèle pour garantir sa vérité. Ce n'est toutefois pas le cas, car une loi scientifique ne dit pas seulement, par exemple, que si ce volume d'eau est chauffé à 100 degré alors se produira un phénomène appelé ébullition ; une loi scientifique dit surtout que toutes les fois que de l'eau est chauffée à cette température, alors elle se met à bouillir. Or, aucune expérience ne nous permet de faire le tour de l'ensemble des cas qui vérifieraient qu'il en va bien ainsi. Par conséquent, une loi scientifique ne peut être considérée comme une simple image fidèle de la réalité sensible : à l'expérience s'ajoute le caractère ''universel'' de la loi, caractère qui n'est pas constatable directement par les sens (nous ne voyons pas tous les cas qui pourraient vérifier la loi). Pourtant, la vérité de la loi réside manifestement dans la validité de cette universalité. ==== Bilan ==== De ces quelques analyses, nous pouvons retenir les deux remarques suivantes : *la conception de la vérité comme adéquation semble être une conception inspirée de la comparaison directe, que nous pratiquons quotidiennement, entre les sens et une certaine image que nous avons à l'esprit, et elle semble en ce sens assez naïve ; elle échoue ainsi à rendre compte de la vérité des jugements que nous formulons par des propositions dans la mesure où ceux-ci se sont pas réductibles aux seuls témoignages des sens ; *la vérité d'une proposition ne peut dépendre de sa seule adéquation aux faits, puisque nous ajoutons par la pensée des relations (ou jugements) que nous ne trouvons pas directement dans l'expérience. === La vérité formelle === Après cette critique de la conception de la vérité comme adéquation, nous pouvons être tenté de trouver dans la manière dont nous formons des jugements le fondement de toute vérité. Cette manière de former des jugements est étudiée par la philosophie depuis l'Antiquité, et c'est ce que nous appelons la ''logique'', dont Aristote est considérée comme l'un des grands initiateurs. Procédant suivant des règles de déduction à partir de postulats et d'axiomes admis, on aboutit à des conclusions valides en vertu de ces seules règles de déduction. Cette vérité est donc indépendante du contenu des propositions, puisqu'elle dépend de son accord avec des lois que nous pouvons considérer comme des lois de notre pensée. Cette sorte de vérité est également dite ''a priori'' car elle ne dépend pas de l'expérience. Considérons l'exemple suivant : #Si la Terre a des ailes, elle vole ; #Or, la Terre a des ailes ; #Donc la Terre vole. Le contenu de la proposition 2 est évidemment faux et la conclusion n'a pas vraiment de sens. Pourtant, le raisonnement est parfaitement correct. Pour le mettre en évidence, remplaçons ces propositions par des lettres, telles que : *p = « La Terre a des ailes » ; *q = « la Terre vole ». Nous obtenons une première esquisse de formalisation : *si p alors q *p *q L'ensemble des règles de déduction, des postulats et des axiomes forment un système hypothético-déductif. Ce dernier point permet d'introduire une distinction : les vérités purement formelle et a priori sont appelées des ''vérités analytiques''. Ces vérités sont nécessaires et ne nous apprennent rien sur le monde. Les vérités tirées de l'expérience sont quant à elle des ''vérités synthétiques'', car nous lions des termes qui supposent pour des êtres dont l'existence est contingente. === La vérité cohérence === La vérité ''d'une croyance'' ou d'une ''opinion'' n'est pas seulement une qualité que nous croyons pouvoir attribuer en nous fondant sur la connaissance de faits, et il arrive en outre bien souvent que nous tenions une proposition pour vraie en dépit de la logique. Autrement dit, la justification de nos croyances peut dépendre uniquement d'un arrière-plan constitué par d'autres croyances : la vérité d'une proposition tient alors du fait qu'elle s'accorde à un ensemble de croyances qui lui préexistent. Ce genre de vérité est souvent appelée ''vérité cohérence''. <div style="font-color:#535068; border:solid 1px #A8A8A8; padding:0.5em 1em 0.5em 0.7em; margin:0.5em 0em;"> {|align=center |[[File:Nuvola apps forward arrow.svg|20px]] |<div style="text-align: center;">''Définition'' : Une croyance est vraie si, et seulement si, elle est une partie d'un système cohérent de croyances.</div> |} </div> === La vérité métaphysique === La vérité que nous appellerons ''métaphysique'' est une vérité d'une sorte encore différente des précédentes, et elle a une longue et riche tradition philosophique. Nous désignerons par cette expression l'idée que la vérité est quelque chose que nous saisissons en soi par l'esprit. Elle tend à identifier la pensée et l'être, l'idée et son objet, la connaissance et l'essence. Nous trouvons ce type de vérités non seulement en métaphysique mais aussi en théologie. Il serait possible de faire une typologie des conceptions d'une saisie d'un en-soi, mais nous nous contenterons ici de deux illustrations, Platon et Bergson. ==== Intuition des réalités vraies ==== Pour Platon, qui, remontant d'une hypothèse à ses conditions, suppose l'existence d'un référant ontologique existant en soi. Dans ce cas, on distingue vérité absolue et vérité relative. ==== Vision immédiate ==== ==== Critiques ==== Ainsi, la vérité métaphysique consiste a déduire d'un ensemble d'hypothèses ou de faits d'expérience, une condition elle-même inconditionnée. Dieu, les Idées, l'âme, le commencement absolu du monde, et même la conscience en tant que fondement de la connaissance dans l'idéalisme, sont des exemples de telles conditions ontologiques. === Théorie pragmatiste === Les théories pragmatistes de la vérité sont elles-mêmes plurielles et complexes. Chez [[Habermas]], par exemple la ''vérité'' se confond avec la notion de ''validité intersubjective''. === Théorie déflationniste === La théorie déflationniste de la vérité consiste à dire qu'il n'y a aucune différence entre dire que p est vrai et dire que p. La vérité, de ce point de vue, n'apporte rien à ce que nous affirmons. En effet, si je dis : le ciel est bleu, cela semble impliquer : c'est le cas que le ciel est bleu. === Histoire du vrai et du faux === ''La première signification de Vrai et de Faux semble avoir son origine dans les récits ; et l’on a dit vrai un récit, quand le fait raconté était réellement arrivé ; faux, quand le fait raconté n’était arrivé nulle part. Plus tard, les philosophes ont employé le mot pour désigner l’accord d’une idée avec son objet ; ainsi, l’on appelle idée vraie celle qui montre une chose comme elle est en elle-même ; fausse, celle qui montre une chose autrement qu’elle n’est en réalité. Les idées ne sont pas autre chose en effet que des récits ou des histoires de la nature dans l’esprit. Et de là on en est venu à désigner de la même façon, par métaphore, des choses inertes ; ainsi, quand nous disons de l’or vrai ou de l’or faux, comme si l’or qui nous est présenté racontait quelque chose sur lui-même, ce qui est ou n’est pas en lui.'' Baruch Spinoza, ''Pensées métaphysiques'' (1663), 1er partie, chap. VI, Gallimard, « La Pléiade », trad. R. Caillois. == Vérité et connaissance == Venons-en maintenant à la question de savoir quelle est la place de la vérité par rapport à la connaissance. Nous avons fait jusqu'ici comme si la vérité pouvait être trouvée dans des propositions isolées portant sur des faits eux-mêmes isolés (''atomisme''), mais l'idée de la vérité cohérence nous a montré qu'un tel isolement n'existe peut-être pas, ou du moins ne représente qu'un cas particulier douteux de vérité se présentant sous forme de vérité particulière. Nous voyons ainsi que les systèmes philosophiques et les théories scientifiques sont constitués d'un ensemble organisé de propositions tenues pour vraies qui ne sont pas indépendantes les unes des autres. Ces systèmes, comme ces théories, ont l'ambition de nous donner une connaissance aussi exacte que possible des objets étudiées, voire de la réalité dans son ensemble. Cela pose non seulement la question de savoir comment il faut comprendre la notion de vérité dans de tels ensembles, autrement dit la question des relations entre vérité et connaissance ; mais aussi celle de la vérité en philosophie, car, s'il peut paraître évident qu'un philosophe cherche la vérité, les sciences semblent bien les disciplines les mieux placées pour nous fournir ''toutes'' les vérités possibles, en sorte qu'il n'y aurait pas, à côté de cela, de vérités philosophiques. === Vérité, sciences et certitude === Revenons sur la brève évocation que nous avons faite de la science dans notre critique de la vérité comme adéquation. Nous avons soutenu que les lois scientifiques ne pouvaient être de simples représentations dont la vérité se manifesterait par une comparaison directe avec la réalité sensible. Nous allons développer et préciser ce point en exposant les réflexions du chimiste et philosophe [[w:Pierre Duhem|Pierre Duhem]] (1861 - 1916) au sujet de l'expérience en physique dans ''La Théorie physique, son objet, sa structure''. Ces réflexions nous permettront de nous faire une idée moins abstraite de la vérité, de l'inscrire dans un processus de recherche (et donc dans une temporalité) et nous verrons que nous pourrons à partir de là esquisser une analyse des rapports entre vérité et certitude. Au chapitre IV de la seconde partie de la ''Théorie physique'', Duhem soutient que le résultat de l'activité d'un physicien expérimentateur n'est pas le constat de certains phénomènes, mais un énoncé d'un jugement reliant des notions qui ne correspondent à des observations que par l'intermédiaire d'une théorie. ... Au terme de l'examen de ces réflexions de Duhem, nous nous trouvons en présence de deux manières d'établir la vérité ; l'une est grossière et immédiate, l'autre est détaillée et demande un long processus de traduction pour parvenir à des énoncés scientifiques. Duhem tire de cette distinction une conséquence étonnante, en ce qu'elle va à l'encontre d'un préjugé au sujet des vérités scientifiques : celles-ci seraient dotées du plus haut degré de certitude que l'homme puisse atteindre. Duhem montre précisément en quoi consiste la fausseté de ce préjugé. La certitude immédiate des sens est solide et laisse peu de place au doute, hormis les cas pathologiques ; les vérités scientifiques sont au contraire le résultat de processus complexes et difficiles d'interprétations des phénomènes et de corrections des observations. On comprend que l'erreur puisse plus facilement se glisser dans ces processus que dans l'observation immédiate que chacun peut faire dans la vie ordinaire. La certitude des vérités scientifiques est donc moins assurée que la vérité de l'intuition directe des faits. === Vérité et philosophie === Que reste-t-il à la philosophie en matière de connaissance, dès lors que les sciences ont repris et reprennent à leur compte ce qui a été, à des époques différentes, l'objet de l'enquête philosophique ? Il est par exemple bien évident que le philosophe ne peut plus faire de physique, comme c'était le cas des Présocratiques. Une discipline à la fois ancienne et récente comme la logique est devenue très spécialisée, sous l'impulsion d'ailleurs de philosophes de la fin du XIXe et du XXe siècle. La philosophie, semble-t-il, est comme le précurseur de toutes les sciences particulières, et ouvre la voie à de nouveaux domaines de connaissance, qui, une fois bien établis, deviennent des disciplines scientifiques qui ne relèvent plus fondamentalement de la philosophie. On pourrait alors dire que, tant qu'un domaine de connaissances relève de la philosophie, il ne s'agit pas encore de connaissances bien assurées. Ainsi, si certaines parties de la philosophie (physique, psychologie, logique) sont devenues des sciences, d'autres sont loin d'avoir acquis ce statut, ou sont même soupçonnées de n'être finalement que des illusions de connaissances, comme dans le cas de la métaphysique. Dans ce cas, il est difficile de considérer la philosophie comme un genre de connaissance telles que les sciences : elle ne possède pas de vérités à elle, mais, par un travail de clarification de nos pensées et de nos méthodes, elle est une aide indispensable au commencement de toute science, voire elle aide à élucider certaines notions scientifiques embrouillées. Nous proposons d'examiner et de discuter ici ces deux idées que nous venons de formuler : # La philosophie n'est pas une science ; # Elle n'est pas une recherche de vérité philosophique, mais une ''activité'' de clarification de la pensée et de la connaissance. ==== La philosophie n'est pas une science ==== L'idée que la philosophie n'est pas une science est sans doute assez répandue de nos jours. Il y a plusieurs raisons à cela. En premier lieu, le développement des sciences à l'époque moderne a conduit à retirer à la philosophie sa prétention à être la reine des sciences, prétention incarnée tout particulièrement par la métaphysique (appelée également ''philosophie première''). La métaphysique est en effet une discipline qui étudie les principes les plus généraux de la réalité (ou de l'être) et elle se situerait pour cette raison au-dessus de toutes les formes particulières de connaissance. Or, face aux sciences (nous verrons pourquoi un peu plus bas), une telle discipline peut apparaître ne formuler aucune vérité vérifiable (par exemple, sur Dieu, sur l'âme) ou aucune vérité qui ne serait pas mieux formulée dans le cadre de telle ou telle science (sur l'espace, le temps, la causalité) ; c'est pourquoi, la métaphysique est apparue vide de tout contenu. Une autre raison est que la philosophie a conservé pour nous la dimension pratique qu'elle possède depuis ses origines, et, qu'à défaut d'être considérée comme une science, elle reste une discipline censée offrir des réponses aux questions morales et, plus généralement, aux problèmes que nous pose notre existence et à laquelle la philosophie serait chargé de donner du sens. Or, ces questions sont rarement considérées comme des questions scientifiques car elles portent sur des valeurs (comme le bien) et des comportements humains qu'il est difficile de quantifier, de théoriser et de prédire. C'est d'ailleurs aussi pourquoi ces questions ont parfois une tonalité polémique à l'égard des sciences, car ces dernières réduiraient indûment l'être humain à un objet d'étude parmi d'autres. Ainsi réduite à des questions d'ordre pratique, la philosophie ne pourrait donc plus prétendre au statut de science. Une telle idée de la philosophie dans ses rapports à la science (idée qui recouvre bien entendu une très large variété de points de vue) était étrangère aux premiers philosophes qui s'occupaient de cosmologie en philosophes (on les désigne d'ailleurs en tant que ''philosophes de la nature''), mais aussi aux philosophes hellénistiques (stoïciens, épicuriens), qui, malgré leurs préoccupations morales, considéraient la physique comme une partie essentielle de la philosophie. Mais, par dessus tout, c'est la conception même de la science qui était bien différente de la nôtre, et cette différence va nous permettre de comprendre comment la connaissance et la vérité étaient conçues par eux. Prenons l'exemple de Platon et de sa théorie de la connaissance. Pour Platon, la science véritable est un contact de la partie intellectuelle de l'âme avec des réalités fondamentales sous-jacentes au monde qui nous est donné par les sens. De ce fait, connaître, c'est être affecté par ces réalités, et celui qui sait, le savant, ou philosophe, possède la vérité dans l'exacte mesure où il a une vision des réalités véritables. Nous avons donc là une conception métaphysique de la vérité, bien que le terme « métaphysique » soit ici anachronique : il faut, pour atteindre la vérité, remonter des impressions sensibles à des entités absolues qui en sont les causes. Dans cette conception, la science est un ''état'' de l'âme de celui qui connait : il est parvenu, par un processus dialectique, à la contemplation de ces réalités, que l'on désignera du terme de ''Formes''. Cet état est celui de la sagesse, et celui qui connaît ainsi est un sage ou un savant (''sophos'' admettant les deux traductions). Tous les philosophes antiques, même s'ils ne partagent pas la théorie platonicienne de la connaissance, conçoivent la science comme un état. Les sciences modernes se présentent de manière bien différente, par exemple comme des ensembles organisés de propositions. L'état du sujet connaissant n'est pas primordial, ou relève de la psychologie. Il est même indifférent de savoir si le scientifique est un sage contemplant des Formes : la vérité des hypothèses ne dépend pas de la relation de son âme à une réalité absolue, mais, par exemple, de procédures de vérifications qui requiert une activité interindividuelle complexe. Cette transformation de la notion de science, qui a lieu à partir du 16e siècle, conduit naturellement à contester au philosophe son statut platonicien de maître de vérité. La raison en est très simple. Si l'on considère que la vérité de nos connaissances sur le monde ne peut être établie que par une validation empirique, les propositions métaphysiques ne sont tout au plus que des illusions sur nos capacités de connaître, et elles sont en tout cas dépourvues de sens parce qu'elles ne portent sur rien de vrai ni de faux. Il est important de saisir toute l'importance de cette dernière remarque pour la philosophie. Ce sera l'objet de la section suivante. ==== La philosophie n'a pas de vérités qui lui soient propres ==== Si en effet toute vérité repose en dernier ressort sur les données de nos sens, il n'est pas possible de constituer un ensemble de connaissances hors de cette limite. La métaphysique est donc obsolète, et la philosophie est purement et simplement remplacée par les sciences. Faut-il alors déclarer la fin de la philosophie ? Mais le rejet de la métaphysique n'a pas entrainé avec elle le rejet de la philosophie toute entière. Plusieurs conceptions de la philosophie demeurent en effet possibles. Tout d'abord, la philosophie peut avoir pour tâche de délimiter le domaine légitime de nos connaissances. Elle est alors une théorie critique de la connaissance qui s'occupe de montrer de quelle manière les propositions que nous formulons sont ou non légitimes. Dès lors, elle peut être une activité réflexive sur des connaissances déjà constituées, ou qui se prétendent telles, et, en clarifiant les conditions d'utilisation et de validation de ses connaissances, elle en évalue la légitimité. == La vérité comme norme morale == Les sections précédentes ont tracé, dans leurs grandes lignes, plusieurs conceptions de la notion de vérité. Bien que ces exposés soient abstraits et aient surtout rapport à la connaissance, leurs liens à la pratique et à la vie quotidienne sont demeurés évidents tout du long, puisque, par exemple, nos propositions les plus triviales peuvent être des illustrations de la problématique de la vérité comme correspondance et la manière dont nous en venons à tenir une croyance pour vraie peut illustrer la vérité comme vérité cohérence. Mais nous en sommes restés à une approche purement intellectuelle, et nous n'avons pas encore considéré ce qu'il en est de notre rapport à la vérité à la lumière de nos sentiments et de nos valeurs morales. Dans cette section, nous aborderons la question des rapports de la vérité et de la morale de deux points de vue. D'une part, nous nous demanderons si, et dans quelle mesure, les jugements moraux (par exemple : « Voler est mal ») sont susceptibles d'être vrais ou faux. Pour répondre à cette question, il nous faudra principalement nous demander si, dans le cas où une telle chose existe, la vérité des jugements moraux est d'une nature particulière. D'autre part, nous allons nous préoccuper de ces rapports moraux à la vérité que l'on désigne par des noms de vertus ou de vices : la véracité et la sincérité, le mensonge, la confiance, la tromperie, etc., c'est-à-dire que nous allons passer de l'idée de vérité comme norme de connaissance, à l'idée de vérité comme norme morale, et que nous allons nous demander si la vérité peut avoir (et si oui, dans quelles conditions) force d'obligation morale. === Vérité et jugement moral === De quelle vérité sont susceptibles les jugements moraux comme « voler est mal », « l'altruisme est une vertu » ? Si nous pensons que de tels jugements peuvent être vrais ou faux, alors nous devons les tenir pour des propositions comparables à celles que nous avons examinées plus haut. Cela nous donne un point de départ, car, pour répondre à cette question, il nous suffit de nous demander si ce sont des propositions portant sur des réalités du monde extérieur (comme celles des sciences de la nature) ou des propositions vraies en vertu de leurs composants (comme celles de la logique et des mathématiques). Or, à l'évidence, les propositions morales ne sont ni des vérités logiques ou mathématiques, ni des vérités de faits. Certes, nous pouvons raisonner ''à partir'' de jugements moraux, en déduisant par exemple que de telle vérité morale générale (par exemple « voler est mal ») appliquée à tel acte, il s'en suit que l'acte en question est bon ou mauvais. Mais la proposition morale dont nous partons n'est pas une proposition vraie en vertu de ses composants : en effet, de la notion de vol, nous ne pouvons déduire la notion de mal. Cela se voit d'ailleurs bien dans le fait que les propositions morales sont rarement tenues pour vraies en toutes circonstances : dans certains cas, nous pouvons admettre que le vol est, par exemple, une nécessité. Or, les propositions vraies en vertu de leurs composants sont ''toujours'' vraies ; par conséquent, les propositions morales ne sont pas de ce genre. Les jugements moraux ne sont pas non plus des jugements portant sur des faits. Nous voyons bien qu'il y a un ensemble d'actions que nous pouvons qualifier de généreux, d'altruistes, etc. ; mais la qualité attribuée (la générosité, l'altruisme, etc.) n'est pas un fait extérieur observable. Il ne peut donc y avoir adéquation ou correspondance entre un jugement moral et une réalité empirique. Nous pouvons alors dire que les propositions morales, si elles sont vraies, ne sont vraies ni par un raisonnement purement formel, ni par une éventuelle possibilité de les vérifier empiriquement. Ce résultat est embarrassant, car nous ne semblons pas posséder de conception de la vérité telle que nous puissions dire qu'une proposition morale est vraie, et, dès lors, la morale apparaît impossible à fonder ; mais, puisqu'elle ne renvoie à aucun fait, tout en portant sur certaines sortes de réalités physiques (les actions humaines), la morale ne serait pas non plus réfutable, puisqu'il n'y a rien dans le monde qui puisse contredire un jugement moral. Cependant, nous n'avons pour le moment examiné les jugements moraux qu'à la lumière de ce qu'est une proposition. Lorsque nous nous sommes efforcés de comprendre la nature de la vérité, nous avons en revanche montré qu'il existe différentes conceptions de celle-ci, et il se peut que l'une de ces conceptions nous éclaire sur les rapports de la morale à la vérité. Voyons donc à présent à quel genre de vérité la vérité morale pourrait appartenir. == Sujets de dissertation == Nous avons réunis dans cette section quelques sujets de dissertations, et nous les avons regroupés par thèmes (les limites entre ces thèmes ne sont bien sûr pas imperméables). Nous n'allons pas traiter ces questions une par une, mais, pour chaque thème, nous proposerons quelques réflexions qui pourront peut-être vous servir de point de départ et que vous pourrez compléter à l'aide de l'article lui-même, les extraits que nous donnons ci-dessous et la bibliographie. Ces questions permettront en outre de traiter dans les grandes lignes les points que nous n'avons pas abordés, bien que ce ne soit pas sous la forme de réflexions développées, mais d'esquisses de problématiques. === Définition, nature de la vérité, vérité et histoire === * La vérité * Qu'est-ce que la vérité ? * Toute vérité est-elle particulière ? * Y a-t-il une vérité des apparences ? * La vérité est-elle soumise au temps ? * La vérité a-t-elle une histoire ? ** On peut commencer par distinguer au moins deux sens dans cette question. La vérité a une histoire au sens où elle est elle-même sujette à des changements, comme l'individu qui a une vie ; mais la vérité peut avoir une histoire au sens où sa découverte n'est pas immédiate : elle fait l'objet de recherches qui permettent de se rapprocher d'elle peu-à-peu. Le premier sens apparaît d'emblée contradictoire, car changer, pour une vérité, c'est devenir faux. Donc, la vérité ne semble pas avoir d'histoire en ce sens. Le second sens apparaît quant à lui trivial au premier abord. Il est évident que nous ne découvrons que peu de vérités du premier coup ; les sciences en sont un exemple de premier ordre. Pourtant, si histoire de la vérité il y a en ce sens, n'est-ce pas plutôt une histoire de nos erreurs ? En effet, s'il y a réellement un progrès dans nos connaissances, ce progrès s'accompagne très souvent de la réfutation des vérités qui étaient admises et qui ne sont donc plus des vérités. Aussi, l'histoire de la vérité serait-elle en réalité l'histoire des vérités réfutées. On voit que le sujet est difficile à problématiser, car les deux sens possibles ne semblent pas permettre d'attribuer une histoire à la vérité en elle-même. On peut alors tenter l'approche suivante : distinguer la notion de vérité de la conception que nous en avons ; si la notion elle-même ne paraît pouvoir être historique sans contradiction, notre conception de la vérité a à l'évidence une histoire. === Critères/conditions de la vérité === * Existe-t-il des critères du vrai ? * La vérité dépend-elle de nous ? ** Pour bien traiter ce sujet, il faut avoir à l'esprit que le verbe ''dépendre'' doit faire l'objet d'une analyse tout autant que les mots ''vérité'' et ''nous''. Sans cela, le travail de réflexion sera confus. En effet, ''dépendre'' a plusieurs sens : si l'on ne retient que l'idée que la vérité est ce que nous décidons, on rate complètement l'intérêt philosophique de la question, car il serait assez trivial de se contenter d'un relativisme qui ferait dépendre la vérité de notre subjectivité par exemple. En revanche, la vérité peut dépendre de nous au sens où la vérité n'est pas dans les choses mais dans notre esprit (voyez ce que nous avons dit à propos d'Aristote, entre autres), et de là se pose de manière bien plus pertinente la question de savoir si cette relation à l'esprit dépend de notre subjectivité (disons par exemple de nos sentiments, de nos opinions, etc.) ou de notre intellect et de sa capacité à juger des choses telles qu'elles sont. On pourra alors se demander si la vérité est une réalité psychologique ou une norme pour notre esprit, et voir dans chaque cas en quoi elle dépend de nous. * « Je ne crois que ce que je vois. » Est-ce la une bonne méthode pour découvrir la vérité ? ** ex.: La victime d'un adultère ne le voit pas, pourtant, la réalité attestée par les coupables prouve cette nouvelle vérité: elle est cocue. * Toute vérité peut-elle se passer de preuve ? * La vérité est-elle discutable ? ** Tant qu'une 'vérité' est en réalité une proposition, elle est discutable. * Y a-t-il des vérités définitives/indiscutables ? * N'y a-t-il de vérité que dans la science ? * Ne faut-il tenir pour vrai que ce qui peut-être démontré ? * Les vérités mathématiques constituent elles le modèle de toute vérité ? * L'unanimité est-elle un critère de la vérité ? ** Si on réuni une majorité d'ignorants qui sont unanimes dans l'erreur obtient-on la vérité? * Une pensée cohérente est-elle nécessairement vraie ? ** Si une pensée composée de 5 informations peut être cohérente, on peut aboutir à une toute autre conclusion (ou pensée) si on y ajoute une nouvelle information. La terre est plate, c'était cohérent à l'époque mais faux selon la réalité. Depuis, on a démontré et prouvé qu'elle est ronde; c'est aussi cohérent mais cela repose sur des réalités et non de simples pensées. Plus les composantes de la pensée sont des faits incontestables et si tous les faits sont réunis, alors on obtient ou l'on s'approche de la vérité. === Recherche de la vérité, valeur, norme === * Pourquoi l'homme cherche-t-il la vérité ? * Peut on ne pas désirer la vérité ? * Peut-on dire : la vérité ça m'est égal ? * Peut-on ne pas vouloir rechercher la vérité ? * Douter, est-ce renoncer à la vérité ? Dans les questions qui touchent à la valeur de la vérité (vérité comme norme), il faut prendre soin de distinguer (même si c'est pour discuter cette distinction) la valeur de la vérité comme norme morale (par exemple, on veut la vérité, car on ne veut pas être trompé, car il ne faut pas mentir, etc.) de la valeur de la vérité dans le domaine de la connaissance. De plus, on peut décrire des motivations très différentes (psychologiques, morales, intellectuelles) pour répondre à la question de savoir pourquoi nous cherchons la vérité. Il est également important de distinguer l'attitude de l'homme par rapport à la vérité (désir, volonté, etc., sont du domaine psychologique et morale) de la vérité comme notion. Dans les questions ci-dessus, c'est le premier point qui est mis en avant, ce qui ne veut pas dire que l'on ne doit pas examiner la notion de vérité, mais que les différentes idées que l'on peut se faire de la vérité doivent être considérées à la lumières de notre attitude à son égard. La première distinction permet de voir qu'il y a de nombreux problèmes dans l'affirmation que l'on ne désire pas la vérité, que la vérité nous est égale : si l'on ne veut pas chercher la vérité, est-ce à dire que nous préférons le mensonge (domaine morale), l'erreur (domaine de la connaissance), l'illusion (conception de la réalité) ? Il faut pouvoir répondre à ces différents points pour parvenir à justifier que la vérité nous indiffère, et on voit, en posant ces questions, que ce n'est pas si facile. Si la question porte sur une question de possibilité (Peut-on ne pas vouloir rechercher la vérité ?), on pourra utilement s'interroger sur le caractère intentionnel d'un rejet de la vérité et sur son authenticité : le menteur compulsif, le mythomane, par exemple, sont des cas pathologiques qui montrent que l'on peut rejeter la vérité, mais qu'il ne s'agit pas d'une volonté. Mais même le menteur ne renonce pas à la vérité, car, pour mentir, il faut admettre qu'il y a de la vérité, et, bien plus, il faut la chercher dans la mesure où cette recherche permet le mensonge. L'artiste serait-il un exemple de volonté, de désir véritable de préférer l'apparence à la vérité, comme le soutient Nietzsche ? On peut penser au contraire, et cela en suivant Nietzsche, que l'art est en réalité un moyen de révéler une vérité plus fondamentale, une vérité métaphysique à propos de notre existence. Même si cette conception est fausse, on voit que le désir de vérité est difficile à éliminer. On pourrait se demander si l'homme n'est pas condamné à vouloir la vérité. Mais pourquoi ? Pourquoi est-il si difficile d'éliminer l'idée de vérité comme norme de nos jugements et de nos pensées et même de nos actions ? Si nous montrons que c'est une tâche impossible, nous montrons du même coup qu'il est impossible de renoncer à la vérité, et que l'indifférence à son égard est illusoire ou inauthentique. Prenons le cas du doute qui, dans sa forme généralisée, peut apparaître comme un renoncement à la vérité, comme une forme d'indifférence. Lorsque nous doutons, nous sentons que la vérité nous échappe. Si nous restons dans cet état de doute, nous ne renonçons pas à la vérité, puisque cet état n'a de sens que par rapport à la vérité. Mais surtout, lorsque nous doutons, nous cherchons une issue à nos doutes. Nous pouvons en proposer une explication anthropologique : le doute est, dans l'action, synonyme d'hésitation ; l'hésitation produit la paralysie qui nous conduit finalement à l'échec. L'échec diminue notre pouvoir et est une source de déplaisir. Dans la recherche de moyens de survie, le doute est également synonyme de blessures et de mort. La connaissance de la réalité est au contraire une bonne condition de survie. La recherche de la vérité pourrait être alors à l'origine un instinct qui s'est par la suite intellectualisé et qui a ainsi contribué à former de manière essentielle notre humanité. Nous obtenons ainsi une explication à la fois simple et, par bien des aspects, triviale, de notre désir de vérité : le plaisir et la douleur que nous cause la réalité nous conduisent à préférer des représentations correctes de ce qui est. Dans l'action et dans la nécessité de survivre, la sanction du réel est impitoyable. === Diversité des opinions, relativisme === * La diversité des opinions rend elle vaine la recherche de la vérité? * Peut-on dire à chacun sa vérité ? * De quelle vérité l'opinion est-elle capable ? Dans ce genre de questions, il faut vraiment faire attention à éviter ces facilités que l'on rencontre aujourd'hui un peu partout, et qui se résument toutes à peu près ainsi : la vérité est une question de point de vue, il n'y a pas de vérité absolue. Ce sont des facilités, car elles n'ont pas un fondement théorique particulièrement élaboré, ce qui permet de les réfuter facilement : si la vérité est une question de point de vue, la proposition « la vérité est une question de point de vue » est une question de vue, et il donc parfaitement raisonnable de ne pas la tenir pour vraie. En outre, il est très difficile de soutenir un tel point de vue lorsqu'on le confronte à certaines réalités : par exemple, la vérité de « 2 + 2 = 4 » dépend-elle de nos opinions ? Chacun peut-il avoir son opinion sur, par exemple, la dimension de la Terre ou la composition moléculaire de l'eau ? La conséquence ultime du « à chacun sa vérité » est que la réalité dépend du point de vue de chacun. Il est sans doute préférable de chercher à déterminer les domaines dans lesquels il y a effectivement, et de manière inévitable, une diversité d'opinions, et les domaines où cette diversité est surtout le résultat de l'ignorance. Dans une telle approche, on peut par exemple estimer que la recherche de la vérité en politique est vaine, parce que l'objectif en politique est de trouver la meilleure manière de faire coexister des individus qui ont des opinons différentes, et non de leur dire ce qu'ils doivent penser ; et, en même temps, on peut estimer que la diversité des opinions dans les sciences est inhérente à notre ignorance naturelle et à la nécessité de formuler des hypothèses pour y remédier, ce qui rend justement la diversité des opinions indispensable. Cette distinction (évidemment sommaire) de deux domaines (politique et sciences) devrait ainsi vous convaincre de la nécessité de ne pas faire des réponses ''en gros'', des réponses générales, qui n'ont plus guère d'intérêt dès qu'on les applique à des problèmes ou des situations particulières. Voyons cela plus précisément en proposant une esquisse de réponse à la troisième question de notre liste (''De quelle vérité l'opinion est-elle capable ?''). Si nous partons de l'idée que chacun possède sa vérité, quelle conception de la vérité peut nous faire comprendre, d'une part, que chacun puisse en effet avoir sa vérité, et, d'autre part, que toutes les opinions des hommes peuvent prétendre à la qualité de vérité ? À l'évidence aucune, car chacun, justement, a sa vérité, et donc aussi sa conception de la vérité qu'il ne partage pas avec ses semblables. Le problème devient déjà plus intéressent si nous distinguons des domaines, comme nous l'avons fait ci-dessus. Dans le domaine politique, il serait possible de comprendre la vérité, pour chacun, comme l'opinion qu'il se fait de la vie la meilleure en société dans la mesure où celle-ci est compatible avec une vie commune ; chacun à ainsi une part à une conception générale de la société, disons, par exemple, la conception démocratique. Par rapport aux sciences et à la connaissance, l'opinion peut être caractérisée de manières très diverses qui reflètent sa diversité et l'impression de « à chacun sa vérité » que nous pouvons en retirer : si c'est un jugement qui ne repose sur aucun fait ni aucune théorie, si elle est contredite par des faits, alors cette opinion est fausse (et si nous tenons que toute opinion est fausse, alors nous pouvons aussi estimer que la diversité des opinions vient de l'erreur, du fait qu'elle n'est pas capable de vérité) ; en revanche, l'opinion peut être une hypothèse et donc une proposition dont la vérité n'est pas encore assurée mais que l'on va pouvoir vérifier (dans ce cas, l'opinion tend vers la vérité, elle est capable de vérité dans cette mesure - la diversité des opinions tient alors au fait que la vérité n'a pas encore été établie); l'opinion peut être aussi un jugement vrai, mais dont on ne sait pas pourquoi il est vrai : pensez aux connaissances scientifiques dont vous disposez parce que vous les avez apprises, entendues ou lues, mais dont vous ne connaissez pas la justification théorique. Dans ce cas, l'opinion est une vérité non justifiée, c'est un savoir que vous possédez, mais sans en avoir la certitude (dans ce cas, l'opinion est pleinement capable de vérité, et la diversité des opinions tient au fait que l'absence de certitude et de justification permet que des erreurs ou des déformations s'y introduisent). Le résultat de ces quelques réflexions, est qu'il est possible de distinguer plusieurs manières pour l'opinion de se rapporter à la vérité, et ces manières vont du faux à la vérité elle-même, en passant par l'incertain et l'opinion commune à propos d'une conception comme le meilleur régime politique. Ce résultat montre aussi que l'on ne peut pas dire dans tous les cas et pour les mêmes raisons que chacun peut posséder sa vérité (dans certains cas, il s'agit d'ignorance, de préjugés, dans d'autres, d'opinions mal assurées, d'hypothèses, etc.). Enfin, ce résultat montre aussi que la diversité des opinions est loin de rendre vaine la recherche de la vérité. === Vérité, morale, politique === * La vérité est elle libératrice ? * La vérité est-elle tyrannique ? * Y a-t-il des vérités préjudiciables ? * La tolérance exclut-elle toute référence à une vérité ? == Doxographie et textes == Nous avons jusqu'ici proposé une analyse de la notion de vérité et des problématiques qui lui sont liées. Nous allons à présent exposer quelques théories sur la vérité soutenue par les philosophes. Si nous n'abordons ces théories que maintenant, c'est parce qu'il fallait d'abord comprendre les problèmes, avant de voir comment ils ont été traités. De cette manière, on assimilera mieux la pensée de ces philosophes, au lieu de l'apprendre par cœur et de la réciter dans une dissertation. === Aristote === « Ce n'est pas parce que nous pensons d'une manière vraie que tu es blanc, que tu es blanc, mais c'est parce que tu es blanc, qu'en disant que tu l'es, nous disons la vérité. » ''Métaphysique'', Livre Gamma, 4, 1006a 10-12, trad. Tricot, Vrin '''Commentaire :''' la vérité de nos pensées repose sur une réalité qui nous est extérieure, qui ne dépend pas de nous et qui précède ce que nous pensons. Nous n'inventons pas la réalité que nous pensons : l'esprit ne créé pas un objet en sorte que cet objet lui corresponde ; au contraire, l'objet existe en dehors de la pensée vraie, et donc avant elle. Mais cela ne veut pas dire pour Aristote que nous trouvons la vérité dans les choses, bien que la vérité soit l'un des sens de l'être (c'est-à-dire qu'elle est une sorte de la réalité) : : « Qu’il nous suffise d’avoir remarqué que la convenance ou la disconvenance du sujet et de l’attribut existe dans la pensée et non dans les choses, et que l’être en question [celui de la vérité] n’a pas d’existence propre [...] » ''Métaphysique'', Livre E, 4, 1027b La vérité existe dans la pensée, et elle a une réalité différente de la réalité des choses mais qui en dérive (car notre pensée est une réalité vraie dans la mesure où elle dit ce qui est), aussi est-elle une affection ou une modification de la pensée et elle n'existe pas par elle-même. La vérité au sens de correspondance a été définie par Aristote dans ''De l'Interprétation'', œuvre où il analyse la formation des propositions logiques, c'est-à-dire les parties du discours susceptibles d'être vraies ou fausses. Une proposition est vraie quand on dit que ce qui est est ou que ce qui n'est pas n'est pas ; elle est fausse quand on dit que ce qui est n'est pas ou que ce qui n'est pas est. Cette vérité est appelée aussi la ''vérité correspondance''. Ce type de vérité concerne la recherche scientifique. Cette conception est fortement réaliste, car nous disons par exemple que le chat est sur le tapis est vrai '''parce qu'il est''' sur le tapis, et non l'inverse. Le problème est alors de savoir ce qu'il faut entendre par correspondance. Une proposition vraie est-elle vraie parce qu'elle ressemble à ce qu'elle signifie ? Non, car une proposition est faite de mots qui ne ressemblent pas à des faits. C'est donc que le sens de la proposition exprimerait quelque chose de la réalité ; mais le problème de cette théorie est de savoir comment cela est possible. Malgré sa théorie du syllogisme, il ne semble pas qu'Aristote soit parvenu à distinguer les deux premiers sens de la vérité. On trouve en revanche cette distinction dans la logique stoïcienne, exposée par Sextus Empiricus dans ses ''Esquisses Pyrrhonnienne''. L'analyse stoicienne de l'implication permet en effet de valider des propositions telles que ''si la terre a des ailes, elle vole'' ; les deux parties de l'implication sont matériellement fausses, et pourtant le raisonnement est valide. === Thomas d'Aquin === « Le vrai est à la fois dans l'intellect et dans les choses. Toutefois, le vrai qui est dans les choses est substantiellement identique à l'être ; et le vrai qui est dans l'intellect est identique à l'être, mais comme une représentation l'est à ce qu'elle représente [...]. » ''Somme théologique'', I, q. 16, a. 3 '''Remarque :''' On voit que, au contraire d'Aristote, cette conception de la vérité assimile la vérité à l'être (ou à la réalité), la vérité dans l'esprit étant dérivée, en tant que représentation, de la vérité dans la réalité, tout en étant cependant identique à l'être. On peut objecter à cette conception qu'elle est contradictoire et distingue deux vérités : car la vérité dans l'esprit est la vérité de la représentation, donc d'une relation entre ce que nous pensons et la réalité de ce que nous pensons, alors que la vérité dans les choses est simplement identique à la réalité. Pourtant, le vrai dans l'intellect, assimilé à une représentation de l'être, est en même temps identique à l'être. Il y a donc là une hésitation entre la séparation et l'identification de la pensée et de l'être. Cette conception qui identifie vérité et réalité était répandue au Moyen Âge ; elle ne l'est plus guère de nos jours. === Hobbes === « Le vrai et le faux sont des attributs du langage, non des choses. Et là où il n'y a pas de langage, il n'y a ni vérité ni fausseté. » ''Léviathan'', chap. 4, trad. G. Mairet, Folio Essais, p. 102. === Pascal === « La vérité doit toujours avoir l'avantage, quoique nouvellement découverte, puisqu'elle est toujours plus ancienne que toutes les opinions qu'on en a eues, et que ce serait ignorer sa nature que de s'imaginer qu'elle ait commencé d'être au temps qu'elle a commencé d'être connue. » ''Sur le traité du vide'' === Spinoza === « On appelle idée vraie, celle qui montre une chose comme elle est en elle-même ; fausse, celle qui montre une chose autrement qu'elle n'est en réalité. » ''Pensées métaphysiques'', I, 6, trad. Appuhn, GF, 1964, p. 352 "et l'on dit vrai un récit quand le fait était réellement arrivé; faux quand le fait raconté n'était arrivé nulle part" === Hume === « Le vrai et le faux consistent en un accord ou un désaccord, soit avec les relations réelles entre les idées, soit avec l'existence et le fait réel. » ''Traité de la nature humaine'' === Hegel === « Il semble que l'on fait consister proprement la possession de la philosophie dans le manque de connaissances et d'études, et que celles-ci finissent quand la philosophie commence. On tient souvent la philosophie pour un savoir formel et vide de contenu. Cependant, on ne se rend pas assez compte que ce qui est Vérité selon le contenu, dans quelque connaissance ou science que ce soit, peut seulement mériter le nom de Vérité si la philosophie l'a engendré ; que les autres sciences cherchent autant qu'elles veulent par la ratiocination à faire des progrès en se passant de la philosophie il ne peut y avoir en elles sans cette philosophie ni vie, ni esprit, ni vérité. » ''Phénoménologie de l'esprit'', « Introduction », ed. Aubier-Montaigne, p.58. === Nietzsche === '''La vérité comme croyance première de la science''' ''De quelle manière, nous aussi, nous sommes encore pieux.'' — On dit, à bon droit, que, dans le domaine de la science, les convictions n'ont pas droit de cité : ce n'est que lorsqu'elles se décident à s'abaisser à la modestie d'une hypothèse, d'un point de vue expérimental provisoire, d'un artifice de régulation, que l'on peut leur accorder l'entrée et même une certaine valeur dans le domaine de la connaissance, — à une condition encore, c'est qu'on les mette sous la surveillance de la police, de la police de la méfiance bien entendue. — Mais cela n'équivaut-il pas à dire : ce n'est que lorsque la conviction cesse d'être une conviction que l'on peut lui concéder l'entrée dans la science? La discipline de l'esprit scientifique ne commencerait-elle pas alors seulement que l'on ne se permet plus de convictions?... Il en est probablement ainsi. Or, il s'agit encore de savoir si, pour que cette discipline puisse commencer, une conviction n'est pas indispensable, une conviction si impérieuse et si absolue qu'elle force toutes les autres convictions à se sacrifier pour elle. On voit que la science, elle aussi, repose sur une foi, et qu'il ne saurait exister de science « inconditionnée ». La question de savoir si la vérité est nécessaire doit, non seulement avoir reçu d'avance une réponse affirmative, mais l'affirmation doit en être faite de façon à ce que le principe, la foi, la conviction y soient exprimés, « rien n'est plus nécessaire que la vérité, et, par rapport à elle, tout le reste n'a qu'une valeur de deuxième ordre. » [[Philosophie/Nietzsche|Nietzsche]], ''[[Le Gai Savoir]]'', §344. == Bibliographie == === Textes classiques === * PLATON, ''Théétète'', 189a-192c * PLATON, ''La République'', livre VI et VII * PLATON, ''Ménon * ARISTOTE, ''De l'Interprétation'' * ARISTOTE, ''Seconds Analytiques'' * AUGUSTIN, ''Sur le mensonge'' * ANSELME, ''De Veritate'' * D’AQUIN, Thomas, ''De la vérité'' * DESCARTES, ''Méditations métaphysiques'' * DESCARTES, ''Recherche de la vérité par les lumières naturelles'' * SPINOZA, ''[[s:fr:L’Éthique|L’Éthique]]'' * MALEBRANCHE, ''De la recherche de la vérité'' * KANT, ''Critique de la raison pure'' * KANT, ''Sur un prétendu droit de mentir'' * NIETZSCHE, ''Le Gai Savoir'' === Textes récents === * RUSSELL, Bertand, ''Essais philosophiques'' * AYER, Alfred, ''Langage, vérité et logique'' * TARSKI, ''Logique, sémantique, métamathématique'' * AUSTIN, John, ''La Vérité'' * QUINE, ''La Poursuite de la vérité'' * ENGEL, Pascal, ''La Vérité : Réflexions sur quelques truismes'', Paris, Hatier, 1998 **Un petit livre clair et instructif, comportant des passages assez denses et hardus qui peuvent rebuter le débutant. * RORTY, Richard et ENGEL, Pascal, ''À quoi bon la vérité ?'', Paris, Grasset, 2005 **Une confrontation riche entre deux conceptions de la vérité (réalisme et pragmatisme). * FRANKFURT, Harry G., ''De l’art de dire des conneries'', traduit de l’américain par Didier Sénécal, Éditions 10/18, coll. « Fait et cause », 2006 ** Un livre amusant et sérieux. L'auteur distingue le mensonge du « baratin » (ou connerie, ''bullshit'' en anglais) relativement à la notion de vérité. Le menteur entretient un rapport déterminé à la vérité (pour mentir, il ne doit pas dire la vérité, ne pas avoir l'intention de la dire, mais cela suppose qu'il admette qu'il y a du vrai). Celui qui dit des conneries n'a en revanche aucun souci de la notion de vérité, raconte n'importe quoi et peut à l'occasion dire la vérité. L'homme politique est un cas exemplaire de baratineur, et, remarque Frankfurt, la volonté d'authenticité apparaît également comme une forme aujourd'hui très répandue de connerie. *DOKIC, Jérôme, ''La Perception'' **Voir la partie sur la connaissance et la perception. == Notions liées == * Réalité * Pensée, Croyance, Jugement, Proposition, Connaissance, Savoir * Erreur * Véracité, Sincérité, Confiance, Mensonge, Baratin {{Autocat}} 2spfa3v70l34wcl0zy1qz7r11mff2y4 Dictionnaire de philosophie/Mort 0 13740 768734 768689 2026-06-26T17:48:22Z PandaMystique 119061 768734 wikitext text/x-wiki {{DicoPhilo|Mort|lecture=oui}} La mort est à la fois l'évidence la mieux partagée et l'énigme la plus résistante. Chacun sait qu'il mourra ; personne n'a l'expérience de sa propre mort. Cette asymétrie explique que la philosophie ne cesse d'y revenir sans jamais l'épuiser. Encore faut-il préciser de quoi l'on parle, car le mot recouvre des questions distinctes qu'il serait imprudent de confondre. On peut distinguer quatre plans, qui se croisent sans se réduire l'un à l'autre. Sur le plan biologique, la mort est la cessation des fonctions qui maintiennent un organisme en vie, et la médecine cherche à en fixer le seuil et les critères. Sur le plan métaphysique, elle pose la question de ce qui disparaît exactement : un corps, une personne, une conscience, peut-être une âme. Sur le plan éthique, elle engage nos décisions, nos devoirs et nos droits, du deuil au soin des mourants, de l'[[Dictionnaire de philosophie/Euthanasie|euthanasie]] à la justice entre les générations. Sur le plan existentiel, enfin, elle n'est plus un événement futur parmi d'autres, mais l'horizon qui donne à chaque vie sa tonalité, son urgence et, peut-être, son sens. Cet article suit ces fils l'un après l'autre, en partant des repères que l'histoire de la philosophie nous a légués. == I. Définitions et approches fondamentales == === 1.1 Définitions ontologiques et biologiques === La mort est souvent décrite, de façon très générale, comme le passage de la vie à la non-vie. Cette formule a l'avantage de la simplicité, mais elle reste vague, car elle ne dit ni ce qu'est « vivre » au sens pertinent (biologique, psychologique, moral, juridique), ni à partir de quel seuil on doit parler de mort plutôt que d'agonie ou de défaillance grave. C'est pourquoi les discussions sur la mort se distribuent habituellement entre deux plans. D'un côté, la médecine et le droit cherchent des critères opératoires, permettant de constater un décès de manière fiable et publique. De l'autre, la philosophie demande ce que ces critères présupposent : s'agit-il de la fin d'un organisme, de la fin d'une personne, de la fin d'une conscience, ou de la fin d'un certain type de relation sociale et symbolique ? Dans les pratiques contemporaines, la mort est généralement constatée à partir d'un état tenu pour irréversible. Selon les cadres juridiques et médicaux, on retient soit la cessation irréversible des fonctions circulatoires et respiratoires, soit la cessation irréversible de l'ensemble des fonctions de l'encéphale (ce que l'on appelle couramment « mort encéphalique »). Il faut éviter ici une confusion fréquente : la « mort clinique » désigne classiquement la phase initiale d'un arrêt cardio-respiratoire, phase qui peut, dans certains cas, être réversible grâce à une réanimation rapide ; elle ne coïncide donc pas, par elle-même, avec la mort au sens du décès constaté. ==== 1.1.1 La mort : un phénomène biologique ==== La mort n'est pas un interrupteur qui ferait tomber instantanément toutes les fonctions du vivant. La décomposition est un processus, et la disparition des fonctions se fait à des vitesses différentes selon les tissus. C'est ce décalage qui explique que certaines activités cellulaires puissent persister un temps après l'arrêt de la circulation, sans que cela suffise à dire que « l'organisme », comme totalité vivante, continue d'exister. Il faut également corriger une idée reçue très répandue : les cheveux et les ongles ne « poussent » pas après la mort. L'impression de croissance vient surtout de la déshydratation et de la rétraction des tissus cutanés, qui découvrent davantage la tige du poil ou le bord de l'ongle et donnent une illusion d'allongement. Enfin, la notion de mort encéphalique soulève une difficulté conceptuelle bien connue. En pratique, l'état dit de « mort encéphalique » n'est possible, comme état clinique observable, que sous assistance (notamment ventilation et prise en charge de réanimation), puisque l'organisme ne respire plus spontanément. Des publications ont néanmoins signalé des cas de maintien somatique prolongé après un diagnostic de mort encéphalique, parfois pendant des semaines ou davantage, avec persistance de certaines fonctions (thermorégulation altérée mais partielle, croissance chez l'enfant, gestation maintenue sous assistance, etc.). Ces situations, rares et discutées, nourrissent la controverse sur l'idée selon laquelle le cerveau serait, à lui seul, « l'intégrateur » indispensable de l'organisme. ==== 1.1.2 La mort comme fin ou comme cessation : clarifier le vocabulaire ==== Pour éviter les malentendus, on peut distinguer deux manières de parler, qui ne se recouvrent pas toujours. La première décrit la mort comme une fin : le vivant « n'est plus », au sens où le sujet a cessé d'exister. La seconde décrit la mort comme une cessation : certaines fonctions vitales, tenues pour déterminantes, cessent définitivement. Ces deux descriptions se croisent souvent, mais elles ne répondent pas exactement à la même question. La première demande : « qu'est-ce qui disparaît ? » La seconde demande : « quels signes publics permettent d'établir que la disparition est advenue ? » Cette distinction éclaire un point important : les définitions opératoires (médicales et juridiques) ne sont pas, à elles seules, des définitions métaphysiques. Le droit doit pouvoir trancher, mais trancher ne revient pas à épuiser le sens de ce qui est tranché. C'est ce décalage qui explique, par exemple, qu'un même cadre légal puisse être jugé satisfaisant du point de vue de la sécurité des pratiques, tout en restant contesté du point de vue de la signification de la mort. On peut illustrer ce rôle des critères opératoires avec l'exemple, souvent cité, du droit américain : l'Uniform Determination of Death Act propose une formulation qui admet deux voies de constatation, l'une par la cessation irréversible des fonctions circulatoires et respiratoires, l'autre par la cessation irréversible de toutes les fonctions de l'ensemble du cerveau, tronc cérébral compris, la détermination devant suivre les standards médicaux reconnus. ==== 1.1.3 Les critères de la mort : problèmes contemporains ==== La question philosophique de la définition de la mort a acquis une urgence pratique nouvelle avec les progrès de la médecine moderne, notamment l'invention des respirateurs artificiels et des techniques de réanimation. Traditionnellement, la mort s'identifiait par le critère cardio-respiratoire : une personne était déclarée morte lorsque son cœur cessait de battre et qu'elle cessait de respirer de manière irréversible. Ce critère restait suffisant à une époque où l'arrêt cardiaque entraînait rapidement des dommages cérébraux irréversibles. Depuis les années 1960, un nouveau critère s'est progressivement imposé dans la plupart des juridictions : le critère de mort cérébrale (ou mort encéphalique). Selon ce critère, une personne meurt lorsque toutes les fonctions de son cerveau, ou du tronc cérébral, selon les juridictions, ont cessé de manière irréversible, même si son cœur continue de battre grâce au soutien artificiel<ref>President's Commission for the Study of Ethical Problems in Medicine, ''Defining Death: Medical, Legal and Ethical Issues'', Washington D.C., 1981</ref>. Cette redéfinition a été motivée en partie par des considérations pratiques (notamment la possibilité de prélever des organes pour transplantation), mais elle soulève des questions philosophiques fondamentales. Plusieurs philosophes et bioéthiciens ont contesté le critère de mort cérébrale. D'une part, certains patients déclarés en état de mort cérébrale continuent à manifester des fonctions intégratives significatives : régulation de la température corporelle, cicatrisation des blessures, réactions immunitaires, et dans quelques cas documentés, maturation sexuelle et croissance<ref>Alan Shewmon, « Brain Death: Can It Be Resuscitated? », dans ''Hastings Center Report'', vol. 39, n° 2, 2009, p. 18-24</ref>. Ces observations suggèrent que le cerveau ne constitue peut-être pas le seul organe responsable de l'intégration organisationnelle, ce qui ébranle le fondement biologique du critère de mort cérébrale. D'autre part, des travaux neuroscientifiques récents ont mis en évidence des formes de conscience préservée ou « couverte » chez des patients longtemps tenus pour dépourvus de toute vie mentale, par exemple certains sujets en état végétatif ou de conscience minimale<ref>Calixto Machado, « Neuroscience and Brain Death Controversies », dans ''Journal of Religion and Health'', vol. 57, n° 5, 2018, p. 2001-2015</ref>. Ces résultats portent sur les troubles de la conscience, et non sur la mort encéphalique correctement diagnostiquée, dans laquelle l'arrêt des fonctions cérébrales est par définition irréversible et exclut tout retour de la conscience ; ils rendent toutefois plus aiguë la question du tracé exact de la frontière et du risque d'erreur diagnostique. Si l'on définit la mort de la personne comme la perte irréversible de la capacité de conscience, ainsi que le proposent certains philosophes, le critère encéphalique paraît trop restrictif : un sujet ayant définitivement perdu toute conscience, comme dans un état végétatif chronique, reste vivant selon ce critère alors qu'il aurait, à cette aune, déjà cessé d'exister comme personne. À l'inverse, ce même critère rattache la mort à l'ensemble des fonctions cérébrales plutôt qu'à la seule conscience, ce qui en fait l'objet d'un désaccord persistant entre partisans d'une définition encéphalique globale et partisans d'une définition fondée sur les fonctions supérieures. Paweł Górka Nowak et Tomasz Żuradzki ont récemment soutenu qu'il n'existe point une seule définition biologiquement correcte de la mort, mais plutôt une pluralité de concepts d'organisme en biologie théorique, chacun donnant lieu à une conception différente de ce qui constitue la mort d'un organisme<ref>Nowak et Żuradzki, « How Many Ways Can You Die? », p. 4-19</ref>. Selon ces auteurs, la question « Quand une personne meurt-elle ? » n'a pas de réponse univoque indépendante du contexte et des objectifs pratiques que nous poursuivons en posant cette question. === 1.2 La mort comme privation et le problème du mal de mourir === L'une des grandes énigmes philosophiques consiste à déterminer en quoi consiste précisément le caractère nuisible de la mort. Pourquoi la mort est-elle considérée comme un mal ? Cette question, qui peut sembler évidente, a engendré des débats philosophiques intenses depuis l'Antiquité. ==== 1.2.1 L'argument épicurien : la mort n'est rien pour nous ==== Épicure, philosophe grec du {{s|IV}} avant notre ère, a formulé l'un des arguments les plus célèbres et les plus troublants concernant la mort. Dans sa ''Lettre à Ménécée'', il affirme que « la mort n'est rien pour nous » (ὁ θάνατος οὐδὲν πρὸς ἡμᾶς)<ref>Épicure, ''Lettre à Ménécée'', dans ''Lettres et Maximes'', traduction de Marcel Conche, PUF, 1987, p. 217-229</ref>. Son raisonnement peut se reconstituer comme suit : # Seul ce qui s'expérimente peut être bon ou mauvais pour nous (principe hédoniste). # La mort n'implique aucune expérience, puisque nous n'existons plus pour percevoir. # Par conséquent, la mort ne peut être ni bonne ni mauvaise pour nous. Lucrèce, poète et philosophe romain disciple d'Épicure, a développé cet argument dans son poème ''De Rerum Natura'' (''De la nature des choses''). Il soutient que puisque nous n'avons pas souffert de ne pas exister avant notre naissance, nous ne devrions pas craindre de ne pas exister après notre mort<ref>Lucrèce, ''De la nature'', livre III, vers 830-869, traduction de José Kany-Turpin, GF Flammarion, 1997, p. 253-257</ref>. Cet argument, souvent appelé « argument de symétrie », affirme que notre attitude envers la mort future devrait être symétrique à notre attitude (indifférente) envers notre non-existence passée. L'argument épicurien repose sur ce que les philosophes contemporains nomment « la condition d'existence » : quelque chose ne peut être bon ou mauvais pour un sujet que si ce sujet existe<ref>Fred Feldman, « Some Puzzles About the Evil of Death », dans ''The Philosophical Review'', vol. 100, n° 2, 1991, p. 205-227</ref>. Si cette condition s'accepte, et si la mort entraîne la cessation de l'existence (terminationnisme), il semble alors impossible que la mort soit nuisible pour celui qui meurt. Pourtant, l'argument épicurien heurte immédiatement nos intuitions les plus profondes. Nous jugeons généralement que la mort prématurée d'un jeune adulte constitue un grave malheur, qu'il est pire de mourir à vingt ans qu'à quatre-vingt-dix ans, et que tuer quelqu'un lui cause du tort. Si la mort n'était rien pour nous, toutes ces intuitions se trouveraient invalides. ==== 1.2.2 La théorie de la privation (Deprivation Account) ==== La réponse dominante à l'argument épicurien dans la philosophie analytique contemporaine est la ''théorie de la privation'' (''deprivation account''). Cette théorie affirme que la mort est nuisible pour celui qui meurt non en vertu de ses propriétés intrinsèques, la mort en elle-même n'implique effectivement aucune souffrance, mais en vertu de ses propriétés extrinsèques : la mort nous prive des biens et des expériences que nous aurions connus si nous avions continué à vivre<ref>Thomas Nagel, « Death », dans ''Mortal Questions'', p. 1-10</ref>. Selon cette approche, la mort constitue un mal ''comparatif'' : elle est nuisible parce qu'elle place la personne dans une situation pire que celle dans laquelle elle aurait été si elle n'était pas morte. Comme le formule Fred Feldman : « La mort au moment ''t'' est nuisible pour une personne ''S'' dans la mesure où elle rend la valeur de la vie de ''S'' inférieure à celle qu'elle aurait eue si ''S'' n'était pas morte à ''t'' »<ref>Feldman, ''Confrontations with the Reaper'', p. 133</ref>. La théorie de la privation repose sur une distinction essentielle entre deux types de valeur : la valeur intrinsèque et la valeur extrinsèque. Un état de choses possède une valeur intrinsèque en vertu de ses propriétés intrinsèques, la douleur est intrinsèquement mauvaise, le plaisir intrinsèquement bon. Un état de choses possède une valeur extrinsèque en vertu de ses relations avec d'autres états de choses, une vaccination douloureuse se révèle extrinsèquement bonne parce qu'elle prévient une maladie future. La mort, selon la théorie de la privation, est extrinsèquement nuisible : elle est mauvaise non pour ce qu'elle est, mais pour ce qu'elle empêche<ref>Christopher Wareham, « Deprivation and the See-saw of Death », dans ''South African Journal of Philosophy'', vol. 28, n° 2, 2009, p. 247-262</ref>. Cette approche parvient à esquiver l'objection épicurienne car elle ne requiert point que le sujet expérimente la mort comme nuisible. De même qu'une vaccination peut être bonne pour moi même si je ne perçois pas cette bonté au moment de la vaccination, la mort peut être nuisible pour moi même si je ne peux l'éprouver comme telle. L'erreur d'Épicure, selon les défenseurs de la théorie de la privation, consiste à avoir négligé la possibilité qu'un événement soit extrinsèquement nuisible. == II. La mort dans l'histoire de la philosophie == Avant d'aborder les problèmes contemporains, il vaut la peine de remonter le fil des grandes réponses que la tradition a formulées. Non par révérence pour les Anciens, mais parce que la plupart des arguments qui nous occupent encore s'y trouvent déjà esquissés. Apprendre à mourir, savoir ce qui survit, mesurer si la mort est un mal : ces trois interrogations traversent vingt-cinq siècles de pensée. === 2.1 L'Antiquité : la mort et l'exercice de la sagesse === C'est avec Platon que la mort devient un thème proprement philosophique. Dans le ''Phédon'', qui met en scène les dernières heures de Socrate avant qu'il ne boive la ciguë, la philosophie est définie comme un apprentissage de la mort. Ceux qui s'attachent à la philosophie de la droite manière, écrit Platon, s'exercent à mourir<ref>Platon, ''Phédon'', 64a.</ref>. La formule peut surprendre. Elle s'éclaire dès qu'on saisit ce que Socrate entend par mourir : la séparation de l'[[Dictionnaire de philosophie/Âme|âme]] et du corps. Or le philosophe, qui cherche le vrai, doit déjà de son vivant détacher sa pensée des sollicitations du corps ; mourir ne serait que l'achèvement de cet exercice. Derrière cette thèse se profile la doctrine de l'immortalité de l'âme, que le dialogue s'efforce d'établir par une série d'arguments : l'âme, simple et apparentée aux Idées, ne saurait se dissoudre comme se dissout le composé corporel. [[Dictionnaire de philosophie/Aristote|Aristote]], élève de Platon, refuse cette séparation. Pour lui, l'âme n'est pas un hôte logé dans le corps, mais la forme du corps vivant, ce qui fait qu'un organisme est en acte ce qu'il est. De cette définition découle une conséquence sévère : l'âme individuelle ne survit pas à la dissolution du composé, pas plus que la forme d'une statue ne subsiste une fois le bronze fondu. Un point reste discuté, celui du ''noûs'' (l'intellect), dont Aristote suggère en un passage obscur qu'il pourrait être séparable ; les commentateurs s'opposent depuis sur le sens de cette remarque. Sur la mort elle-même, Aristote est plus net. Dans l{{'}}''Éthique à Nicomaque'', il la nomme la chose la plus effrayante, parce qu'elle est une limite : pour celui qui est mort, dit-il, plus rien ne semble être ni bien ni mal<ref>Aristote, ''Éthique à Nicomaque'', III, 9, 1115a26.</ref>. Cette dernière observation ouvre déjà la voie à l'argument qu'Épicure rendra célèbre. Cet argument, on l'examine en détail plus loin (section 1.2). Rappelons-en seulement le principe : pour Épicure, la mort n'est rien pour nous, car tant que nous sommes, elle n'est pas là, et quand elle est là, nous ne sommes plus. La crainte de la mort reposerait donc sur une confusion. L'école rivale, le stoïcisme, parvient à une sérénité comparable par un autre chemin. Là où Épicure dissout la peur en niant que la mort nous concerne, les Stoïciens invitent à l'apprivoiser par un exercice quotidien, la ''meditatio mortis'' (la méditation de la mort), qui consiste à se représenter sa propre fin pour lui ôter son pouvoir de surprise. Médite la mort, écrit Sénèque à Lucilius : celui qui a appris à mourir a désappris à être esclave<ref>Sénèque, ''Lettres à Lucilius'', lettre 26.</ref>. Épictète déplace la difficulté du côté du jugement : ce n'est pas la mort qui effraie les hommes, mais l'opinion qu'ils s'en font<ref>Épictète, ''Manuel'', 5.</ref>. Marc Aurèle, enfin, replace la mort dans le cycle de la nature, où elle n'est qu'une transformation parmi d'autres, ni à désirer ni à fuir<ref>Marc Aurèle, ''Pensées pour moi-même'', IV, 17.</ref>. Quatre écoles, deux stratégies : nier que la mort nous atteigne, ou s'entraîner à la regarder en face. Une part de la sagesse antique se tient dans cet écart. === 2.2 De Montaigne à Spinoza : apprendre à mourir, apprendre à vivre === La Renaissance hérite de cette sagesse et la déplace. Dans un essai au titre programmatique, « Que philosopher c'est apprendre à mourir » (''Essais'', I, 20), Montaigne reprend d'abord le mot d'ordre antique : puisque la mort est le terme de notre course, mieux vaut l'avoir constamment à l'esprit pour n'en être jamais surpris. Mais l'intérêt de Montaigne tient à ce qu'il se déjuge. Dans les essais plus tardifs, et notamment dans « De l'expérience » (''Essais'', III, 13), il renverse la maxime : à force de penser à la mort, on risque de manquer la vie. La nature, observe-t-il, nous apprend mieux à mourir que toute la philosophie, à condition qu'on la laisse faire. Il souhaite que la mort le trouve occupé à son jardin, indifférent à elle et plus encore à son ouvrage inachevé<ref>Montaigne, ''Essais'', I, 20.</ref>. Ce passage du ''memento mori'' à une forme de confiance dans le cours des choses annonce un tournant. Spinoza en tire la formule la plus abrupte. Dans l{{'}}''Éthique'', il écrit que l'homme libre ne pense à rien moins qu'à la mort, et que sa sagesse est une méditation non de la mort, mais de la vie<ref>Spinoza, ''Éthique'', IV, proposition 67.</ref>. La phrase paraît contredire toute la tradition de la ''meditatio mortis''. Elle la prolonge en réalité, en la portant à son terme. Pour Spinoza, se complaire dans la pensée de la mort est une passion triste, qui diminue notre puissance d'agir. L'homme conduit par la raison ne nie pas qu'il mourra ; il refuse seulement de laisser cette pensée gouverner sa vie. La sagesse n'est pas de se préparer à la mort, mais de comprendre et d'aimer ce qui, en nous, participe de l'éternel. On mesure le chemin parcouru depuis le ''Phédon'' : l'immortalité, chez Spinoza, n'est plus la survie d'une âme individuelle après le trépas, mais un certain rapport à l'éternité que l'on peut éprouver dès maintenant. === 2.3 Schopenhauer : la mort, « muse » du philosophe === Le {{s|XIX}} accorde à la mort une place de premier plan. Schopenhauer va jusqu'à voir en elle l'origine même du philosopher : la mort, écrit-il, est le génie inspirateur de la philosophie, et sans elle on aurait peine à philosopher<ref>Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', supplément au livre IV, chapitre 41.</ref>. Sa pensée tient en une intuition. Ce qui meurt, c'est l'individu, ce phénomène passager ; mais l'individu n'est que la manifestation éphémère d'un vouloir-vivre (''Wille zum Leben'') unique, aveugle et sans terme, indifférent à la naissance comme à la mort de ses innombrables exemplaires. À l'échelle de ce vouloir, mourir n'est rien : la volonté ne se trouve pas entamée par la disparition d'un de ses reflets, de même que l'océan n'est pas diminué par la vague qui se brise. Cette consolation a quelque chose de glaçant, car elle s'achète au prix de l'individu, dont elle nie l'importance. Elle inaugure pourtant une manière neuve de penser la mort : non plus comme le problème d'un sujet inquiet pour son salut, mais comme un moment dans l'économie d'une nature impersonnelle. === 2.4 Le {{s|XX}} : pulsion de mort, personnes du mourir, histoire des attitudes === Le {{s|XX}} démultiplie les approches. Trois apports méritent d'être isolés, car ils ne se confondent ni avec le courant existentiel ni avec les débats analytiques que l'on retrouvera plus loin. Freud, d'abord, introduit en 1920 une hypothèse troublante. Dans ''Au-delà du principe de plaisir'', cherchant à comprendre la répétition des expériences pénibles, il avance l'existence d'une pulsion de mort (''Todestrieb''), tendance silencieuse de tout vivant à retourner à l'état inorganique d'où il est issu. La vie psychique serait le théâtre d'un conflit entre cette pulsion et les pulsions de vie (''Éros''). L'hypothèse reste contestée, y compris chez les psychanalystes ; elle a néanmoins imposé l'idée que le rapport à la mort travaille la psyché bien en deçà de la conscience. Quelques années plus tôt, dans « Considérations actuelles sur la guerre et sur la mort » (1915), Freud avait déjà relevé un paradoxe : nul ne croit à sa propre mort, et dans son inconscient chacun se tient pour immortel<ref>Sigmund Freud, « Considérations actuelles sur la guerre et sur la mort », 1915.</ref>. Jankélévitch, ensuite, propose dans ''La Mort'' (1966) une distinction devenue classique, celle des trois personnes de la mort. Il y a la mort en première personne, la mienne, dont je ne puis rien savoir puisque je ne lui survivrai pas ; la mort en deuxième personne, celle de l'être aimé, du « toi », qui m'atteint comme une amputation et m'ouvre pourtant à ce que la mort a de plus présent ; et la mort en troisième personne, anonyme et statistique, celle dont parlent les journaux, abstraite et presque indolore. La mort de l'autre proche occupe ici une situation singulière : assez proche pour me bouleverser, assez extérieure pour que j'y survive et la pense<ref>Vladimir Jankélévitch, ''La Mort'', Paris, Flammarion, 1966.</ref>. C'est ce thème que développeront, dans un autre vocabulaire, Levinas et Derrida (voir section 3.2). Ariès, enfin, n'est pas un philosophe mais un historien, et c'est ce déplacement qui fait son prix. Dans ''L'Homme devant la mort'' (1977), il montre que le rapport à la mort possède une histoire, que nos attitudes n'ont rien d'éternel. À la mort apprivoisée du Moyen Âge, familière et publique, aurait succédé, à l'époque contemporaine, une mort interdite, refoulée, dissimulée à l'hôpital et soustraite au regard des vivants. La thèse a été discutée et nuancée ; elle a le mérite de rappeler que la manière dont une époque traite ses mourants en dit long sur l'idée qu'elle se fait de la vie<ref>Philippe Ariès, ''L'Homme devant la mort'', Paris, Seuil, 1977.</ref>. Ce constat fait le lien avec les questions éthiques et bioéthiques que soulève aujourd'hui la médicalisation de la fin de vie (parties V et X). == III. La mort et l'identité personnelle == === 3.1 La continuité du moi et la survivance personnelle === La mort pose immédiatement une question métaphysique fondamentale : que devient ce qui me constitue lorsque je cesse de vivre ? Cette interrogation apparemment simple ouvre sur des problèmes ontologiques redoutables. Les théories de l'identité personnelle se divisent historiquement selon deux grands axes : d'un côté les théories du critère psychologique, de l'autre les théories dites somatiques. Ces deux approches proposent des réponses divergentes quant à la manière de concevoir ma relation à ma propre mort. ==== 3.1.1 Les théories psychologiques : la conscience comme fondement de l'identité ==== Les théories psychologiques, notamment chez John Locke et David Hume, font reposer l'identité personnelle sur une base psychologique : la continuité de la conscience et de la mémoire. Locke affirme explicitement dans son ''Essai concernant l'entendement humain'' (auquel il ajoute ce chapitre dans la deuxième édition de 1694) que « l'identité personnelle ne consiste pas dans l'identité de substance, mais dans l'identité de conscience »<ref>John Locke, ''An Essay Concerning Human Understanding'', Book II, Chapter XXVII, édition critique de P. H. Nidditch, Oxford University Press, 1975, p. 346</ref>. Cette formulation inédite introduit une distinction capitale entre trois types d'identité : l'identité de la personne, l'identité de l'homme (c'est-à-dire l'organisme biologique), et l'identité de substance. Selon Locke, seule la continuité de conscience garantit l'identité personnelle à travers le temps. Je suis la même personne que celle qui a accompli telle action passée dans la mesure où je peux me souvenir d'avoir accompli cette action. Ce qui importe au premier chef, ce n'est ni la persistance du même corps, ni la continuité de la même âme immatérielle, mais la chaîne ininterrompue de mémoire<ref>Locke, ''Essay'', Book II.XXVII.9-10, p. 346-347</ref>. Cette théorie psychologique possède des implications profondes pour notre compréhension de la mort : si l'identité personnelle consiste en continuité de conscience, alors la mort, entendue comme cessation irréversible de toute conscience, représente bien la fin du moi, la destruction de ce qui me rend moi-même. David Hume, philosophe écossais du {{s|XVIII}}, a transformé la théorie lockienne en l'approfondissant. Contrairement à Locke, Hume soutient que le moi n'est pas une entité substantielle stable mais plutôt un « faisceau de perceptions » (''bundle of perceptions''), c'est-à-dire une succession constante de pensées, de sensations et d'émotions<ref>David Hume, ''A Treatise of Human Nature'' (1739-40), Book I, Part IV, Section VI, traduction française de Jean-Pierre Clero, Garnier Flammarion, 1995, p. 301-314</ref>. Pour Hume, ce que nous appelons l'identité personnelle n'est qu'une fiction utile, une illusion née de la ressemblance et de la causalité entre nos perceptions successives. L'unité que nous attribuons à notre moi n'est qu'une construction artificielle de l'esprit. Le débat entre Locke et Hume reste central dans la philosophie contemporaine de l'identité personnelle. Ruth Boeker a montré que la théorie lockienne ne repose pas sur une simple analyse métaphysique, mais s'enracine dans des préoccupations morales et religieuses spécifiques : Locke développe sa théorie de l'identité en liaison directe avec sa conception de la responsabilité morale et du jugement divin<ref>Ruth Boeker, « Locke and Hume on Personal Identity: Moral and Religious Differences », dans ''Hume Studies'', vol. 41, n° 2, 2015, p. 105-135</ref>. La mémoire, pour Locke, constitue le critère d'identité non pas comme simple fait métaphysique brut, mais parce que la responsabilité morale, et particulièrement la possibilité du jugement et de la récompense ou du châtiment divins, exige que celui qui subit les conséquences de ses actes soit identique à celui qui les a commis. ==== 3.1.2 Derek Parfit et la réduction de l'identité personnelle : explications détaillées ==== ===== Le problème fondamental : réductionnisme vs. non-réductionnisme ===== Pour comprendre la contribution majeure de Derek Parfit à la philosophie de l'identité personnelle, il faut d'abord saisir une distinction conceptuelle capitale qu'il établit : celle entre réductionnisme et non-réductionnisme. ''La conception non-réductionniste'' affirme que l'existence d'une personne constitue une « réalité supplémentaire » (''further fact'') qui s'ajoute à l'ensemble des faits physiques et psychologiques. Selon cette vision, même si nous connaissions la totalité absolue des faits concernant mon cerveau, mon corps et tous mes états mentaux, il resterait encore un fait supplémentaire à déterminer : suis-je la même personne ou une personne différente ? Ce fait additionnel serait une réalité métaphysique fondamentale, irréductible, peut-être une âme immatérielle ou un « moi » cartésien pur<ref>Derek Parfit, ''Reasons and Persons'', Oxford University Press, 1984, p. 199-215</ref>. ''La conception réductionniste'', par contraste, soutient que l'existence d'une personne ne constitue point une réalité supplémentaire. L'existence d'une personne se réduit entièrement à l'existence de son cerveau, de son corps et à la manifestation de certains événements physiques et psychologiques. Parfit offre une analogie élucidante : de même que l'existence d'une nation n'ajoute aucune réalité supplémentaire au-delà des faits concernant les individus qui la composent et leurs interrelations mutuelles, l'existence d'une personne n'ajoute rien au-delà des faits psychophysiques<ref>Parfit, ''Reasons and Persons'', p. 210</ref>. Une nation constitue une réalité complexe mais réductible ; il en va identiquement pour une personne. Parfit défend le réductionnisme en soulignant l'absence totale de preuves probantes en faveur de l'existence de ces supposées « réalités supplémentaires ». Les cas de fission cérébrale, où le cerveau est divisé en deux, montrent qu'aucune entité métaphysique simple et indivisible ne détermine univoquement qui je suis. Aucune preuve scientifique ne corrobore l'existence d'une âme ou d'un moi cartésien<ref>Parfit, ''Reasons and Persons'', p. 207-210</ref>. ===== La théorie réductionniste de l'identité personnelle : la Relation R ===== Parfit propose que si nous adoptons le réductionnisme, nous devons spécifier les faits plus élémentaires en lesquels l'identité personnelle se réduit. Il examine deux candidates principales : la continuité physique et la continuité psychologique. Après analyse rigoureuse, il conclut que c'est la continuité psychologique qui importe<ref>Parfit, ''Reasons and Persons'', p. 201-215</ref>. Parfit introduit alors le concept central de sa théorie : ''la Relation R'' (continuité et connectivité psychologiques). Cette relation se compose de deux éléments distincts : 1. ''La connectivité psychologique directe'' (''psychological connectedness'') : les connexions immédiates et directes de mémoire, de désir, d'intention et autres états mentaux entre mes états psychologiques à deux moments différents. Par exemple, je me souviens d'avoir pris hier une décision particulière. 2. ''La continuité psychologique'' (''psychological continuity'') : une chaîne causale connectée d'états psychologiques reliés les uns aux autres, même si les états situés aux extrémités de cette chaîne ne sont pas directement connectés l'un à l'autre. Par exemple, je me souviens d'hier, hier je me souvenais d'avant-hier, et ainsi de suite, même si je ne me souviens peut-être pas directement d'événements remontant à mon enfance. La Relation R se définit donc comme ''la connectivité psychologique et/ou la continuité psychologique, pourvues de la bonne sorte de cause''. La « bonne sorte de cause » ne renvoie pas nécessairement à un mode naturel ordinaire de continuité ; ce qui importe est qu'il existe une relation causale appropriée entre les états psychologiques<ref>Parfit, ''Reasons and Persons'', p. 216</ref>. ===== Le cas de division du cerveau : le cœur du problème ===== La force de la position de Parfit réside largement dans son analyse du ''cas de division du cerveau'', qui crée une aporie majeure pour toutes les théories traditionnelles de l'identité. ''Le scénario :'' Imaginez que vous souffriez d'une maladie incurable et que la seule issue thérapeutique consiste à séparer vos deux hémisphères cérébraux, qui fonctionnent normalement de manière tout à fait indépendante, et à les transplanter chacun dans un corps différent. Les deux êtres conscients résultant de cette opération seraient qualitativement identiques à vous : ils posséderaient les mêmes souvenirs, les mêmes intentions, les mêmes traits de personnalité. Vous vous réveilleriez apparemment comme deux personnes distinctes, chacune convaincue d'être vous. ''Le problème logique qui en découle :'' Posez maintenant une question qui semble simple : dans ce scénario, serai-je numériquement identique à la personne qui se réveille dans le corps de gauche ? - Si la réponse est « oui », serai-je aussi numériquement identique à la personne du corps de droite ? - Si les réponses sont « oui » aux deux questions, alors par transitivité logique, les deux personnes seraient identiques l'une à l'autre, ce qui est absurde. - Si la réponse n'est « oui » que pour une seule des deux, il nous faut une raison objective pour distinguer les deux cas, mais aucune raison objective n'existe. Les deux corps sont identiques, et les deux personnes résultantes entretiennent une relation identiquement forte avec mon moi pré-division. - Si la réponse est « non » pour les deux, il semblerait que je ne survive pas à l'opération, ce qui contredit notre intuition : la totalité de ma vie mentale s'est néanmoins perpétuée et poursuivie dans les deux corps<ref>Parfit, ''Reasons and Persons'', Partie III, sections 79-80, p. 254-255</ref>. ''La conclusion paradoxale de Parfit :'' Parfit soutient que ce dilemme révèle que l'identité personnelle ne peut pas constituer ce qui compte vraiment pour la survie. Au lieu de cela, c'est ''la Relation R'' qui compte. Dans le cas de division, même si je ne suis numériquement identique à aucune des deux personnes résultantes (au sens strict de l'identité numérique), j'ai néanmoins survécu de la manière la plus excellente possible : la totalité de mes contenus mentaux, mes connexions psychologiques, se perpétuent dans les deux corps<ref>Parfit, ''Reasons and Persons'', p. 261</ref>. Parfit énonce ainsi sa célèbre maxime : « l'identité n'est pas ce qui compte » (''identity is not what matters''). Ce qui doit vraiment nous préoccuper concernant notre avenir, ce qui mérite notre inquiétude rationnelle, ce n'est point l'identité numérique stricte, mais plutôt la présence et la persistance de la Relation R<ref>Parfit, ''Reasons and Persons'', p. 215-216</ref>. ===== Implications pour notre compréhension de la mort ===== Cette théorie novatrice engendre des implications importantes pour notre rapport à la mort : ''Première implication :'' Si ce qui compte vraiment n'est pas l'identité personnelle mais la Relation R, alors notre peur ordinaire de la mort, entendue comme anéantissement simple et fin de l'identité, s'en trouve largement reconsidérée. La mort met certes fin à la Relation R, mais ce phénomène n'est pas plus mystérieux ou rationnellement troublant que d'autres ruptures naturelles de continuité<ref>Parfit, ''Reasons and Persons'', p. 216-223</ref>. ''Deuxième implication :'' Si dans le cas de division du cerveau, ne pas être identique à mes continuateurs psychologiques ne constitue pas un problème du moment que la Relation R se perpétue, alors nous devons remettre en question notre conception ordinaire et quasi-intuitive de la mort. Une mort prématurée n'est mauvaise que parce qu'elle prive la Relation R d'une continuité ultérieure possible. Elle ne constitue point un mystère métaphysique terrifiant ou incompréhensible<ref>Parfit, ''Reasons and Persons'', p. 280-281</ref>. ''Troisième implication :'' Parfit propose une conception graduée de la mort. Au lieu de la concevoir comme une fin abrupte, totale et catégorique, il invite à la penser, dans les cas limites du remplacement progressif, de la fission ou de la fusion, comme une diminution par degrés de la continuité psychologique, au point qu'il puisse n'exister aucune réponse tranchée à la question de savoir si la personne a survécu. Cette gradation concerne la persistance ou l'affaiblissement de la Relation R entre une personne et ses propres continuateurs psychologiques. Elle ne s'étend pas aux traces qu'un défunt laisse dans la mémoire d'autrui ou à l'influence posthume de son œuvre : ces dernières, si elles adoucissent peut-être le sentiment de perte, ne constituent pas la Relation R au sens technique, puisque celle-ci relie un sujet à ses états mentaux futurs et non à l'esprit d'autres personnes<ref>Parfit, ''Reasons and Persons'', p. 281</ref>. ===== Critiques majeures et difficultés ===== Cette théorie, bien qu'influente et féconde, affronte plusieurs objections philosophiques sérieuses : ''L'objection tirée de l'asymétrie :'' on peut douter, dans la lignée des interrogations de Bernard Williams sur l'anticipation, que la Relation R suffise à rendre compte de nos craintes rationnelles face à la mort. Dans une mort ordinaire, la Relation R cesse entièrement ; dans la fission, elle se trouve au contraire préservée chez les deux continuateurs. Si seule comptait la Relation R, la fission devrait nous paraître au moins aussi désirable qu'une survie ordinaire, alors que beaucoup la jugent troublante. Cette asymétrie de nos attitudes laisse penser que l'identité numérique, et non la seule Relation R, pèse dans notre rapport à la persistance et à la mort. David Lewis cherche au contraire à dissoudre la difficulté : correctement analysées au moyen des parties temporelles, identité et Relation R coïncideraient, de sorte que l'identité resterait bien ce qui importe<ref>David Lewis, « Survival and Identity », dans ''The Identities of Persons'', University of California Press, 1976, p. 17-40</ref>. ''L'objection de la non-trivialité :'' Si la Relation R est ce qui compte vraiment, alors selon Parfit, la question « serai-je identique à quelqu'un dans le futur ? » n'est pas tranchée par des faits profonds et non-triviaux. Or, cela semble peu convaincant : que je survive ou non me paraît dépendre de faits bien plus fondamentaux que la simple absence de division cérébrale ou la présence de continuité psychologique<ref>Parfit, ''Reasons and Persons'', p. 264-265</ref>. ''L'objection de la perplexité conceptuelle :'' Si dans le cas de division je ne suis numériquement identique à aucune des deux personnes résultantes, mais que je survis néanmoins en un sens significatif, cela rend le concept même de survie perplexe et énigmatique. Qu'est-ce que « survivre » pourrait signifier si ce n'est précisément être identique à une personne future<ref>Derek Parfit, « We Are Not Human Beings », ''Journal of Consciousness Studies'', vol. 19, n° 5-6, 2012, p. 79-105</ref> ? ===== La révision ultérieure de Parfit ===== Une trentaine d'années après ''Reasons and Persons'', Parfit est revenu sur la question de ce que nous sommes. Dans « We Are Not Human Beings » (2012), il soutient que nous ne sommes pas des animaux de l'espèce humaine, mais la partie consciente et pensante de ces animaux, qu'il identifie au cerveau, ou plus précisément à la portion du cerveau qui sous-tend directement la conscience<ref>Parfit, « We Are Not Human Beings », p. 79-105</ref>. Cette thèse porte sur l'ontologie de la personne, c'est-à-dire sur la nature de ce que nous sommes, et non sur ce qui compte dans la survie : Parfit n'y abandonne pas l'idée, défendue dès 1984, que c'est la continuité psychologique, et non l'identité numérique, qui importe. La portée de ce déplacement est discutée. Olson y voit le signe que la distinction entre Relation R et identité numérique restait difficile à stabiliser, et lit ce texte comme un repli vers une forme d'animalisme centré sur le cerveau<ref>E. T. Olson, « On Parfit's View that We are not Human Beings », dans ''Journal of Philosophy'', vol. 112, n° 1, 2015, p. 5-22</ref>. On peut au contraire souligner la continuité du propos : en distinguant l'animal du sujet pensant, Parfit cherche moins à se rétracter qu'à préciser le support de la continuité psychologique déjà placée au centre de ce qui compte. Sa contribution garde en tout cas son intérêt, celui d'avoir montré que les intuitions ordinaires sur l'identité et la mort reposent sur des présupposés métaphysiques contestables qui appellent un examen critique. ==== 3.1.3 L'animalisme : la mort comme mort de l'organisme ==== Face aux théories psychologiques, une position rivale s'est progressivement imposée au cours des dernières décennies : l'animalisme. Selon cette approche, nous ''sommes'' des organismes biologiques appartenant à l'espèce ''Homo sapiens''<ref>Eric Olson, ''The Human Animal: Personal Identity Without Psychology'', Oxford University Press, 1997, p. 1-18</ref>. Ce que nous désignons par le terme « personne » constitue simplement un animal particulier, nous ne sommes pas composés d'un corps animal auquel s'ajouterait une personne psychologique ; nous ''sommes'' l'animal lui-même. Cette théorie possède des implications directes pour notre conception de la mort. Si je suis un organisme biologique, je meurs précisément quand cet organisme meurt, c'est-à-dire lorsque ses fonctions biologiques intégrées cessent de manière irréversible. L'animalisme semble offrir une réponse simple : la mort est littéralement la mort de l'organisme dont je suis, et c'est pourquoi elle constitue un mal pour moi<ref>Olson, ''The Human Animal'', p. 107-128</ref>. Il ne s'agit pas de chercher dans des abstractions psychologiques pour comprendre l'identité personnelle ; il suffit de reconnaître que je suis, ontologiquement, un animal. Cependant, l'animalisme affronte une objection majeure. Si je suis le même animal que le fœtus dans l'utérus maternel ou que le nourrisson que j'ai été, comment affirmer que je suis identique à ce nourrisson, doté maintenant de souvenirs, de croyances et de désirs que le nourrisson ne possédait nullement ? Kevin Sharpe a proposé une position intermédiaire : le « psychological animalism » selon laquelle nous sommes essentiellement à la fois des animaux et des personnes<ref>Kevin W. Sharpe, « Animalism and Person Essentialism », dans ''Metaphilosophy'', vol. 46, n° 1, 2015, p. 48-68</ref>. Selon cette approche plus nuancée, nos conditions de persistance sont à la fois biologiques (puisque nous sommes des organismes) et psychologiques (puisque nous sommes essentiellement des personnes conscientes). ==== 3.1.4 Paul Ricoeur et l'identité narrative ==== Une approche différente a été développée par le philosophe français Paul Ricoeur, qui propose le concept d'« identité narrative ». Ricoeur reconnaît que toutes les théories traditionnelles de l'identité personnelle affrontent des difficultés logiques fondamentales : elles tentent toutes de fonder l'identité sur une base objective (la continuité de substance, de conscience, ou d'organisme), alors que la réalité de l'identité personnelle est bien plus complexe et herméneutique<ref>Paul Ricoeur, ''Oneself as Another'', traduction de Kathleen Blamey, University of Chicago Press, 1992, p. 113-159</ref>. Ricoeur propose que l'identité personnelle s'établit plutôt à travers le récit que j'élabore de moi-même. Je suis la personne que je me raconte être, et cette identité narrative se constitue par la manière dont j'intègre les événements de ma vie, y compris ma conscience de ma finitude et de ma mortalité, dans une totalité cohérente<ref>Ricoeur, ''Oneself as Another'', p. 140-168</ref>. L'importance de cette approche pour la compréhension de la mort réside en ceci : ma relation à ma propre mortalité ne se réduit pas à une simple question de fait biologique ou de continuité psychologique ; elle constitue une dimension constitutive de la manière dont je me comprends moi-même en tant que sujet. La mortalité, selon Ricoeur, confère forme et sens à ma vie en lui donnant une trajectoire comprise entre naissance et mort. La conscience de ma finitude ne représente pas une simple information supplémentaire me concernant ; elle transforme de fond en comble le sens de mon identité<ref>Ricoeur, ''Oneself as Another'', p. 451-476</ref>. Cette approche narrative offre un avantage de poids : elle évite les apories des théories purement métaphysiques de l'identité en reconnaissant que l'identité personnelle constitue une construction herméneutique à la fois individuelle et collective, et qu'elle reste essentiellement liée au temps vécu et à la conscience de la finitude. === 3.2 La mort de l'autre et l'altérité irréductible === Un aspect trop souvent négligé de la philosophie de la mort concerne ma relation à la mort d'autrui, plutôt que ma relation anticipée à ma propre mort. Tandis que la tradition existentialiste insiste sur la manière dont l'anticipation de ma propre mort structure mon existence, une autre tradition philosophique, issue notamment d'Emmanuel Levinas, soutient que c'est précisément la mort de l'autre, et non la mienne, qui pose la question éthique fondamentale. ==== 3.2.1 Levinas et l'impossibilité d'approprier la mort de l'autre ==== Emmanuel Levinas, philosophe d'origine lituanienne qui a passé la majeure partie de sa vie en France, a mis en avant le caractère éminemment singulier et irréductible de la mort d'autrui. Dans son œuvre majeure ''Totalité et Infini'', Levinas critique explicitement les philosophies existentialistes (particulièrement Heidegger) qui tendent à ramener la mort à une structure constitutive de l'existence du Dasein : il n'existe, selon Levinas, aucun moyen pour moi d'anticiper ou de posséder la mort de l'autre de la même façon que je pourrais (du moins en principe) anticiper ma propre mort<ref>Emmanuel Levinas, ''Totalité et Infini. Essai sur l'Extériorité'', Martinus Nijhoff, 1961, p. 235-250</ref>. Levinas établit une distinction entre le mourir en tant que réalité que j'expérimente, acte que je pourrais en principe anticiper et intérioriser, et la mort d'autrui comme événement qui m'échappe entièrement. La mort du proche est ce qui me « résiste » de manière absolue, ce qui n'entre jamais dans le champ de ma compréhension ou de mon pouvoir<ref>Levinas, ''Totalité et Infini'', p. 238-240</ref>. Ce qui différencie foncièrement la position levinassienne de celle de Heidegger, c'est que pour Levinas, ce n'est pas ma mort qui me constitue éthiquement, mais ma responsabilité infinie face à la mort de l'autre. La vulnérabilité d'autrui face à la mort m'appelle à la responsabilité éthique. La mort possible de celui que j'aime, la fragilité absolue du proche, le fait qu'à tout moment il peut disparaître, autant de réalités qui me posent une obligation morale incontournable<ref>Emmanuel Levinas, « De la conscience à la veille » (1990), dans ''Dieu, la mort et le temps'', traduction de Michel Haerne, Grasset, 2007, p. 97-128</ref>. Cette responsabilité ne constitue pas quelque chose que j'aurais ''choisi'' de prendre, mais quelque chose auquel je suis d'emblée assigné du simple fait même de ma relation à autrui. ==== 3.2.2 Derrida et le deuil comme appropriation impossible ==== Jacques Derrida, philosophe franco-algérien qui a poursuivi certaines intuitions de Levinas, a accordé une importance philosophique centrale à la mort d'autrui, notamment à travers le phénomène du deuil. Dans son ouvrage ''Aporias'', Derrida pose des questions vertigineuses : la mort de l'autre peut-elle être anticipée ou redoutée de la même manière que ma propre mort ? N'existe-t-il pas une asymétrie entre mon rapport à ma propre mortalité et mon rapport à celle d'autrui<ref>Jacques Derrida, ''Aporias'', Galilée, 1996, p. 47-52</ref> ? Derrida établit une distinction conceptuelle fondamentale entre le « mourir » (''dying''), qui désigne mon expérience particulière de mon propre processus vers la mort, et le « périr » (''perishing''), qui désigne l'altérité absolue de l'événement de mort d'autrui. Le mourir peut posséder un caractère de ''mien'', en un sens ; le périr de l'autre ne peut jamais réellement m'appartenir, c'est précisément ce qui m'échappe de manière irréductible<ref>Derrida, ''Aporias'', p. 78-84</ref>. Cette distinction est déterminante pour comprendre le deuil : celui-ci porte essentiellement sur quelque chose d'irrémédiablement perdu et incommunicable. Derrida introduit une autre distinction conceptuelle importante : celle entre le travail du deuil (''mourning work'') et la mélancolie. Selon la tradition psychanalytique héritée de Freud, le travail du deuil consiste à progressivement désinvestir l'objet perdu pour réinvestir les relations vivantes. Cependant, Derrida soutient que ce modèle du deuil « réussi » passe sous silence quelque chose d'essentiel : la mort de la personne est unique, irremplaçable, incomparable. Aucun deuil ne peut être vraiment « complètement élaboré », car cela supposerait que la personne décédée puisse être finalement « intégrée » à mon univers psychique et émotionnel, ce qui constituerait une forme de trahison envers son absolue singularité<ref>Jacques Derrida, ''The Work of Mourning'', traduction d'Edmund Jephcott, Pascale-Anne Brault et Michael Naas, University of Chicago Press, 2001, p. 1-30</ref>. Plus précisément, Derrida soutient que le deuil doit rester « impossible » en un sens précis : il faut à la fois s'approprier d'une certaine manière la mort de celui que j'ai aimé (pour ne pas l'abandonner à l'indifférence totale) et en même temps ne pas l'approprier complètement (pour respecter son altérité absolue)<ref>Derrida, ''The Work of Mourning'', p. 169-175</ref>. Le deuil authentique oscille dans cette aporie, dans ce double lien impossible. C'est en cela que tout deuil porte en lui une dimension irréductiblement mélancolique, non pas comme pathologie psychologique, mais comme structure constitutive de la relation à celui qui meurt. ==== 3.2.3 La mort de l'autre et la transformation de mon identité ==== La mort d'autrui ne se limite pas à constituer un problème éthique abstrait ; elle bouleverse mon identité personnelle. Levinas affirme avec une force particulière que « la mort de l'autre affecte ma responsabilité »<ref>Emmanuel Levinas, ''Autrement qu'être ou au-delà de l'essence'', Martinus Nijhoff, 1974, p. 247-253</ref>. La mort d'un proche, d'une personne envers laquelle j'assumais une responsabilité, cela m'affecte ''en moi-même'', ce n'est pas une expérience que je pourrais simplement observer ou éprouver de manière neutre. La perte de celui qui meurt transforme ma relation à moi-même. Je ne suis plus la même personne après la mort de quelqu'un qui m'était cher. Mais cette transformation ne se réduit pas à une simple modification psychologique, ni même essentiellement affective, elle est d'abord éthique. J'ai perdu un vis-à-vis, quelqu'un à qui je devais rendre des comptes. Cette perte redéfinit constitutionnellement ce que je suis<ref>Paul Ricoeur, ''La Mémoire, l'Histoire, l'Oubli'', Éditions du Seuil, 2000, p. 523-538</ref>. Le deuil, dans cette perspective, ne constitue pas simplement un travail psychologique de séparation et d'élaboration ; il s'agit d'une reconstitution fondamentale de mon identité en l'absence de celui qui en était une part essentielle. ==== 3.2.4 La singularité irremplaçable de chaque mort ==== Une dernière dimension de l'importance philosophique de la mort de l'autre concerne sa singularité absolue et irremplaçable. Derrida insiste avec persistance sur le fait que chaque mort est unique, incomparable, singulière. Face à la mort de celui qu'on aime, ce que nous éprouvons c'est que « avec sa mort, c'est un monde entier qui disparaît »<ref>Derrida, ''The Work of Mourning'', p. 322-325</ref>. Cette affirmation peut sembler exagérée, car bien entendu le monde continue physiquement après la mort d'une personne. Mais Derrida entend souligner que du point de vue éthique et existentiel, quelque chose d'irréversible s'effondre. Cette singularité de chaque mort crée une tension philosophique majeure. D'un côté, nous cherchons à honorer la mémoire des morts en les intégrant à une histoire collective, à un récit communautaire qui préserve leur mémoire. De l'autre côté, cette intégration comporte un risque significatif : celui de « normaliser » ce qui était unique en son genre, de réduire le mort à une place dans une série identique<ref>Derrida, ''The Work of Mourning'', p. 140-160</ref>. C'est pourquoi le deuil authentique doit naviguer dans cette tension irrésolue : reconnaître l'unicité incomparable du disparu tout en le gardant présent dans la communauté des vivants, sans jamais complètement l'assimiler. Cette question de la singularité de chaque mort rejoint une dimension essentielle de ma relation à mon identité personnelle : je suis moi aussi unique et incomparable, et ce que je redoute dans la mort, c'est peut-être moins la perte abstraite de conscience que la cessation de cette singularité particulière qui est précisément la mienne. L'impossibilité pour autrui de me sauver de ma propre mort, tout comme mon impossibilité à sauver celui que j'aime de sa mort, constituent deux faces d'une même condition humaine : nous sommes chacun seul face à notre mort, dans une solitude sans partage. Et c'est paradoxalement cette solitude partagée qui constitue le fondement même de notre communauté éthique. == IV. Existentialisme et finitude == === 4.1 Martin Heidegger et l'être-vers-la-mort === La compréhension existentialiste de la mort s'enracine étroitement dans l'œuvre majeure de Martin Heidegger, ''Être et Temps'' (1927). Heidegger pose une question apparemment simple mais philosophiquement centrale : qu'est-ce que vivre authentiquement ? Sa réponse s'articule autour du concept du ''Sein-zum-Tode'', l'« être-vers-la-mort », qui ne constitue point une morbide obsession pour la mort, mais une élucidation fondamentale de ce que signifie exister en tant qu'être humain<ref>Martin Heidegger, ''Sein und Zeit'' (1927), traduction française de François Vezin, Gallimard, 1986, divisions II et sections 46-53, p. 279-304</ref>. Heidegger établit d'abord une distinction capitale entre le ''Dasein'' (littéralement « être-là »), terme qu'il utilise pour désigner spécifiquement l'existence humaine, et les autres formes d'être. Ce qui caractérise uniquement le Dasein, c'est que son être-même reste constamment une question pour lui. Tandis que les choses inanimées simplement sont, et tandis que les animaux existent selon des instincts programmés, le Dasein est l'étant pour lequel il y va, en son être, de cet être même : il a à être ce qu'il est<ref>Heidegger, ''Sein und Zeit'', Introduction, p. 9-20</ref>. C'est précisément dans cette ouverture à la mort que réside l'authenticité de l'existence. Heidegger affirme que la mort se situe à l'horizon de toute existence humaine, mais que nous la fuyons généralement. Dans la vie quotidienne, nous nous perdons dans le « On », ce que nous pourrions appeler le « on-dit », la doxa, la sagesse populaire partagée, et nous nous laissons absorber dans les préoccupations de la routine. Le Dasein se disperse dans ce qu'il fait, ce qu'il pense, ce que tout le monde pense<ref>Heidegger, ''Sein und Zeit'', section 27, p. 153-164</ref>. Heidegger énonce quatre caractéristiques fondamentales de la mort envisagée existentialement. Elle est d'abord « non-relationnelle » (unbeziehbar), nul ne peut mourir à ma place, car ma mort reste rigoureusement singulière et insubstituable. Ensuite, elle est « certaine », nous savons avec une certitude indubitable que nous mourrons. Elle est aussi « indéfinie », bien que la mort soit certaine, nous ignorons quand elle surviendra. Enfin, elle est « insurpassable » (unüberholbar), aucune possibilité future ne peut dépasser ou surpasser la mort, car elle termine toutes les possibilités<ref>Heidegger, ''Sein und Zeit'', section 50, p. 293-299</ref>. Mais pourquoi cette analyse minutieuse de la mort revêt-elle une importance ontologique pour Heidegger ? Parce que la conscience de la mort, loin de paralyser l'existence, la libère en réalité pour une authenticité. Confronté à la certitude absolue de sa mort, le Dasein peut se « ressaisir » face au flux inauthentique de la vie quotidienne. Cette prise de conscience s'accompagne généralement d'une émotion caractéristique que Heidegger appelle l'« angoisse » (Angst), non la peur devant un objet spécifique, mais plutôt une tonalité affective originaire face au néant et à la liberté<ref>Heidegger, ''Sein und Zeit'', section 40, p. 227-231</ref>. [[Dictionnaire de philosophie/Angoisse|L'angoisse]], pour Heidegger, ne constitue point une pathologie, elle demeure salutaire. Elle arrache le Dasein à son immersion commode dans les préoccupations triviales et le confronte à la nudité de son existence. En expérimentant cette angoisse face à sa propre finitude, le Dasein découvre ce que Heidegger appelle sa « possibilité la plus extrême ». Cette possibilité, c'est précisément de vivre en constante anticipation de la mort, non par morbidité, mais comme principe d'organisation de l'existence authentique<ref>Heidegger, ''Sein und Zeit'', sections 30-31, p. 176-189</ref>. Cette « anticipation authentique de la mort » (eigentliches Vorlaufen-zu-Tode) constitue ce que Heidegger appelle la « résolution authentique » ou « authenticité » (Eigentlichkeit). Elle ne paralyse point l'existence ; au contraire, elle nous permet de vivre de manière résolue, d'accepter nos responsabilités avec une lucidité nouvelle, et de nous approprier notre propre existence plutôt que de simplement la subir passivement<ref>Heidegger, ''Sein und Zeit'', section 53, p. 304-314</ref>. === 4.2 Jean-Paul Sartre : la liberté face à la facticité et la mort === Jean-Paul Sartre, bien qu'influencé par Heidegger, apporte une perspective toute différente sur la mort et l'existence. Le principe fondamental du système sartresque repose sur l'affirmation que « l'existence précède l'essence », proposition qui inverse complètement la tradition métaphysique occidentale<ref>Jean-Paul Sartre, ''L'existentialisme est un humanisme'' (1945), Éditions Nagel, 1966, p. 15-49</ref>. Selon Sartre, aucune essence humaine fixe ne préexiste à notre entrée dans l'existence. Nous venons à l'existence d'abord, et ce n'est qu'ensuite, par nos choix et nos actions, que nous créons notre essence et définissons ce que nous sommes. Il n'existe pas de « nature humaine » en attente de réalisation ; il n'existe que la tâche constante de nous créer nous-mêmes<ref>Sartre, ''L'existentialisme est un humanisme'', p. 45-49</ref>. Cette liberté, toujours prise dans une situation concrète, engendre ce que Sartre appelle une « responsabilité absolue ». Nous sommes « condamnés à être libres », c'est-à-dire que nous ne pouvons nous échapper à la nécessité de choisir et de créer notre essence. Aucune instance divine, aucune nature fixe, aucune détermination externe ne peut nous exonérer de cette responsabilité<ref>Sartre, ''L'Être et le Néant'', Gallimard, 1943, p. 9-60</ref>. Comment la mort s'inscrit-elle dans cette philosophie de la liberté absolue ? Ici, Sartre adopte une position critique envers l'approche heideggérienne. Pour Sartre, la mort ne constitue pas une structure fondamentale de l'existence, c'est plutôt un fait brut, une contingence qui met fin à la possibilité d'existence sans pour autant structurer l'existence elle-même. Sartre affirme que « la mort n'est jamais ce qui donne sens à la vie ; c'est au contraire ce qui enlève tout sens à la vie »<ref>Sartre, ''L'Être et le Néant'', p. 615-617</ref>. Cette affirmation peut sembler étrange, mais elle exprime une intuition importante : contrairement à Heidegger qui voit dans la mort un principe d'organisation pour une vie authentique, Sartre soutient que la mort est simplement ce qui intervient du dehors, cessant abruptement toute possibilité de création de sens<ref>Sartre, ''L'Être et le Néant'', p. 619-623</ref>. Donc, plutôt que de nous interroger sur « comment vivre authentiquement en vue de la mort », nous devrions nous interroger sur « comment créer du sens et des valeurs dans une existence absurde qui sera inévitablement terminée »<ref>Sartre, ''L'existentialisme est un humanisme'', p. 37-44</ref>. Pour Sartre, la vraie question n'est donc pas celle de la finitude face à la mort, mais celle de la liberté face à la facticité, c'est-à-dire face aux conditions concrètes données de notre existence (notre classe sociale, notre époque historique, notre corps, etc.). Notre liberté consiste à transcender cette facticité, à la dépasser vers des projets futurs, à nous créer dans et par rapport à ces conditions<ref>Sartre, ''L'Être et le Néant'', p. 568-580</ref>. === 4.3 Søren Kierkegaard : l'angoisse comme condition de la liberté === Bien que Kierkegaard soit antérieur au mouvement existentialiste proprement dit, ses analyses de l'angoisse et de la liberté constituent une source majeure pour les existentialistes modernes. Dans son ouvrage ''Le Concept d'angoisse'' (1844), Kierkegaard propose une analyse psychologique et métaphysique de cette émotion première<ref>Søren Kierkegaard, ''Le Concept d'angoisse'', traduction de Knud Ferlov et Jean-J. Gateau, Éditions Gallimard, 1990, p. 45-120</ref>. Kierkegaard distingue soigneusement entre la « peur » et l'« angoisse ». La peur porte toujours sur quelque chose de spécifique, on a peur d'un chien, d'une maladie, d'une blessure physique. L'angoisse, en contraste, ne porte sur rien de précis. Elle constitue plutôt l'émotion devant la pure possibilité, devant la liberté elle-même et ses implications infinies<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 70-75</ref>. Kierkegaard illustre cette distinction par une image frappante. Un homme se tient au bord d'un précipice. Il craint certes de tomber, c'est une peur naturelle et rationnelle. Mais il éprouve aussi l'angoisse en réalisant qu'il reste libre de sauter. Rien dans le monde physique ne l'empêcherait de se jeter dans le vide si telle était sa volonté. C'est cette conscience de sa propre liberté, de cette possibilité absolue face à l'abîme, qui constitue l'angoisse, ce que Kierkegaard appelle « le vertige de la liberté »<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 61-65</ref>. Cruciale est l'observation de Kierkegaard selon laquelle cette angoisse ne constitue pas simplement un défaut à corriger, mais une dimension intrinsèque et inévitable de l'existence humaine. Chaque être conscient, chaque entité pourvue de liberté, doit expérimenter l'angoisse. Car la liberté elle-même consiste en la conscience d'une multiplicité infinie de possibilités, dont aucune n'est garantie, dont aucune ne s'impose avec une nécessité absolue<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 45-50</ref>. Or, cette angoisse est étroitement liée chez Kierkegaard à la conscience de la mort. Pourquoi ? Parce que la mort représente la limite absolue de ma liberté, le moment où l'ensemble des possibilités qui se déploient devant moi s'effondrera et prendra fin. La conscience de cette possibilité ultime de ne-plus-être confère à ma liberté une intensité particulière et une responsabilité accablante. Je dois choisir ma vie, créer mon essence, décider de mon être, sachant qu'une fin certaine viendra mettre un terme à ce processus<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 113-120</ref>. Pour Kierkegaard, l'angoisse peut mener à deux chemins opposés : ou bien elle inspire le désespoir, la démission face à la liberté, le refuge dans des certitudes factices, ou bien elle devient le catalyseur d'une existence authentique fondée sur la foi et la passion<ref>Kierkegaard, ''Étapes de la vie'', traduction de Jean-J. Gateau, Éditions Gallimard, 1943, p. 340-360</ref>. === 4.4 Albert Camus et la révolte face à l'absurde === Albert Camus, bien qu'il rejette l'étiquette d'« existentialiste » (notamment en raison de ses désaccords avec Sartre), offre une réflexion existentielle majeure sur la mort envisagée comme source de l'absurde. Dans son essai ''Le Mythe de Sisyphe'' (1942), Camus énonce une thèse frappante : « Il n'y a qu'un seul problème philosophique vraiment sérieux : c'est le suicide »<ref>Albert Camus, ''Le Mythe de Sisyphe'', Gallimard, 1942, p. 13-18</ref>. Cette affirmation peut sembler extrême, mais elle exprime une vérité existentielle profonde. Car si l'existence demeure absurde, c'est-à-dire si elle se confronte à une contradiction insurmontable entre nos exigences rationnelles et un univers qui reste par essence irrationnel, alors à quoi bon vivre ? Si nos vies sont destinées au néant, si tous nos projets, nos aspirations, nos créations finiront dans l'oubli et le silence de la mort, quel sens peuvent-ils posséder<ref>Camus, ''Le Mythe de Sisyphe'', p. 25-45</ref> ? Camus identifie trois réponses possibles à ce problème. Première réponse : le suicide physique, qui consiste à céder face au sentiment d'absurdité en mettant fin à sa propre vie. Seconde réponse : le « suicide philosophique », qui consiste à s'échapper dans la foi religieuse ou dans une philosophie qui promet un absolu, que ce soit Dieu, l'Idée, la Raison. Ces deux options, selon Camus, échouent : le suicide physique annule simplement la possibilité même d'existence ; le suicide philosophique constitue une forme de déshonnêteté envers la réalité<ref>Camus, ''Le Mythe de Sisyphe'', p. 47-80</ref>. Mais existe une troisième voie : la révolte. Camus propose d'« imaginer Sisyphe heureux ». Sisyphe, cet être mythologique condamné à repousser éternellement un rocher qui retombe toujours, devient pour Camus le symbole du héros absurde. Il ne se suicide point ; il ne s'échappe point non plus dans l'illusion d'une signification cosmique. Au lieu de cela, il accepte pleinement l'absurdité de sa condition, il reconnaît que ses efforts restent vains, que le rocher retombera toujours, mais il persiste néanmoins. Il accepte la lutte, non en espérant qu'elle produise un résultat final satisfaisant, mais pour la simple raison que vivre, persister, lutter constituent la réalité de l'existence<ref>Camus, ''Le Mythe de Sisyphe'', p. 168-180</ref>. Cette position camussienne face à la mort diffère significativement de celle de Heidegger. Pour Camus, il ne s'agit pas de se projeter authentiquement vers la mort pour donner une structure à l'existence. Au contraire, il s'agit de reconnaître clairement le caractère brut et inintelligible de la mort, et pourtant de continuer à vivre avec passion, solidarité et lucidité. La mort demeure un scandale, une injustice même, mais cette injustice ne nous autorise point à cesser d'exister<ref>Camus, ''Le Mythe de Sisyphe'', p. 120-140</ref>. === 4.5 Karl Jaspers et les « situations limites » === Karl Jaspers, philosophe allemand qui a influencé à la fois Heidegger et Sartre, apporte une perspective distincte sur la mort en la situant dans le contexte plus large de ce qu'il appelle les « situations limites » (Grenzsituationen). Ces situations constituent des moments où les limites de la compréhension rationnelle se heurtent à l'inévitable : la mort, la souffrance, la culpabilité, le hasard<ref>Karl Jaspers, ''Introduction à la pensée philosophique'', traduction d'Yvon Belaval, Éditions 10/18, 1970, p. 40-65</ref>. Jaspers établit une distinction importante entre deux significations de la mort. D'abord, la mort est un fait objectif, la cessation des fonctions vitales, une réalité biologique. Ensuite, la mort constitue une situation limite existentielle, une expérience que je dois affronter personnellement, qui me concerne d'une manière unique et irremplaçable<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 45-50</ref>. C'est précisément cette deuxième dimension qui revêt une importance existentielle cardinale. Confronté à sa propre finitude, à la conscience de sa propre mort, l'être humain peut soit se perdre davantage dans l'inauthenticité, soit accéder à un niveau plus profond d'existence que Jaspers appelle ''Existenz'', une forme d'auto-conscience critique et de transcendance<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 55-65</ref>. Pour Jaspers, c'est justement dans l'expérience authentique des situations limites que l'individu accède à ce qu'il appelle la « transcendance ». Cette transcendance ne signifie point un dépassement métaphysique vers un autre monde, mais plutôt une conscience aiguë de la « Totalité » englobante au sein de laquelle mon existence particulière trouve son sens relatif<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 65-80</ref>. === 4.6 Simone de Beauvoir : mort, liberté et éthique de l'ambiguïté === Simone de Beauvoir offre une perspective existentialiste qui intègre les questions de genre, de liberté concrète et de responsabilité éthique. Dans son ouvrage ''Éthique de l'ambiguïté'' (1947) et son monumental ''Le Deuxième Sexe'' (1949), Beauvoir affirme que la liberté est la valeur normative première de toute éthique existentielle<ref>Simone de Beauvoir, ''Éthique de l'ambiguïté'', Éditions Gallimard, 1947, p. 9-30</ref>. Comment la mort s'inscrit-elle dans cette éthique de la liberté ? Beauvoir soutient que la mort, loin de constituer une structure ontologique donnant sens à l'existence comme chez Heidegger, représente plutôt une limite arbitraire imposée du dehors. Mais cette limite n'anéantit pas la liberté ; elle la redéfinit. La liberté consiste à créer du sens, à poursuivre des projets, à s'engager dans la construction d'un monde plus juste, tout en sachant que cette liberté reste finie, que cette création de sens sera finalement interrompue<ref>Beauvoir, ''Éthique de l'ambiguïté'', p. 40-60</ref>. Ce qui distingue Beauvoir des autres existentialistes, c'est son insistance sur le fait que cette liberté ne reste pas abstraite. Elle se fait concrète, incarnée, et inégalement distribuée parmi les êtres humains. Les femmes, les opprimés, les marginalisés se voient souvent refuser l'accès aux formes d'existence que les existentialistes masculins envisagent comme naturelles ou universelles<ref>Simone de Beauvoir, ''Le Deuxième Sexe'', tome I, Éditions Gallimard, 1949, p. 13-32</ref>. Beauvoir affirme que « l'on ne naît pas femme, on le devient », formule qui exprime en microcosme sa pensée : aucune essence féminine fixe n'existe, aucune nature donnée une fois pour toutes. Au lieu de cela, la féminité est une condition historiquement construite et socialement imposée. Mais puisque cette condition ne s'inscrit pas dans la nature, elle peut être transformée par une action libre et consciente<ref>Beauvoir, ''Le Deuxième Sexe'', tome I, p. 13-18</ref>. Quant à la mort, Beauvoir en reconnaît le caractère terrible et absurde. Mais elle refuse de permettre que cette absurdité justifie l'oppression, la domination ou le refus de reconnaître la liberté d'autrui. Au contraire, c'est précisément en raison de l'inévitabilité de la mort que nous devons créer de la solidarité, de la justice, de la fraternité pendant que nous vivons. La mort impose une urgence éthique à nos actions<ref>Beauvoir, ''Éthique de l'ambiguïté'', p. 115-145</ref>. === 4.7 Les thèmes transversaux de l'existentialisme face à la mort === Malgré les différences substantielles entre ces penseurs, certains thèmes existentialistes récurrents concernant la mort et la finitude émergent avec netteté : ''L'authenticité contre l'inauthenticité :'' Plusieurs philosophies de l'existence reviennent à une opposition entre une vie assumée et une vie fuyante, même si elles ne donnent pas toutes le même sens à l'authenticité. L'inauthenticité consiste généralement à fuir la responsabilité, à se réfugier dans les rôles sociaux prédéfinis, à nier la nécessité de créer sa propre essence. La mort, par sa certitude et son caractère inévitable, pose à chaque individu la question de savoir s'il vivra authentiquement ou s'il continuera de fuir<ref>Heidegger, ''Sein und Zeit'', sections 38-41, p. 214-225</ref>. ''L'angoisse existentielle :'' L'angoisse ne constitue point une pathologie à traiter mais une révélation existentielle salutaire. Elle exprime la conscience de la liberté sans entraves, la réalité de la contingence humaine, et la responsabilité absolue face à l'absence de fondement stable. C'est précisément dans l'expérience de l'angoisse que l'existant accède à la vérité de sa condition<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 61-70</ref>. ''La singularité et l'irremplaçabilité :'' Ma mort reste pleinement mienne. Elle ne peut être confiée à personne d'autre, elle ne peut être vécue qu'en première personne. Cette singularité absolue me constitue en tant qu'individu unique et irremplaçable. Elle fonde une forme d'égalité originelle : devant la mort, tous les êtres humains se trouvent dans une situation métaphysiquement identique<ref>Camus, ''Le Mythe de Sisyphe'', p. 23-25</ref>. ''L'absence de fondement justificatif :'' L'univers ne fournit aucune justification à l'existence. Il n'existe pas de « pourquoi » cosmique qui expliquerait notre présence dans le monde. Cette absence de fondement définit précisément la condition absurde, et c'est cette absence qui confère une responsabilité absolue : si rien ne justifie notre existence de l'extérieur, nous devons créer cette justification de l'intérieur, par nos actions et nos choix<ref>Sartre, ''L'Être et le Néant'', p. 76-90</ref>. En conclusion, l'approche existentialiste de la mort refuse de la traiter comme un simple problème technique ou biologique. Elle la conçoit plutôt comme le moment de révélation par excellence où la vérité de l'existence humaine, sa liberté, sa responsabilité, son absurdité, sa dignité, se manifeste avec la plus grande clarté. Loin de constituer une réflexion morbide, la philosophie existentialiste de la mort invite à vivre plus authentiquement, plus lucidement, plus librement. == V. Dimensions éthiques et axiologiques == === 5.1 L'autonomie et le « droit de mourir » === La question du rapport entre autonomie et mort soulève des enjeux éthiques majeurs. La notion d'autonomie, entendue comme la capacité et le droit de chaque individu à orienter sa propre existence en accord avec ses valeurs, s'est imposée au cœur de la bioéthique contemporaine, notamment dans les débats relatifs à l'euthanasie et à l'assistance médicale à mourir<ref>Tom L. Beauchamp et James F. Childress, ''Principles of Biomedical Ethics'', Oxford University Press, 7e éd., 2013, p. 101-150</ref>. Les partisans d'un « droit de mourir » soutiennent que le respect de l'autonomie implique de reconnaître à chacun la faculté de décider des conditions de sa fin de vie, notamment le refus de traitements prolongeant artificiellement l'existence ou, là où la loi l'autorise, la demande d'une assistance médicale pour hâter la mort<ref>Ronald Dworkin, ''Life's Dominion'', Knopf, 1993, p. 190-237</ref>. Cette position repose sur un principe fondamental : il revient à chaque personne de déterminer le sens et la valeur de sa propre vie. Il serait dès lors contraire au respect d'imposer une manière de mourir qui contredit les convictions et les préférences de cette personne<ref>Beauchamp et Childress, ''Principles of Biomedical Ethics'', p. 135-140</ref>. Cette invocation de l'autonomie soulève néanmoins plusieurs difficultés. D'abord, le caractère réellement autonome de la demande d'aide à mourir reste problématique : lorsqu'une personne souffre intensément, déprimée, se vit comme un fardeau pour ses proches, peut-on raisonnablement tenir sa demande pour entièrement libre de pressions, explicites ou implicites<ref>Alexandra Mullock et Jonathan Lewis, « Assisted Dying, Vulnerability, and the Potential Value of Prospective Legal Authorization », ''Medical Law Review'', vol. 33, n° 2, 2025, article fwaf014</ref> ? Ensuite, même à supposer la demande authentiquement autonome, reste à déterminer si l'autonomie individuelle suffit à justifier l'intervention d'un tiers, le médecin, pour provoquer la mort, ou si d'autres considérations (protection des plus vulnérables, rôle de la médecine, répercussions sociales) doivent aussi entrer en compte<ref>Helga Kuhse et Peter Singer (dir.), ''A Companion to Bioethics'', Blackwell, 2009, p. 314-325</ref>. Plusieurs auteurs dénoncent un « autonomisme » excessif dans la [[Dictionnaire de philosophie/Bioéthique|bioéthique]] contemporaine, c'est-à-dire une surestimation du rôle que devrait jouer l'autonomie dans les décisions de fin de vie. Ils observent que l'autonomie n'existe jamais en isolation : elle s'exerce toujours prise dans des réseaux d'inégalités, de vulnérabilités et de rapports de pouvoir<ref>Mullock, « Assisted Dying, Vulnerability… », p. 12-18</ref>. Lorsque des personnes pauvres, sans domicile fixe, gravement handicapées ou incarcérées demandent à mourir, il devient nécessaire de se demander si cette demande reflète un choix authentiquement libre, ou si elle résulte de conditions sociales si désastreuses que la société aurait pu et dû améliorer<ref>Rebecca Dresser et Peter Singer, « Euthanasia and the Question of Justice », dans ''Choices at the End of Life'', 2002, p. 82-104</ref>. === 5.2 Dignité, qualité de vie et valeur de la vie === Le concept de « mort digne » revient constamment dans les débats bioéthiques sur l'euthanasie et l'assistance médicale à mourir. Ceux qui défendent ces pratiques soutiennent qu'il importe de permettre à chacun de mourir selon sa propre conception de la dignité, que refuser cette possibilité constituerait une atteinte à la valeur fondamentale de la personne<ref>Michael Tooley, Celia Wolf-Devine et James W. Diamond (dir.), ''Physician-Assisted Suicide: Expanding the Debate'', Routledge, 1997, p. 201-232</ref>. Mais que signifie exactement « mourir avec dignité » ? S'agit-il de conserver la maîtrise de ses décisions et de son corps jusque dans la mort ? De ne pas endurer une souffrance extrême ? Ou bien d'une valeur inconditionnelle, inhérente au seul fait d'être une personne, indépendamment de l'état physique ou mental<ref>Stephen Richards, « The Morality of Assisted Dying », ''The Journal of Medicine and Philosophy'', vol. 50, n° 4, 2025, p. 262-284</ref> ? Une longue tradition philosophique et juridique défend cette dernière conception : la dignité humaine serait intrinsèque, inaliénable, et ne pourrait donc ni se perdre ni se gagner. Une existence marquée par la douleur, la dépendance physique ou la démence ne serait pas, en elle-même, « indigne », car la dignité ne se mesure ni à la performance physique, ni au fonctionnement autonome, ni à la lucidité mentale<ref>Lydia Dugdale, ''The Lost Art of Dying'', Harper Wave, 2020, p. 145-180</ref>. Les partisans du droit à l'assistance au mourir rétorquent que cette approche, bien qu'elle protège contre les jugements méprisants sur la valeur des vies fragiles, risque de devenir insensible à la souffrance concrètement vécue. Ils observent aussi qu'une distinction entre dignité ontologique (égale pour tous) et dignité existentielle (comment se déploient les derniers moments d'une vie) s'impose : la manière dont s'écoulent les derniers instants influe sur le sens que l'existence entière revêt, rétrospectivement, pour la personne mourante et pour les proches<ref>Ronald Dworkin, ''Life's Dominion'', p. 187-240</ref>. === 5.3 Justice, équité et accès aux soins de fin de vie === Une dimension moins médiatisée mais politiquement névralgique concerne la justice et l'équité dans l'accès aux soins de fin de vie. Tandis que les débats théoriques portent volontiers sur l'euthanasie en contextes où une offre médicale existe déjà, la réalité révèle un scandale plus fondamental : l'inégalité d'accès aux soins palliatifs, au soulagement de la douleur et à l'accompagnement des mourants<ref>Marissa T. French et alii, « Exploring Socioeconomic Inequities in Access to Palliative and End-of-Life Care in the UK », ''Palliative Medicine'', vol. 35, n° 10, 2021, p. 1843-1856</ref>. Les personnes sans domicile, les détenus, les migrants sans statut légal et même certains patients souffrant de troubles psychiatriques graves restent largement écartés de dispositifs permettant un mourir apaisé, entouré, médicalement et humainement accompagné<ref>Kelli Stajduhar et Merryn Gott, « Closing the Health Equity Gap in Palliative Care: The Time for Action Is Now », ''Palliative Medicine'', vol. 37, n° 4, 2023, p. 424-425</ref>. L'accès à un « bon mourir » reste un privilège socioéconomique. Il en résulte une dissonance morale frappante : promouvoir un « droit à mourir » là où n'est pas garanti un droit effectif à bien vivre jusqu'au bout. Tant que l'accès universel à des soins palliatifs de qualité, à la prise en charge de la douleur et au soutien psychosocial n'est pas assuré, existe le risque que l'assistance médicale à mourir ne devienne une réponse aux carences sociales plutôt que l'expression d'un choix existentiel mûrement réfléchi<ref>Leon R. Kass, « 'I Will Give No Deadly Drug': Why Doctors Must Not Kill », dans ''The Case Against Physician-Assisted Suicide'', 2002, p. 17-39</ref>. === 5.4 Vulnérabilité, dépendance et éthique du care === Une éthique contemporaine de la vulnérabilité et du care rappelle que la dépendance ne constitue pas une anomalie réservée à certains groupes fragiles, mais une condition humaine universelle. Tout être humain se trouve exposé à la maladie, à l'accident, à la précarité du corps et, finalement, à la mort<ref>Martha Albertson Fineman, ''The Autonomy Myth: A Theory of Dependency'', The New Press, 2004, p. 1-30</ref>. L'éthique du care propose de déplacer le centre de gravité : au lieu de prendre l'individu abstraitement autonome comme modèle, elle met au premier plan les relations concrètes de soin, l'interdépendance et la responsabilité mutuelle. Personne ne meurt « seul » au sens existentiel : chaque mort affecte un tissu humain de proches, interpelle une communauté, suppose un ensemble de gestes, de présences, de paroles<ref>Nel Noddings, ''Caring: A Feminine Approach to Ethics and Moral Education'', University of California Press, 2e éd., 2003, p. 142-175</ref>. Dans cette perspective, les questions de fin de vie ne sauraient se réduire à un conflit binaire entre le « droit individuel » et les « interdits collectifs ». Il convient de tenir compte des responsabilités relationnelles, des liens de soin qu'il faut entretenir ou créer, et de ce que signifie pour une communauté d'accueillir et de soutenir ses mourants<ref>Siv Maj Jämterud, « Acknowledging Vulnerability in Ethics of Palliative Care », ''Nursing Ethics'', vol. 29, n° 2, 2022, p. 335-347</ref>. La vulnérabilité n'est pas un simple motif de protection paternaliste : elle constitue le point de départ d'une éthique de l'attention mutuelle. === 5.5 Finitude, signification de la vie et axiologie de la mort === Du point de vue axiologique, la mort ne se réduit pas à un « problème » moral qu'il faudrait encadrer. Elle joue un rôle de premier plan dans la valeur que peut prendre une vie. Une part importante de la philosophie contemporaine soutient que la finitude n'appauvrit pas nécessairement la signification de l'existence ; elle en constitue plutôt une condition<ref>Liudmila Baeva, ''Existential Axiology: A New Philosophical Paradigm'', Routledge, 2013, p. 1-40</ref>. Thaddeus Metz a défendu l'idée qu'une vie sans terme imaginable, infinie et interminable, perdrait une bonne part de ce qui rend l'existence précieuse : l'urgence des choix, la nécessité de hiérarchiser les projets, la conscience que tout ne pourra pas être accompli<ref>Thaddeus Metz, « The Meaning of Life », ''Stanford Encyclopedia of Philosophy'', 2021, sections 3-4</ref>. C'est précisément la finitude qui confère à l'amitié, l'amour, le travail créateur ou la quête de justice leur poids particulier. La reconnaissance lucide de la mortalité invite à une réorientation des priorités morales. Au lieu de rêver d'abolir la mort, ou de s'absorber exclusivement dans la maîtrise technique de ses modalités, il s'agit de se demander ce qui mérite d'être accompli dans le temps qui nous échoit : quels liens tisser, quelles œuvres entreprendre, quelle empreinte laisser<ref>Jonathan Noonan, « Mortality, Finitude, and Meaningful Lives », ''Journal of Philosophy of Life'', vol. 3, n° 1, 2013, p. 5-41</ref>. === 5.6 Responsabilité collective et conditions sociales du mourir === Enfin, la mort n'est jamais seulement affaire de choix privés. Elle reste inséparable de structures institutionnelles, de politiques publiques et d'allocations budgétaires. La manière dont on meurt dans une société dépend de systèmes de santé, de régimes d'assurance, de normes professionnelles, mais aussi de politiques de logement, de lutte contre la pauvreté, d'accompagnement du grand âge<ref>Courtney S. Campbell, « Mortal Responsibilities: Bioethics and Medical-Assisted Dying », ''Yale Journal of Biology and Medicine'', vol. 92, n° 4, 2019, p. 733-739</ref>. Il est révélateur que les pays ayant légalisé les formes les plus étendues d'assistance médicale à mourir (Pays-Bas, Belgique, Canada, certaines provinces australiennes) disposent tous d'un accès universel à des soins de santé de base<ref>Campbell, « Mortal Responsibilities… », p. 735-736</ref>. À l'inverse, il apparaît moralement troublant qu'une société qui ne garantit pas à tous un accès minimal aux soins puisse se prévaloir d'avoir légalisé la mort médicalement provoquée comme une avancée bioéthique majeure. Une éthique responsable de la mort exige que l'on dépasse la seule question : « Qu'ai-je le droit de décider pour moi-même ? ». Elle impose de se demander aussi : « Quelles conditions de vie créons-nous pour les vivants et pour les mourants ? » ; « Quelles vies estimons-nous suffisamment dignes pour être soutenues, accompagnées, soignées jusqu'au bout » ? Ces interrogations collectives ne peuvent rester sans réponse<ref>Stajduhar et alii, « Equity-Focused Palliative and End-of-Life Care… », p. 125-138</ref>. Dans cette perspective, l'enjeu ultime n'est pas d'opposer abstraitement un « droit de mourir » à un « devoir de vivre », mais de faire en sorte que chacun puisse vivre et mourir dans un cadre où l'assistance à la mort ne remplace jamais l'obligation collective de soulager la misère, la solitude et l'abandon. == VI. La mort et le sens de la vie == === 6.1 L'immortalité comme malédiction : la théorie de l'ennui infini === L'une des questions les plus intrigantes que pose la philosophie de la mort concerne l'hypothèse contrefactuelle (contraire aux faits) suivante : serait-il bon de vivre éternellement ? Au premier abord, cette question semble relever du domaine des jeux de l'esprit, mais elle révèle en réalité des enjeux profonds concernant la relation entre finitude et sens. Bernard Williams, philosophe analytique contemporain, a défendu une position controversée : contrairement à ce que l'on pourrait attendre, vivre éternellement serait en réalité indésirable<ref>Bernard Williams, « The Makropulos Case: Reflections on the Tedium of Immortality » (1973), dans ''Problems of the Self'', Cambridge University Press, 1973, p. 82-100</ref>. Williams prend appui sur la pièce de théâtre de Karel Čapek ''La Vie de Madame Macropulos'', où l'héroïne, qui a vécu trois cents ans grâce à un élixir, découvre que la vie immortelle devient irrémédiablement ennuyeuse. L'argument de Williams procède ainsi : d'une part, ce qui donne sens à nos projets et à nos engagements, c'est notamment leur caractère temporellement limité et urgent ; d'autre part, une vie infinie serait nécessairement monotone, car il n'y aurait jamais vraiment de nouvelles expériences (après un temps suffisamment long, tout s'épuiserait et se répéterait), ou bien nous devrions constamment avoir oublié nos expériences passées pour préserver l'impression de nouveauté (ce qui reviendrait à une discontinuité de la conscience et de l'identité)<ref>Bernard Williams, « The Makropulos Case », p. 88-99</ref>. Simone de Beauvoir avait déjà exploré cette possibilité dans ses analyses de l'ennui, affirmant que la mort, paradoxalement, peut être un bienfait en tant qu'elle introduit une limite nécessaire à l'existence<ref>Simone de Beauvoir, ''Tout compte fait'', Gallimard, 1972, p. 308-315</ref>. Cette position remet en question l'idée commune selon laquelle la mort serait un mal absolu qu'il faudrait à tout prix surmonter. Cependant, cette théorie a été vigoureusement contestée. Certains philosophes soutiennent que Williams confond l'immortalité corporelle avec une immortalité qui permettrait l'oubli régulier, ou que sa conception de l'ennui est trop restrictive<ref>Donald Bruckner, « Against the Tedium of Immortality », dans ''Journal of Philosophy'', vol. 109, n° 11, 2012, p. 628-645</ref>. D'autres objectent que nous ne pouvons tout simplement pas savoir ce que serait une vie infinie et que par conséquent cet argument reste hautement spéculatif. === 6.2 La mort comme condition de signification === Une autre approche insiste sur le lien constitutif entre finitude et signification. Ce qui nous motive, ce qui nous donne direction, c'est précisément le fait que le temps nous manque, que nos jours sont comptés. Heidegger lui-même en fait un élément central de sa pensée : c'est la conscience de ma mortalité qui me permet de ''vraiment'' décider, de ''vraiment'' m'engager dans un projet, plutôt que de vivre passivement au jour le jour<ref>Heidegger, ''Sein und Zeit'', § 67-72</ref>. De plus, la mort de l'autre donne sens à notre solidarité, à notre compassion. Si personne ne mourait, la distinction entre vraie bienveillance et simple échange utilitaire s'estomperait. Nos engagements les plus profonds envers les autres, ceux qui nous font accepter du sacrifice, du deuil, tirent leur sens de cette conscience partagée de la mortalité. Cette perspective a une résonance particulière dans les traditions existentialistes et notamment dans la pensée de Paul Ricœur, qui voit dans la finitude le fondement même de ce qui rend la vie digne d'être vécue : c'est une vie finie qui me demande de bien la vivre<ref>Paul Ricœur, ''Soi-même comme un autre'', Seuil, 1990, p. 453-476</ref>. Sans cette limitation, l'existence serait peut-être éternelle, mais elle risquerait de perdre cette tension, cette urgence qui la rend signifiante. === 6.3 Thomas Nagel et l'absurdité de la mort === [[Dictionnaire de philosophie/Thomas Nagel|Thomas Nagel]] a proposé une analyse novatrice en situant la mort parmi les sources majeures de ce qu'il appelle l'absurdité de l'existence humaine. L'absurdité naît, selon Nagel, non de la mortalité elle-même, mais du contraste entre l'importance subjective que nous conférons à nos vies et la relative insignifiance de ces vies au sein de l'univers cosmique<ref>Thomas Nagel, « The Absurd » (1971), dans ''Mortal Questions'', p. 11-32</ref>. La mort amplifie cette absurdité en ceci que la mort apparaît à la fois comme certaine et comme inimaginable pour le sujet vivant. Nous savons que nous mourrons, mais cette certitude reste abstraite ; nous ne pouvons vraiment imaginer notre non-existence. De ce contraste surgit une forme d'absurdité existentielle qui n'est pas directement accessible à la résolution rationnelle<ref>Nagel, « The Absurd », p. 27-30</ref>. Contrairement à Camus, qui voyait dans cette absurdité une occasion pour la révolte créative, Nagel y voit plutôt une condition inéluctable de la conscience réflexive : du moment que nous pouvons nous voir ''de l'extérieur'', que nous pouvons prendre du recul sur nos propres préoccupations, nous sommes confrontés à cette absurdité<ref>Nagel, « The Absurd », p. 31-32</ref>. La mort, dans ce contexte, est l'un des symptômes majeurs de notre condition d'êtres à la fois immergés dans la vie et capables de nous en distancier. == VII. Phénoménologie du mourir == === 7.1 Le mourir comme phénomène vécu === Bien que la mort elle-même, stricto sensu, échappe à toute expérience possible (puisque l'expérience présuppose la conscience et la mort sa cessation), le mourir, le processus qui mène à la mort, constitue une réalité vécue qui peut être objet de réflexion phénoménologique. La phénoménologie du mourir, dans la tradition heideggérienne et post-heideggérienne, cherche à décrire comment la proximité de la mort se manifeste dans l'expérience vécue. La peur de la mort, l'angoisse devant la finitude, l'acceptation progressive ou la dénégation, voilà autant de phénomènes psychologiques et ontologiques que la mort entraîne<ref>Heidegger, ''Sein und Zeit'', § 40</ref>. Jan Patočka, philosophe tchèque influencé par Husserl et Heidegger, a développé une approche phénoménologique particulière où le mourir apparaît comme ce qui révèle la structure fondamentale de la vie humaine. Pour Patočka, nous vivons constamment ''dans la proximité de la mort'', et c'est cette proximité qui confère à la vie son caractère de ''drame'' inéludable<ref>Jan Patočka, ''Platon et l'Europe'', Verdier, 1983, p. 157-198</ref>. Michel Henry a proposé une approche critique des phénoménologies heideggériennes de la mort, affirmant que l'accent mis sur l'être-vers-la-mort risque de passer sous silence l'expérience la plus profonde de la vie : la présence affective originaire (l'affectivité comme ''pathos'' primordial)<ref>Michel Henry, ''C'est moi la vérité. Pour une philosophie du christianisme'', Seuil, 1996, p. 129-145</ref>. De ce point de vue, toute tentative d'intelliger la mort par la seule réflexion existentiale reste insuffisante. === 7.2 L'angoisse face à la mort === L'angoisse (''Angst'' en allemand) constitue un thème central de la pensée existentialiste, notamment chez Kierkegaard, Heidegger et Sartre. L'angoisse face à la mort ne doit pas être confondue avec la peur de la mort, bien que les deux soient liées. La peur se rapporte à quelque chose de particulier et déterminé ; l'angoisse, en revanche, reste indéterminée, sans objet précis<ref>Søren Kierkegaard, ''Le Concept d'Angoisse'' (''Begrebet Angest'', 1844), traduction de Gilles Hanot, PUF, 2007, p. 53-87</ref>. Chez Heidegger, l'angoisse révèle l'essence de la mort comme possibilité absolue et singulière du Dasein. Dans l'angoisse, nous sommes face à face avec l'absurdité fondamentale de l'existence : que je sois plutôt que rien, c'est quelque chose qui ne se justifie pas et qui, un jour, s'arrêtera<ref>Heidegger, ''Sein und Zeit'', § 40-42</ref>. Cette approche a des implications profondes pour la psychologie et la psychiatrie. Si l'angoisse face à la mort est constitutive de la condition humaine et non une pathologie, comment faut-il la traiter ? La psychanalyse a proposé que refouler cette angoisse (l'inconscient humain dénie systématiquement la réalité de la mort) peut mener à des symptômes névrotiques. Certains thérapeutes, influencés par les existentialistes, affirment que l'acceptation progressive de la mortalité représente un élément clé de la maturation psychologique<ref>Irvin Yalom, ''Staring at the Sun: Overcoming the Terror of Death'', Jossey-Bass, 2008, p. 47-89</ref>. == VIII. La mort dans les traditions religieuses et spirituelles == === 8.1 L'au-delà et l'immortalité de l'âme === Historiquement, les traditions religieuses ont majoritairement affirmé que la mort n'est pas la fin absolue de la personne, mais une transition vers une autre forme d'existence (l'au-delà, le paradis, la réincarnation, le nirvana, etc.). Ces conceptions ne relèvent pas directement de la philosophie, mais elles constituent un contexte culturel et historique inévitable pour comprendre la réflexion philosophique occidentale sur la mort<ref>Mircea Eliade, ''Le Chamanisme et les Techniques archaïques de l'extase'', Payot, 1951, p. 401-437</ref>. Ces conceptions, qu'on regroupe trop vite, reposent en réalité sur des métaphysiques distinctes qu'il importe de séparer. La première est l'immortalité de l'âme : une partie immatérielle de la personne, son âme, survivrait par nature à la dissolution du corps. C'est la thèse du ''Phédon'', reprise par une longue tradition jusqu'à [[Dictionnaire de philosophie/René Descartes|Descartes]], pour qui l'âme est une substance pensante réellement distincte du corps étendu. L'identité du défunt y est portée par l'âme seule. La seconde, propre aux traditions juive, chrétienne et musulmane, est la résurrection des corps : ce n'est pas une âme spontanément immortelle qui assure la survie, mais un acte divin qui recrée la personne entière, corps compris, à la fin des temps. La nuance est de taille. Dans le premier cas, quelque chose en nous échappe par nature à la mort ; dans le second, la mort est bien réelle et complète, et seule une intervention extérieure peut la défaire. Saint Paul, qui parle d'un « corps spirituel » rendu à la vie, n'affirme pas l'immortalité de l'âme à la manière grecque, mais le relèvement de tout l'homme. Les traditions venues de l'Inde déplacent encore les termes du problème. La doctrine de la réincarnation, ou métempsycose, suppose un soi permanent, l{{'}}''ātman'', qui transmigre de corps en corps au fil des renaissances ; le but recherché, la délivrance (''mokṣa''), est la sortie hors de ce cycle (''saṃsāra''). Le bouddhisme, qui partage le cadre du cycle des renaissances, en retranche pourtant la pièce maîtresse : il nie l'existence d'un soi substantiel et permanent, c'est la thèse de l{{'}}''anātman'', le non-soi. Comment, dès lors, parler de renaissance sans personne qui renaisse ? La réponse bouddhique est subtile : ce qui se perpétue n'est pas un sujet identique, mais un flux causal d'états conditionnés, comparable à une flamme qui en allume une autre sans qu'aucune substance ne passe de l'une à l'autre. Le ''nirvāṇa'' n'est pas un paradis, mais l'extinction du désir et l'arrêt du cycle lui-même. On remarquera que cette idée d'une continuité sans sujet permanent rejoint, par un tout autre chemin, les analyses réductionnistes de l'identité personnelle examinées plus haut (section 3.1.2) ; Parfit lui-même reconnaissait la parenté de sa position avec la pensée bouddhique. Il s'agit toutefois d'une analogie, non d'une équivalence doctrinale : Parfit raisonne dans un cadre analytique contemporain, là où le bouddhisme inscrit le non-soi dans une visée de délivrance, éthique et méditative, qui déborde de loin la seule question de l'identité personnelle. La question philosophique spécifique que ces traditions soulèvent concerne la possibilité conceptuelle d'une immortalité personnelle. Si l'immortalité consiste en une simple survie de l'âme (entendue comme substance immatérielle), comment l'âme peut-elle persister sans rapport au corps ? Quel serait le contenu de cette expérience immortelle ? Ces questions ont occupé les plus grands penseurs, de Platon (notamment dans le ''Phédon'') à Descartes en passant par Leibniz et Kant<ref>Platon, ''Phédon'', traduction de Monique Dixsaut, GF Flammarion, 1991, p. 88-145</ref>. Kant refuse, dans la ''Critique de la raison pure'', les preuves théoriques de l'immortalité de l'âme ; dans la ''Critique de la raison pratique'', il lui accorde le statut de postulat de la raison pratique : nous ne pouvons progresser moralement à l'infini dans une vie finie, et il faut donc postuler une survie indéfinie de l'âme pour rendre intelligible la possibilité du progrès moral<ref>Immanuel Kant, ''Critique de la Raison Pratique'' (1788), traduction de François Picavet, PUF, 1943, p. 154-162</ref>. === 8.2 La mort et le sacré === Bien au-delà des doctrines spécifiques d'immortalité, la mort a toujours occupé une place privilégiée dans l'expérience religieuse et spirituelle. Des rites funéraires à travers le monde aux pratiques contemplatives des traditions mystiques, la mort demeure au cœur du rapport humain au sacré. Depuis les travaux du sociologue et anthropologue Émile Durkheim, la mort a été reconnue comme un moment privilégié de manifestation du sacré. Les rituels funéraires, bien qu'ils varient fortement selon les cultures, partagent souvent une fonction commune : marqueur de transition, affirmation de la continuité du groupe social face à la rupture qu'introduit le décès d'un de ses membres<ref>Émile Durkheim, ''Les Formes élémentaires de la vie religieuse'' (1912), traduction de Corinne Enaudeau, Seuil, 2003, p. 325-381</ref>. Certaines traditions spirituelles, notamment dans le bouddhisme tibétain (notamment le ''Bardo Thödol'' ou ''Livre des Morts Tibétain''), conçoivent le mourir et le moment qui suit comme une opportunité transformatrice majeure. La mort n'est pas considérée comme une fin, mais comme un passage initiatique potentiel offrant la possibilité d'une libération ou d'une meilleure réincarnation<ref>Jetsun Kalu Rinpoche, ''Le Chemin de la Lumière'', Claire Lumière, 1987</ref>. La philosophie contemporaine peut étudier ces phénomènes sans adopter les croyances qui les accompagnent, tout en reconnaissant que le rapport de l'humanité à la mort reste indissociable de la dimension spirituelle et rituelle de l'existence. Ignorer cet aspect serait réduire la mort à une simple question biologique, ce qui passerait sous silence une partie essentielle du phénomène<ref>Paul Tillich, ''Le Courage d'exister'', Centurion, 1967, p. 156-198</ref>. == IX. Questions métaphysiques et logiques == === 9.1 La mort et la causalité inversée : le problème du manque === Un problème logique subtil s'impose à la théorie déprivationniste : comment quelque chose qui n'existe pas (une vie non-vécue) peut-il être causal dans le monde ? Si je suis privé de certains biens parce que je suis mort, comment la mort (un événement qui produit mon inexistence) peut-elle être la cause d'une privation qui m'affecte ? Cette question de la ''causalité inversée'' a occupé les métaphysiciens de la mort contemporains<ref>George Pitcher, « The Misfortune of the Dead », dans ''The American Philosophical Quarterly'', vol. 21, n° 3, 1984, p. 183-188</ref>. Plusieurs solutions ont été proposées. Fred Feldman, par exemple, soutient que nous pouvons concevoir une relation de ''privation causale'' où la mort cause une privation sans que la mort elle-même agisse comme cause efficiente au sens traditionnel<ref>Fred Feldman, ''Confrontations with the Reaper'', Oxford University Press, 1986, chap. 1</ref>. D'autres, comme James Stacey Taylor, explorent une conception contrefactuelle : la mort m'est nuisible en ceci qu'elle rend faux un contrefactuel (s'il y avait continuité de vie, j'aurais expérimenté certains biens)<ref>James Stacey Taylor, ''Death, Positivism and Meaning'', Routledge, 2007, p. 42-71</ref>. === 9.2 La mort et le réalisme métaphysique === La mort soulève aussi des questions métaphysiques concernant le statut des entités qui cessent d'exister. Un objet matériel qui se désagrège au fil du temps semble persister en tant qu'objet jusqu'à un certain degré de désagrégation. Mais à quel point devient-il plus correct de dire que l'objet n'existe plus ? De la même façon, une personne meurt progressivement : ses fonctions cognitives s'altèrent, puis ses fonctions biologiques s'arrêtent. Y a-t-il un moment précis où la personne cesse d'être, ou s'agit-il plutôt d'un processus continu<ref>Dean Zimmerman, « The A-Theory of Time and the B-Theory », dans ''Stanford Encyclopedia of Philosophy'', 2011</ref> ? Ces questions se sont intensifiées avec les progrès biomédicaux contemporains. Les notions de mort cérébrale, de mort clinique et de possibilités de réanimation ont troublé les frontières autrefois claires entre vie et mort. Philosophiquement, ces développements nous forcent à reconnaître que la mort n'est pas une simple dichotomie (on vit ou on meurt), mais un spectre complexe<ref>Robert D. Truog, « Defining Death, Again », ''Hastings Center Report'', vol. 35, n° 6, 2005, p. 6</ref>. == X. Perspectives bioéthiques contemporaines == === 10.1 Mort clinique, mort cérébrale et statut du mourant === Les développements des technologies de maintien artificiel de la vie ont nettement modifié le paysage éthique et philosophique de la mort. Avant l'invention des respirateurs artificiels et autres dispositifs de soutien vital, la mort était un processus relativement rapide et, dans la plupart des cas, reconnaissable. Aujourd'hui, il est possible de maintenir certaines fonctions biologiques longtemps après que les fonctions cognitives ou toutes les fonctions biologiques aient cessé<ref>Robert D. Truog et James L. Bernat, « Ethical Guidelines for the Diagnosis and Management of Brain Death in Adults and Children », ''Critical Care Medicine'', vol. 38, n° 9, 2010, p. 1962-1978</ref>. La question de savoir qui est ''vraiment'' mort a acquis une nouvelle urgence pratique. La notion de mort cérébrale, adoptée depuis les années 1960, redéfinit la mort non plus comme arrêt du cœur et de la respiration, mais comme arrêt irréversible de toutes les fonctions du cerveau (ou du tronc cérébral, selon les juridictions)<ref>David M. Greer, Matthew P. Kirschen, Ariane Lewis et al., « Pediatric and Adult Brain Death/Death by Neurologic Criteria Consensus Practice Guideline », ''Neurology'', vol. 101, n° 24, 2023, p. 1112-1132</ref>. Cette redéfinition, bien que médicalement et scientifiquement justifiée, a des implications philosophiques majeures : elle privilégie le cerveau comme siège de l'identité personnelle, ce qui représente un choix métaphysique au-delà de la simple constatation empirique. Cette redéfinition rend indispensable de distinguer plusieurs états cliniques que le langage courant confond aisément. Le coma désigne une abolition de la vigilance et de la conscience, souvent transitoire, dont le patient peut émerger. L'état végétatif, ou état d'éveil non répondant, associe un retour de l'éveil, avec cycles veille-sommeil et ouverture des yeux, à l'absence de tout signe de conscience de soi ou de l'environnement. L'état de conscience minimale se caractérise par des manifestations de conscience fluctuantes mais reproductibles. Le syndrome d'enfermement (''locked-in'') laisse au contraire la conscience intacte alors que la motricité volontaire est presque entièrement abolie, le sujet ne pouvant souvent communiquer que par les mouvements oculaires<ref>Joseph T. Giacino, Douglas I. Katz, Nicholas D. Schiff et al., « Practice Guideline Update Recommendations Summary: Disorders of Consciousness », ''Neurology'', vol. 91, n° 10, 2018, p. 450-460</ref>. La mort encéphalique se sépare de tous ces états : elle suppose l'arrêt irréversible de l'ensemble des fonctions du cerveau, tronc cérébral compris, et n'autorise par définition ni éveil, ni conscience, ni respiration spontanée. Confondre ces situations, en particulier l'état végétatif et la mort encéphalique, expose à des erreurs cliniques et éthiques lourdes, qu'il s'agisse d'interrompre à tort des soins ou de les prolonger sans terme. === 10.2 L'allongement de la vie et l'anti-vieillissement === La bioéthique contemporaine est occupée par un dilemme : d'un côté, la mort demeure inévitable et, en un sens, souhaitable (sans elle, l'existence deviendrait infinie, monotone) ; de l'autre, les capacités technologiques contemporaines permettent d'envisager des vies bien plus longues, voire, dans certains scénarios futuristes, potentiellement infinies. Aubrey de Grey et d'autres chercheurs en biogérontologie soutiennent que le vieillissement est une maladie et qu'il est en principe possible de développer des thérapies susceptibles d'arrêter ou d'inverser les processus biologiques du vieillissement<ref>Aubrey de Grey et Michael Rae, ''Ending Aging'', St. Martin's Press, 2007</ref>. Cette perspective soulève immédiatement la question : si l'on pouvait techniquement éliminer le vieillissement, devrait-on le faire ? La réponse dépend largement de la manière dont on évalue les enjeux philosophiques et éthiques que nous avons discutés plus haut (la théorie de l'ennui infini, le rôle de la mort dans la signification de la vie, etc.)<ref>Nick Bostrom, « The Immortality Question », ''Journal of Medical Ethics'', vol. 31, n° 12, 2005, p. 682-686</ref>. === 10.3 L'équité d'accès et la justice distributive === Si l'allongement de la vie devient techniquement possible, une question majeure de justice se pose : qui aura accès à ces technologies ? L'histoire de la médecine et des technologies montre que les innovations émergent généralement dans les contextes de richesse et de privilège avant, éventuellement, de devenir plus largement accessibles. Il serait naïf de croire qu'une technologie de rupture comme l'extension massive de la durée de vie serait immédiatement disponible pour tous<ref>Eric Parens (éd.), ''Shaping Our Selves: On Technology, Flourishing, and a Habit of Thinking'', Oxford University Press, 2010, p. 78-104</ref>. Cela pose une question de justice : serait-il acceptable que certains accèdent à une très grande longévité tandis que d'autres mourraient à un âge ordinaire ? Cela reposerait-il sur une conception fortement inégalitaire de la justice ? Ou, au contraire, faudrait-il considérer que chacun est libre de décider si oui ou non il souhaite bénéficier des technologies de prolongement de la vie, indépendamment du fait que d'autres n'y auraient pas accès<ref>Michael J. Sandel, ''The Case Against Perfection: Ethics in the Age of Genetic Engineering'', Harvard University Press, 2007</ref> ? == XI. Mort et écriture : le mourir philosophique == === 11.1 L'ineffable de la mort et les limites du langage === Un dernier ensemble de questions, épistémologiquement et esthétiquement pertinent, concerne la possibilité de dire la mort, d'en écrire et d'en penser. La mort semble occuper une place singulière dans le langage : elle est à la fois ce dont on parle constamment (mort naturelle, meurtre, suicide, etc.) et ce qui échappe apparemment à la pensée conceptuelle quand nous nous confrontons à notre propre finitude. Blanchot, écrivain et philosophe français, a insisté sur ce point : la mort ne peut être pensée qu'à la limite du pensable, là où le langage frôle son ineffabilité. Pour Blanchot, il ne s'agit pas simplement de dire que la mort est au-delà des mots (ce qui serait un platonisme romantique), mais que la mort révèle les limites du langage de manière productive : c'est dans l'expérience de cette limite que survient une certaine clarté<ref>Maurice Blanchot, ''L'Entretien infini'', Gallimard, 1969, p. 123-152</ref>. === 11.2 Littérature et philosophie face à la mort === La littérature, particulièrement dans les traditions lyrique et épique, a souvent offert ce que la philosophie ne peut que pointer du doigt. Les poètes, de Gilgamesh à Baudelaire en passant par Rilke, ont exploré les dimensions existentielles, affectives et imaginaires de la mort d'une manière que les arguments philosophiques stricts ne peuvent qu'approximativement capturer. Heidegger lui-même, malgré son effort pour ''libérer'' la mort d'une réduction technoscientifique, reconnaît que la poésie peut révéler des dimensions de la mort que la seule analyse conceptuelle ne peut atteindre. Quand Rilke demande, dans ''Le Livre d'heures'', que soit donnée à chacun « sa propre mort », ou quand Hölderlin, dans l'élégie ''Pain et vin'', chante le retrait des dieux, ces œuvres ne ''démontrent'' rien philosophiquement, mais elles ''montrent'' : elles ouvrent une expérience différente du rapport à la mort<ref>Heidegger, ''Introduction à la Métaphysique'', traduction de Gilbert Kahn, PUF, 1967, p. 147-165</ref>. == XII. Synthèse et enjeux ouverts == === 12.1 La pluralité des approches et l'impossibilité d'une réduction === Ce qui émerge de cet examen détaillé de la philosophie de la mort, c'est d'abord l'impossibilité d'une réduction de la mort à une seule dimension (biologique, psychologique, existentielle, éthique, métaphysique). La mort se présente plutôt comme un phénomène polymorphe qui appelle des réponses philosophiques multiples, souvent en tension les unes avec les autres. La tension entre la théorie déprivationniste (qui insiste sur la mort comme privation de biens futurs) et l'argument épicurien (qui affirme que nous ne pouvons pas vraiment expérimenter la mort comme un mal) reste en grande partie non résolue. Cette tension n'est pas une imperfection de la philosophie, mais révèle quelque chose d'essentiel : que la mort échappe à nos catégories conceptuelles habituelles. De la même façon, la tension entre l'affirmation existentialiste selon laquelle la mort donne sens à la vie et la théorie que la mort rend la vie absurde (Camus) ne peut être ''résolue'' au sens d'une démonstration logique univoque. Ces deux positions reflètent plutôt deux aspects complémentaires et irréductibles de la condition humaine mortelle. === 12.2 La mort comme horizon de la pensée === Pour conclure, il importe de souligner que la question de la mort n'est pas une question parmi d'autres en philosophie. Elle constitue l'horizon ultime sur lequel se projette toute réflexion sur le sens, la valeur, l'authenticité et la responsabilité éthique. Aussi bien Heidegger qu'Épicure, Camus que Levinas, bien qu'ils arrivent à des conclusions différentes, s'accordent sur un point : la mort nous force à nous interroger sur ce qui compte vraiment, sur ce qui rend la vie vivable. Dans un contexte contemporain d'accélération technologique et de transformation de grande ampleur de la condition humaine, cette réflexion ancienne sur la mort demeure aussi nécessaire qu'elle l'a toujours été. Comment devons-nous concevoir nos rapports à la finitude face aux promesses d'allongement de la vie ? Comment construire une éthique du deuil et du respect des morts dans un monde de plus en plus fragmenté et délocalisé ? Comment penser la solidarité humaine sans la conscience partagée de notre mortalité commune<ref>Jonathan Glover, ''Humanity: A Moral History of the Twentieth Century'', Yale University Press, 1999, p. 234-267</ref> ? Ce sont les questions que les générations futures devront continuer à se poser, et c'est peut-être en cela que la mort, ce phénomène qui se dérobe toujours à l'expérience, demeure la question constitutive de toute réflexion sérieuse sur ce que c'est que d'être humain. == Notes et références == {{references|colonnes=2}} == Bibliographie indicative == Les références complètes figurent dans les notes. On regroupe ici, par grands domaines, les principaux ouvrages auxquels le lecteur peut se reporter. === Textes classiques === * Platon, ''Phédon'', traduction de Monique Dixsaut, GF Flammarion, 1991. * Épicure, ''Lettre à Ménécée'', dans ''Lettres et Maximes'', traduction de Marcel Conche, PUF, 1987. * Lucrèce, ''De la nature'', livre III, traduction de José Kany-Turpin, GF Flammarion, 1997. * Sénèque, ''Lettres à Lucilius''. * Marc Aurèle, ''Pensées pour moi-même''. * Montaigne, ''Essais'', I, 20 et III, 13. * Spinoza, ''Éthique'', partie IV. === Philosophie contemporaine de la mort === * Thomas Nagel, ''Mortal Questions'', Cambridge University Press, 1979. * Bernard Williams, « The Makropulos Case: Reflections on the Tedium of Immortality », dans ''Problems of the Self'', Cambridge University Press, 1973. * Fred Feldman, ''Confrontations with the Reaper'', Oxford University Press, 1986. * James Stacey Taylor, ''Death, Positivism and Meaning'', Routledge, 2007. * Steven Luper, ''The Philosophy of Death'', Cambridge University Press, 2009. * Ben Bradley, Fred Feldman et Jens Johansson (dir.), ''The Oxford Handbook of Philosophy of Death'', Oxford University Press, 2013. * Steven Luper, « Death », ''The Stanford Encyclopedia of Philosophy'' (sous la direction d'Edward N. Zalta), 2002. === Identité personnelle === * Derek Parfit, ''Reasons and Persons'', Oxford University Press, 1984. * John Locke, ''An Essay Concerning Human Understanding'', livre II, chapitre XXVII. * David Hume, ''A Treatise of Human Nature'', livre I, partie IV, section VI. * David Lewis, « Survival and Identity », dans ''The Identities of Persons'', University of California Press, 1976. * Eric Olson, ''The Human Animal: Personal Identity Without Psychology'', Oxford University Press, 1997. * Paul Ricœur, ''Soi-même comme un autre'', Seuil, 1990. === Existentialisme et finitude === * Martin Heidegger, ''Être et Temps'' (''Sein und Zeit'', 1927), traduction de François Vezin, Gallimard, 1986. * Albert Camus, ''Le Mythe de Sisyphe'', Gallimard, 1942. * Søren Kierkegaard, ''Le Concept d'Angoisse'' (1844), traduction de Gilles Hanot, PUF, 2007. * Simone de Beauvoir, ''Tout compte fait'', Gallimard, 1972. * Karl Jaspers, ''Introduction à la pensée philosophique'', traduction d'Yvon Belaval, 10/18, 1970. === Bioéthique et fin de vie === * Tom L. Beauchamp et James F. Childress, ''Principles of Biomedical Ethics'', Oxford University Press, 7e édition, 2013. * Helga Kuhse et Peter Singer (dir.), ''A Companion to Bioethics'', Blackwell, 2009. * David M. Greer, Matthew P. Kirschen, Ariane Lewis et al., « Pediatric and Adult Brain Death/Death by Neurologic Criteria Consensus Practice Guideline », ''Neurology'', vol. 101, n° 24, 2023. * President's Commission for the Study of Ethical Problems in Medicine, ''Defining Death: Medical, Legal and Ethical Issues'', Washington D.C., 1981. * Michael J. Sandel, ''The Case Against Perfection: Ethics in the Age of Genetic Engineering'', Harvard University Press, 2007. === Histoire sociale et anthropologie de la mort === * Philippe Ariès, ''L'Homme devant la mort'', Seuil, 1977. * Vladimir Jankélévitch, ''La Mort'', Flammarion, 1966. * Émile Durkheim, ''Les Formes élémentaires de la vie religieuse'' (1912), traduction de Corinne Enaudeau, Seuil, 2003. * Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', supplément au livre IV, chapitre 41. == Notions liées == * [[../Finitude/]] * [[../Âme/]] * [[../Conscience/]] * [[../Existence/]] * [[../Angoisse/]] * [[../Euthanasie/]] * [[../Bioéthique/]] {{AutoCat}} bh11l53n00b7aw2rt4f9vnlb5y6u88i 768735 768734 2026-06-26T18:49:29Z PandaMystique 119061 768735 wikitext text/x-wiki {{DicoPhilo|Mort|lecture=oui}} [[Fichier:Philippe de Champaigne Still-Life with a Skull.JPG|vignette|upright=1.1|''Vanité'' (Philippe de Champaigne, vers 1671) : le crâne, la tulipe fanée et le sablier composent un ''memento mori'', rappel de la brièveté de la vie.]] La mort est à la fois l'évidence la mieux partagée et l'énigme la plus résistante. Chacun sait qu'il mourra ; personne n'a l'expérience de sa propre mort. Cette asymétrie explique que la philosophie ne cesse d'y revenir sans jamais l'épuiser. Encore faut-il préciser de quoi l'on parle, car le mot recouvre des questions distinctes qu'il serait imprudent de confondre. On peut distinguer quatre plans, qui se croisent sans se réduire l'un à l'autre. Sur le plan biologique, la mort est la cessation des fonctions qui maintiennent un organisme en vie, et la médecine cherche à en fixer le seuil et les critères. Sur le plan [[Dictionnaire de philosophie/Métaphysique|métaphysique]], elle pose la question de ce qui disparaît exactement : un corps, une personne, une conscience, peut-être une âme. Sur le plan éthique, elle engage nos décisions, nos devoirs et nos droits, du deuil au soin des mourants, de l'[[Dictionnaire de philosophie/Euthanasie|euthanasie]] à la justice entre les générations. Sur le plan existentiel, enfin, elle n'est plus un événement futur parmi d'autres, mais l'horizon qui donne à chaque vie sa tonalité, son urgence et, peut-être, son sens. Cet article suit ces fils l'un après l'autre, en partant des repères que l'histoire de la philosophie nous a légués. == I. Définitions et approches fondamentales == === 1.1 Définitions ontologiques et biologiques === La mort est souvent décrite, de façon très générale, comme le passage de la vie à la non-vie. Cette formule a l'avantage de la simplicité, mais elle reste vague, car elle ne dit ni ce qu'est « vivre » au sens pertinent (biologique, psychologique, moral, juridique), ni à partir de quel seuil on doit parler de mort plutôt que d'agonie ou de défaillance grave. C'est pourquoi les discussions sur la mort se distribuent habituellement entre deux plans. D'un côté, la médecine et le droit cherchent des critères opératoires, permettant de constater un décès de manière fiable et publique. De l'autre, la philosophie demande ce que ces critères présupposent : s'agit-il de la fin d'un organisme, de la fin d'une personne, de la fin d'une [[Dictionnaire de philosophie/Conscience|conscience]], ou de la fin d'un certain type de relation sociale et symbolique ? Dans les pratiques contemporaines, la mort est généralement constatée à partir d'un état tenu pour irréversible. Selon les cadres juridiques et médicaux, on retient soit la cessation irréversible des fonctions circulatoires et respiratoires, soit la cessation irréversible de l'ensemble des fonctions de l'encéphale (ce que l'on appelle couramment « mort encéphalique »). Il faut éviter ici une confusion fréquente : la « mort clinique » désigne classiquement la phase initiale d'un arrêt cardio-respiratoire, phase qui peut, dans certains cas, être réversible grâce à une réanimation rapide ; elle ne coïncide donc pas, par elle-même, avec la mort au sens du décès constaté. ==== 1.1.1 La mort : un phénomène biologique ==== La mort n'est pas un interrupteur qui ferait tomber instantanément toutes les fonctions du vivant. La décomposition est un processus, et la disparition des fonctions se fait à des vitesses différentes selon les tissus. C'est ce décalage qui explique que certaines activités cellulaires puissent persister un temps après l'arrêt de la circulation, sans que cela suffise à dire que « l'organisme », comme totalité vivante, continue d'exister. Il faut également corriger une idée reçue très répandue : les cheveux et les ongles ne « poussent » pas après la mort. L'impression de croissance vient surtout de la déshydratation et de la rétraction des tissus cutanés, qui découvrent davantage la tige du poil ou le bord de l'ongle et donnent une illusion d'allongement. Enfin, la notion de mort encéphalique soulève une difficulté conceptuelle bien connue. En pratique, l'état dit de « mort encéphalique » n'est possible, comme état clinique observable, que sous assistance (notamment ventilation et prise en charge de réanimation), puisque l'organisme ne respire plus spontanément. Des publications ont néanmoins signalé des cas de maintien somatique prolongé après un diagnostic de mort encéphalique, parfois pendant des semaines ou davantage, avec persistance de certaines fonctions (thermorégulation altérée mais partielle, croissance chez l'enfant, gestation maintenue sous assistance, etc.). Ces situations, rares et discutées, nourrissent la controverse sur l'idée selon laquelle le cerveau serait, à lui seul, « l'intégrateur » indispensable de l'organisme. ==== 1.1.2 La mort comme fin ou comme cessation : clarifier le vocabulaire ==== Pour éviter les malentendus, on peut distinguer deux manières de parler, qui ne se recouvrent pas toujours. La première décrit la mort comme une fin : le vivant « n'est plus », au sens où le sujet a cessé d'exister. La seconde décrit la mort comme une cessation : certaines fonctions vitales, tenues pour déterminantes, cessent définitivement. Ces deux descriptions se croisent souvent, mais elles ne répondent pas exactement à la même question. La première demande : « qu'est-ce qui disparaît ? » La seconde demande : « quels signes publics permettent d'établir que la disparition est advenue ? » Cette distinction éclaire un point important : les définitions opératoires (médicales et juridiques) ne sont pas, à elles seules, des définitions métaphysiques. Le droit doit pouvoir trancher, mais trancher ne revient pas à épuiser le sens de ce qui est tranché. C'est ce décalage qui explique, par exemple, qu'un même cadre légal puisse être jugé satisfaisant du point de vue de la sécurité des pratiques, tout en restant contesté du point de vue de la signification de la mort. On peut illustrer ce rôle des critères opératoires avec l'exemple, souvent cité, du droit américain : l'Uniform Determination of Death Act propose une formulation qui admet deux voies de constatation, l'une par la cessation irréversible des fonctions circulatoires et respiratoires, l'autre par la cessation irréversible de toutes les fonctions de l'ensemble du cerveau, tronc cérébral compris, la détermination devant suivre les standards médicaux reconnus. ==== 1.1.3 Les critères de la mort : problèmes contemporains ==== La question philosophique de la définition de la mort a acquis une urgence pratique nouvelle avec les progrès de la médecine moderne, notamment l'invention des respirateurs artificiels et des techniques de réanimation. Traditionnellement, la mort s'identifiait par le critère cardio-respiratoire : une personne était déclarée morte lorsque son cœur cessait de battre et qu'elle cessait de respirer de manière irréversible. Ce critère restait suffisant à une époque où l'arrêt cardiaque entraînait rapidement des dommages cérébraux irréversibles. Depuis les années 1960, un nouveau critère s'est progressivement imposé dans la plupart des juridictions : le critère de mort cérébrale (ou mort encéphalique). Selon ce critère, une personne meurt lorsque toutes les fonctions de son cerveau, ou du tronc cérébral, selon les juridictions, ont cessé de manière irréversible, même si son cœur continue de battre grâce au soutien artificiel<ref>President's Commission for the Study of Ethical Problems in Medicine, ''Defining Death: Medical, Legal and Ethical Issues'', Washington D.C., 1981</ref>. Cette redéfinition a été motivée en partie par des considérations pratiques (notamment la possibilité de prélever des organes pour transplantation), mais elle soulève des questions philosophiques fondamentales. Plusieurs philosophes et bioéthiciens ont contesté le critère de mort cérébrale. D'une part, certains patients déclarés en état de mort cérébrale continuent à manifester des fonctions intégratives significatives : régulation de la température corporelle, cicatrisation des blessures, réactions immunitaires, et dans quelques cas documentés, maturation sexuelle et croissance<ref>Alan Shewmon, « Brain Death: Can It Be Resuscitated? », dans ''Hastings Center Report'', vol. 39, n° 2, 2009, p. 18-24</ref>. Ces observations suggèrent que le cerveau ne constitue peut-être pas le seul organe responsable de l'intégration organisationnelle, ce qui ébranle le fondement biologique du critère de mort cérébrale. D'autre part, des travaux neuroscientifiques récents ont mis en évidence des formes de conscience préservée ou « couverte » chez des patients longtemps tenus pour dépourvus de toute vie mentale, par exemple certains sujets en état végétatif ou de conscience minimale<ref>Calixto Machado, « Neuroscience and Brain Death Controversies », dans ''Journal of Religion and Health'', vol. 57, n° 5, 2018, p. 2001-2015</ref>. Ces résultats portent sur les troubles de la conscience, et non sur la mort encéphalique correctement diagnostiquée, dans laquelle l'arrêt des fonctions cérébrales est par définition irréversible et exclut tout retour de la conscience ; ils rendent toutefois plus aiguë la question du tracé exact de la frontière et du risque d'erreur diagnostique. Si l'on définit la mort de la personne comme la perte irréversible de la capacité de conscience, ainsi que le proposent certains philosophes, le critère encéphalique paraît trop restrictif : un sujet ayant définitivement perdu toute conscience, comme dans un état végétatif chronique, reste vivant selon ce critère alors qu'il aurait, à cette aune, déjà cessé d'exister comme personne. À l'inverse, ce même critère rattache la mort à l'ensemble des fonctions cérébrales plutôt qu'à la seule conscience, ce qui en fait l'objet d'un désaccord persistant entre partisans d'une définition encéphalique globale et partisans d'une définition fondée sur les fonctions supérieures. Paweł Górka Nowak et Tomasz Żuradzki ont récemment soutenu qu'il n'existe point une seule définition biologiquement correcte de la mort, mais plutôt une pluralité de concepts d'organisme en biologie théorique, chacun donnant lieu à une conception différente de ce qui constitue la mort d'un organisme<ref>Nowak et Żuradzki, « How Many Ways Can You Die? », p. 4-19</ref>. Selon ces auteurs, la question « Quand une personne meurt-elle ? » n'a pas de réponse univoque indépendante du contexte et des objectifs pratiques que nous poursuivons en posant cette question. === 1.2 La mort comme privation et le problème du mal de mourir === L'une des grandes énigmes philosophiques consiste à déterminer en quoi consiste précisément le caractère nuisible de la mort. Pourquoi la mort est-elle considérée comme un mal ? Cette question, qui peut sembler évidente, a engendré des débats philosophiques intenses depuis l'Antiquité. ==== 1.2.1 L'argument épicurien : la mort n'est rien pour nous ==== [[Fichier:Marble Bust of Epicurus, Roman Copy.jpg|vignette|upright=1.1|Buste d'Épicure (copie romaine d'un original grec). Pour le philosophe, « la mort n'est rien pour nous ».]] Épicure, philosophe grec du {{s|IV}} avant notre ère, a formulé l'un des arguments les plus célèbres et les plus troublants concernant la mort. Dans sa [[s:Lettre à Ménécée|''Lettre à Ménécée'']], il affirme que « la mort n'est rien pour nous » (ὁ θάνατος οὐδὲν πρὸς ἡμᾶς)<ref>Épicure, ''Lettre à Ménécée'', dans ''Lettres et Maximes'', traduction de Marcel Conche, PUF, 1987, p. 217-229</ref>. Son raisonnement peut se reconstituer comme suit : # Seul ce qui s'expérimente peut être bon ou mauvais pour nous (principe hédoniste). # La mort n'implique aucune expérience, puisque nous n'existons plus pour percevoir. # Par conséquent, la mort ne peut être ni bonne ni mauvaise pour nous. Lucrèce, poète et philosophe romain disciple d'Épicure, a développé cet argument dans son poème ''De Rerum Natura'' (''De la nature des choses''). Il soutient que puisque nous n'avons pas souffert de ne pas exister avant notre naissance, nous ne devrions pas craindre de ne pas exister après notre mort<ref>Lucrèce, [[s:De la nature des choses|''De la nature'']], livre III, vers 830-869, traduction de José Kany-Turpin, GF Flammarion, 1997, p. 253-257</ref>. Cet argument, souvent appelé « argument de symétrie », affirme que notre attitude envers la mort future devrait être symétrique à notre attitude (indifférente) envers notre non-existence passée. L'argument épicurien repose sur ce que les philosophes contemporains nomment « la condition d'existence » : quelque chose ne peut être bon ou mauvais pour un sujet que si ce sujet existe<ref>Fred Feldman, « Some Puzzles About the Evil of Death », dans ''The Philosophical Review'', vol. 100, n° 2, 1991, p. 205-227</ref>. Si cette condition s'accepte, et si la mort entraîne la cessation de l'existence (terminationnisme), il semble alors impossible que la mort soit nuisible pour celui qui meurt. Pourtant, l'argument épicurien heurte immédiatement nos intuitions les plus profondes. Nous jugeons généralement que la mort prématurée d'un jeune adulte constitue un grave malheur, qu'il est pire de mourir à vingt ans qu'à quatre-vingt-dix ans, et que tuer quelqu'un lui cause du tort. Si la mort n'était rien pour nous, toutes ces intuitions se trouveraient invalides. ==== 1.2.2 La théorie de la privation (Deprivation Account) ==== La réponse dominante à l'argument épicurien dans la philosophie analytique contemporaine est la ''théorie de la privation'' (''deprivation account''). Cette théorie affirme que la mort est nuisible pour celui qui meurt non en vertu de ses propriétés intrinsèques, la mort en elle-même n'implique effectivement aucune souffrance, mais en vertu de ses propriétés extrinsèques : la mort nous prive des biens et des expériences que nous aurions connus si nous avions continué à vivre<ref>Thomas Nagel, « Death », dans ''Mortal Questions'', p. 1-10</ref>. Selon cette approche, la mort constitue un mal ''comparatif'' : elle est nuisible parce qu'elle place la personne dans une situation pire que celle dans laquelle elle aurait été si elle n'était pas morte. Comme le formule Fred Feldman : « La mort au moment ''t'' est nuisible pour une personne ''S'' dans la mesure où elle rend la valeur de la vie de ''S'' inférieure à celle qu'elle aurait eue si ''S'' n'était pas morte à ''t'' »<ref>Feldman, ''Confrontations with the Reaper'', p. 133</ref>. La théorie de la privation repose sur une distinction essentielle entre deux types de valeur : la valeur intrinsèque et la valeur extrinsèque. Un état de choses possède une valeur intrinsèque en vertu de ses propriétés intrinsèques, la douleur est intrinsèquement mauvaise, le plaisir intrinsèquement bon. Un état de choses possède une valeur extrinsèque en vertu de ses relations avec d'autres états de choses, une vaccination douloureuse se révèle extrinsèquement bonne parce qu'elle prévient une maladie future. La mort, selon la théorie de la privation, est extrinsèquement nuisible : elle est mauvaise non pour ce qu'elle est, mais pour ce qu'elle empêche<ref>Christopher Wareham, « Deprivation and the See-saw of Death », dans ''South African Journal of Philosophy'', vol. 28, n° 2, 2009, p. 247-262</ref>. Cette approche parvient à esquiver l'objection épicurienne car elle ne requiert point que le sujet expérimente la mort comme nuisible. De même qu'une vaccination peut être bonne pour moi même si je ne perçois pas cette bonté au moment de la vaccination, la mort peut être nuisible pour moi même si je ne peux l'éprouver comme telle. L'erreur d'Épicure, selon les défenseurs de la théorie de la privation, consiste à avoir négligé la possibilité qu'un événement soit extrinsèquement nuisible. == II. La mort dans l'histoire de la philosophie == Avant d'aborder les problèmes contemporains, il vaut la peine de remonter le fil des grandes réponses que la tradition a formulées. Non par révérence pour les Anciens, mais parce que la plupart des arguments qui nous occupent encore s'y trouvent déjà esquissés. Apprendre à mourir, savoir ce qui survit, mesurer si la mort est un mal : ces trois interrogations traversent vingt-cinq siècles de pensée. === 2.1 L'Antiquité : la mort et l'exercice de la sagesse === [[Fichier:David - The Death of Socrates.jpg|vignette|upright=1.1|''La Mort de Socrate'' (Jacques-Louis David, 1787). Condamné à boire la ciguë, Socrate incarne le philosophe qui « s'exerce à mourir ».]] C'est avec Platon que la mort devient un thème proprement philosophique. Dans le [[s:Phédon|''Phédon'']], qui met en scène les dernières heures de Socrate avant qu'il ne boive la ciguë, la philosophie est définie comme un apprentissage de la mort. Ceux qui s'attachent à la philosophie de la droite manière, écrit Platon, s'exercent à mourir<ref>Platon, ''Phédon'', 64a.</ref>. La formule peut surprendre. Elle s'éclaire dès qu'on saisit ce que Socrate entend par mourir : la séparation de l'[[Dictionnaire de philosophie/Âme|âme]] et du corps. Or le philosophe, qui cherche le vrai, doit déjà de son vivant détacher sa pensée des sollicitations du corps ; mourir ne serait que l'achèvement de cet exercice. Derrière cette thèse se profile la doctrine de l'immortalité de l'âme, que le dialogue s'efforce d'établir par une série d'arguments : l'âme, simple et apparentée aux Idées, ne saurait se dissoudre comme se dissout le composé corporel. [[Dictionnaire de philosophie/Aristote|Aristote]], élève de Platon, refuse cette séparation. Pour lui, l'âme n'est pas un hôte logé dans le corps, mais la forme du corps vivant, ce qui fait qu'un organisme est en acte ce qu'il est. De cette définition découle une conséquence sévère : l'âme individuelle ne survit pas à la dissolution du composé, pas plus que la forme d'une statue ne subsiste une fois le bronze fondu. Un point reste discuté, celui du ''noûs'' (l'intellect), dont Aristote suggère en un passage obscur qu'il pourrait être séparable ; les commentateurs s'opposent depuis sur le sens de cette remarque. Sur la mort elle-même, Aristote est plus net. Dans l{{'}}''Éthique à Nicomaque'', il la nomme la chose la plus effrayante, parce qu'elle est une limite : pour celui qui est mort, dit-il, plus rien ne semble être ni bien ni mal<ref>Aristote, ''Éthique à Nicomaque'', III, 9, 1115a26.</ref>. Cette dernière observation ouvre déjà la voie à l'argument qu'Épicure rendra célèbre. Cet argument, on l'examine en détail plus loin (section 1.2). Rappelons-en seulement le principe : pour Épicure, la mort n'est rien pour nous, car tant que nous sommes, elle n'est pas là, et quand elle est là, nous ne sommes plus. La crainte de la mort reposerait donc sur une confusion. L'école rivale, le stoïcisme, parvient à une sérénité comparable par un autre chemin. Là où Épicure dissout la peur en niant que la mort nous concerne, les Stoïciens invitent à l'apprivoiser par un exercice quotidien, la ''meditatio mortis'' (la méditation de la mort), qui consiste à se représenter sa propre fin pour lui ôter son pouvoir de surprise. Médite la mort, écrit Sénèque à Lucilius : celui qui a appris à mourir a désappris à être esclave<ref>Sénèque, [[s:Lettres à Lucilius|''Lettres à Lucilius'']], lettre 26.</ref>. Épictète déplace la difficulté du côté du jugement : ce n'est pas la mort qui effraie les hommes, mais l'opinion qu'ils s'en font<ref>Épictète, [[s:Manuel d’Épictète|''Manuel'']], 5.</ref>. Marc Aurèle, enfin, replace la mort dans le cycle de la nature, où elle n'est qu'une transformation parmi d'autres, ni à désirer ni à fuir<ref>Marc Aurèle, [[s:Pensées pour moi-même|''Pensées pour moi-même'']], IV, 17.</ref>. Quatre écoles, deux stratégies : nier que la mort nous atteigne, ou s'entraîner à la regarder en face. Une part de la sagesse antique se tient dans cet écart. === 2.2 De Montaigne à Spinoza : apprendre à mourir, apprendre à vivre === La Renaissance hérite de cette sagesse et la déplace. Dans un essai au titre programmatique, « Que philosopher c'est apprendre à mourir » ([[s:Essais|''Essais'']], I, 20), Montaigne reprend d'abord le mot d'ordre antique : puisque la mort est le terme de notre course, mieux vaut l'avoir constamment à l'esprit pour n'en être jamais surpris. Mais l'intérêt de Montaigne tient à ce qu'il se déjuge. Dans les essais plus tardifs, et notamment dans « De l'expérience » (''Essais'', III, 13), il renverse la maxime : à force de penser à la mort, on risque de manquer la vie. La nature, observe-t-il, nous apprend mieux à mourir que toute la philosophie, à condition qu'on la laisse faire. Il souhaite que la mort le trouve occupé à son jardin, indifférent à elle et plus encore à son ouvrage inachevé<ref>Montaigne, ''Essais'', I, 20.</ref>. Ce passage du ''memento mori'' à une forme de confiance dans le cours des choses annonce un tournant. Spinoza en tire la formule la plus abrupte. Dans l{{'}}[[s:Éthique (Spinoza)|''Éthique'']], il écrit que l'homme libre ne pense à rien moins qu'à la mort, et que sa sagesse est une méditation non de la mort, mais de la vie<ref>Spinoza, ''Éthique'', IV, proposition 67.</ref>. La phrase paraît contredire toute la tradition de la ''meditatio mortis''. Elle la prolonge en réalité, en la portant à son terme. Pour Spinoza, se complaire dans la pensée de la mort est une passion triste, qui diminue notre puissance d'agir. L'homme conduit par la raison ne nie pas qu'il mourra ; il refuse seulement de laisser cette pensée gouverner sa vie. La sagesse n'est pas de se préparer à la mort, mais de comprendre et d'aimer ce qui, en nous, participe de l'éternel. On mesure le chemin parcouru depuis le ''Phédon'' : l'immortalité, chez Spinoza, n'est plus la survie d'une âme individuelle après le trépas, mais un certain rapport à l'éternité que l'on peut éprouver dès maintenant. === 2.3 Schopenhauer : la mort, « muse » du philosophe === [[Fichier:Arthur Schopenhauer by J Schäfer, 1859b.jpg|vignette|upright=1.1|Arthur Schopenhauer (photographie de 1859). Il voyait dans la mort le « génie inspirateur » de la philosophie.]] Le {{s|XIX}} accorde à la mort une place de premier plan. Schopenhauer va jusqu'à voir en elle l'origine même du philosopher : la mort, écrit-il, est le génie inspirateur de la philosophie, et sans elle on aurait peine à philosopher<ref>Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', supplément au livre IV, chapitre 41.</ref>. Sa pensée tient en une intuition. Ce qui meurt, c'est l'individu, ce phénomène passager ; mais l'individu n'est que la manifestation éphémère d'un vouloir-vivre (''Wille zum Leben'') unique, aveugle et sans terme, indifférent à la naissance comme à la mort de ses innombrables exemplaires. À l'échelle de ce vouloir, mourir n'est rien : la volonté ne se trouve pas entamée par la disparition d'un de ses reflets, de même que l'océan n'est pas diminué par la vague qui se brise. Cette consolation a quelque chose de glaçant, car elle s'achète au prix de l'individu, dont elle nie l'importance. Elle inaugure pourtant une manière neuve de penser la mort : non plus comme le problème d'un sujet inquiet pour son salut, mais comme un moment dans l'économie d'une nature impersonnelle. === 2.4 Le {{s|XX}} : pulsion de mort, personnes du mourir, histoire des attitudes === Le {{s|XX}} démultiplie les approches. Trois apports méritent d'être isolés, car ils ne se confondent ni avec le courant existentiel ni avec les débats analytiques que l'on retrouvera plus loin. Freud, d'abord, introduit en 1920 une hypothèse troublante. Dans ''Au-delà du principe de plaisir'', cherchant à comprendre la répétition des expériences pénibles, il avance l'existence d'une pulsion de mort (''Todestrieb''), tendance silencieuse de tout vivant à retourner à l'état inorganique d'où il est issu. La vie psychique serait le théâtre d'un conflit entre cette pulsion et les pulsions de vie (''Éros''). L'hypothèse reste contestée, y compris chez les psychanalystes ; elle a néanmoins imposé l'idée que le rapport à la mort travaille la psyché bien en deçà de la conscience. Quelques années plus tôt, dans « Considérations actuelles sur la guerre et sur la mort » (1915), Freud avait déjà relevé un paradoxe : nul ne croit à sa propre mort, et dans son inconscient chacun se tient pour immortel<ref>Sigmund Freud, « Considérations actuelles sur la guerre et sur la mort », 1915.</ref>. Jankélévitch, ensuite, propose dans ''La Mort'' (1966) une distinction devenue classique, celle des trois personnes de la mort. Il y a la mort en première personne, la mienne, dont je ne puis rien savoir puisque je ne lui survivrai pas ; la mort en deuxième personne, celle de l'être aimé, du « toi », qui m'atteint comme une amputation et m'ouvre pourtant à ce que la mort a de plus présent ; et la mort en troisième personne, anonyme et statistique, celle dont parlent les journaux, abstraite et presque indolore. La mort de l'autre proche occupe ici une situation singulière : assez proche pour me bouleverser, assez extérieure pour que j'y survive et la pense<ref>Vladimir Jankélévitch, ''La Mort'', Paris, Flammarion, 1966.</ref>. C'est ce thème que développeront, dans un autre vocabulaire, Levinas et Derrida (voir section 3.2). Ariès, enfin, n'est pas un philosophe mais un historien, et c'est ce déplacement qui fait son prix. Dans ''L'Homme devant la mort'' (1977), il montre que le rapport à la mort possède une histoire, que nos attitudes n'ont rien d'éternel. À la mort apprivoisée du Moyen Âge, familière et publique, aurait succédé, à l'époque contemporaine, une mort interdite, refoulée, dissimulée à l'hôpital et soustraite au regard des vivants. La thèse a été discutée et nuancée ; elle a le mérite de rappeler que la manière dont une époque traite ses mourants en dit long sur l'idée qu'elle se fait de la vie<ref>Philippe Ariès, ''L'Homme devant la mort'', Paris, Seuil, 1977.</ref>. Ce constat fait le lien avec les questions éthiques et bioéthiques que soulève aujourd'hui la médicalisation de la fin de vie (parties V et X). == III. La mort et l'identité personnelle == === 3.1 La continuité du moi et la survivance personnelle === La mort pose immédiatement une question métaphysique fondamentale : que devient ce qui me constitue lorsque je cesse de vivre ? Cette interrogation apparemment simple ouvre sur des problèmes ontologiques redoutables. Les théories de l'identité personnelle se divisent historiquement selon deux grands axes : d'un côté les théories du critère psychologique, de l'autre les théories dites somatiques. Ces deux approches proposent des réponses divergentes quant à la manière de concevoir ma relation à ma propre mort. ==== 3.1.1 Les théories psychologiques : la conscience comme fondement de l'identité ==== Les théories psychologiques, notamment chez John Locke et David Hume, font reposer l'identité personnelle sur une base psychologique : la continuité de la conscience et de la mémoire. Locke affirme explicitement dans son ''Essai concernant l'entendement humain'' (auquel il ajoute ce chapitre dans la deuxième édition de 1694) que « l'identité personnelle ne consiste pas dans l'identité de substance, mais dans l'identité de conscience »<ref>John Locke, ''An Essay Concerning Human Understanding'', Book II, Chapter XXVII, édition critique de P. H. Nidditch, Oxford University Press, 1975, p. 346</ref>. Cette formulation inédite introduit une distinction capitale entre trois types d'identité : l'identité de la personne, l'identité de l'homme (c'est-à-dire l'organisme biologique), et l'identité de substance. Selon Locke, seule la continuité de conscience garantit l'identité personnelle à travers le temps. Je suis la même personne que celle qui a accompli telle action passée dans la mesure où je peux me souvenir d'avoir accompli cette action. Ce qui importe au premier chef, ce n'est ni la persistance du même corps, ni la continuité de la même âme immatérielle, mais la chaîne ininterrompue de mémoire<ref>Locke, ''Essay'', Book II.XXVII.9-10, p. 346-347</ref>. Cette théorie psychologique possède des implications profondes pour notre compréhension de la mort : si l'identité personnelle consiste en continuité de conscience, alors la mort, entendue comme cessation irréversible de toute conscience, représente bien la fin du moi, la destruction de ce qui me rend moi-même. David Hume, philosophe écossais du {{s|XVIII}}, a transformé la théorie lockienne en l'approfondissant. Contrairement à Locke, Hume soutient que le moi n'est pas une entité substantielle stable mais plutôt un « faisceau de perceptions » (''bundle of perceptions''), c'est-à-dire une succession constante de pensées, de sensations et d'émotions<ref>David Hume, ''A Treatise of Human Nature'' (1739-40), Book I, Part IV, Section VI, traduction française de Jean-Pierre Clero, Garnier Flammarion, 1995, p. 301-314</ref>. Pour Hume, ce que nous appelons l'identité personnelle n'est qu'une fiction utile, une illusion née de la ressemblance et de la causalité entre nos perceptions successives. L'unité que nous attribuons à notre moi n'est qu'une construction artificielle de l'esprit. Le débat entre Locke et Hume reste central dans la philosophie contemporaine de l'identité personnelle. Ruth Boeker a montré que la théorie lockienne ne repose pas sur une simple analyse métaphysique, mais s'enracine dans des préoccupations morales et religieuses spécifiques : Locke développe sa théorie de l'identité en liaison directe avec sa conception de la responsabilité morale et du jugement divin<ref>Ruth Boeker, « Locke and Hume on Personal Identity: Moral and Religious Differences », dans ''Hume Studies'', vol. 41, n° 2, 2015, p. 105-135</ref>. La mémoire, pour Locke, constitue le critère d'identité non pas comme simple fait métaphysique brut, mais parce que la responsabilité morale, et particulièrement la possibilité du jugement et de la récompense ou du châtiment divins, exige que celui qui subit les conséquences de ses actes soit identique à celui qui les a commis. ==== 3.1.2 Derek Parfit et la réduction de l'identité personnelle : explications détaillées ==== ===== Le problème fondamental : réductionnisme vs. non-réductionnisme ===== Pour comprendre la contribution majeure de Derek Parfit à la philosophie de l'identité personnelle, il faut d'abord saisir une distinction conceptuelle capitale qu'il établit : celle entre réductionnisme et non-réductionnisme. ''La conception non-réductionniste'' affirme que l'existence d'une personne constitue une « réalité supplémentaire » (''further fact'') qui s'ajoute à l'ensemble des faits physiques et psychologiques. Selon cette vision, même si nous connaissions la totalité absolue des faits concernant mon cerveau, mon corps et tous mes états mentaux, il resterait encore un fait supplémentaire à déterminer : suis-je la même personne ou une personne différente ? Ce fait additionnel serait une réalité métaphysique fondamentale, irréductible, peut-être une âme immatérielle ou un « moi » cartésien pur<ref>Derek Parfit, ''Reasons and Persons'', Oxford University Press, 1984, p. 199-215</ref>. ''La conception réductionniste'', par contraste, soutient que l'existence d'une personne ne constitue point une réalité supplémentaire. L'existence d'une personne se réduit entièrement à l'existence de son cerveau, de son corps et à la manifestation de certains événements physiques et psychologiques. Parfit offre une analogie élucidante : de même que l'existence d'une nation n'ajoute aucune réalité supplémentaire au-delà des faits concernant les individus qui la composent et leurs interrelations mutuelles, l'existence d'une personne n'ajoute rien au-delà des faits psychophysiques<ref>Parfit, ''Reasons and Persons'', p. 210</ref>. Une nation constitue une réalité complexe mais réductible ; il en va identiquement pour une personne. Parfit défend le réductionnisme en soulignant l'absence totale de preuves probantes en faveur de l'existence de ces supposées « réalités supplémentaires ». Les cas de fission cérébrale, où le cerveau est divisé en deux, montrent qu'aucune entité métaphysique simple et indivisible ne détermine univoquement qui je suis. Aucune preuve scientifique ne corrobore l'existence d'une âme ou d'un moi cartésien<ref>Parfit, ''Reasons and Persons'', p. 207-210</ref>. ===== La théorie réductionniste de l'identité personnelle : la Relation R ===== Parfit propose que si nous adoptons le réductionnisme, nous devons spécifier les faits plus élémentaires en lesquels l'identité personnelle se réduit. Il examine deux candidates principales : la continuité physique et la continuité psychologique. Après analyse rigoureuse, il conclut que c'est la continuité psychologique qui importe<ref>Parfit, ''Reasons and Persons'', p. 201-215</ref>. Parfit introduit alors le concept central de sa théorie : ''la Relation R'' (continuité et connectivité psychologiques). Cette relation se compose de deux éléments distincts : 1. ''La connectivité psychologique directe'' (''psychological connectedness'') : les connexions immédiates et directes de mémoire, de désir, d'intention et autres états mentaux entre mes états psychologiques à deux moments différents. Par exemple, je me souviens d'avoir pris hier une décision particulière. 2. ''La continuité psychologique'' (''psychological continuity'') : une chaîne causale connectée d'états psychologiques reliés les uns aux autres, même si les états situés aux extrémités de cette chaîne ne sont pas directement connectés l'un à l'autre. Par exemple, je me souviens d'hier, hier je me souvenais d'avant-hier, et ainsi de suite, même si je ne me souviens peut-être pas directement d'événements remontant à mon enfance. La Relation R se définit donc comme ''la connectivité psychologique et/ou la continuité psychologique, pourvues de la bonne sorte de cause''. La « bonne sorte de cause » ne renvoie pas nécessairement à un mode naturel ordinaire de continuité ; ce qui importe est qu'il existe une relation causale appropriée entre les états psychologiques<ref>Parfit, ''Reasons and Persons'', p. 216</ref>. ===== Le cas de division du cerveau : le cœur du problème ===== La force de la position de Parfit réside largement dans son analyse du ''cas de division du cerveau'', qui crée une aporie majeure pour toutes les théories traditionnelles de l'identité. ''Le scénario :'' Imaginez que vous souffriez d'une maladie incurable et que la seule issue thérapeutique consiste à séparer vos deux hémisphères cérébraux, qui fonctionnent normalement de manière tout à fait indépendante, et à les transplanter chacun dans un corps différent. Les deux êtres conscients résultant de cette opération seraient qualitativement identiques à vous : ils posséderaient les mêmes souvenirs, les mêmes intentions, les mêmes traits de personnalité. Vous vous réveilleriez apparemment comme deux personnes distinctes, chacune convaincue d'être vous. ''Le problème logique qui en découle :'' Posez maintenant une question qui semble simple : dans ce scénario, serai-je numériquement identique à la personne qui se réveille dans le corps de gauche ? - Si la réponse est « oui », serai-je aussi numériquement identique à la personne du corps de droite ? - Si les réponses sont « oui » aux deux questions, alors par transitivité logique, les deux personnes seraient identiques l'une à l'autre, ce qui est absurde. - Si la réponse n'est « oui » que pour une seule des deux, il nous faut une raison objective pour distinguer les deux cas, mais aucune raison objective n'existe. Les deux corps sont identiques, et les deux personnes résultantes entretiennent une relation identiquement forte avec mon moi pré-division. - Si la réponse est « non » pour les deux, il semblerait que je ne survive pas à l'opération, ce qui contredit notre intuition : la totalité de ma vie mentale s'est néanmoins perpétuée et poursuivie dans les deux corps<ref>Parfit, ''Reasons and Persons'', Partie III, sections 79-80, p. 254-255</ref>. ''La conclusion paradoxale de Parfit :'' Parfit soutient que ce dilemme révèle que l'identité personnelle ne peut pas constituer ce qui compte vraiment pour la survie. Au lieu de cela, c'est ''la Relation R'' qui compte. Dans le cas de division, même si je ne suis numériquement identique à aucune des deux personnes résultantes (au sens strict de l'identité numérique), j'ai néanmoins survécu de la manière la plus excellente possible : la totalité de mes contenus mentaux, mes connexions psychologiques, se perpétuent dans les deux corps<ref>Parfit, ''Reasons and Persons'', p. 261</ref>. Parfit énonce ainsi sa célèbre maxime : « l'identité n'est pas ce qui compte » (''identity is not what matters''). Ce qui doit vraiment nous préoccuper concernant notre avenir, ce qui mérite notre inquiétude rationnelle, ce n'est point l'identité numérique stricte, mais plutôt la présence et la persistance de la Relation R<ref>Parfit, ''Reasons and Persons'', p. 215-216</ref>. ===== Implications pour notre compréhension de la mort ===== Cette théorie novatrice engendre des implications importantes pour notre rapport à la mort : ''Première implication :'' Si ce qui compte vraiment n'est pas l'identité personnelle mais la Relation R, alors notre peur ordinaire de la mort, entendue comme anéantissement simple et fin de l'identité, s'en trouve largement reconsidérée. La mort met certes fin à la Relation R, mais ce phénomène n'est pas plus mystérieux ou rationnellement troublant que d'autres ruptures naturelles de continuité<ref>Parfit, ''Reasons and Persons'', p. 216-223</ref>. ''Deuxième implication :'' Si dans le cas de division du cerveau, ne pas être identique à mes continuateurs psychologiques ne constitue pas un problème du moment que la Relation R se perpétue, alors nous devons remettre en question notre conception ordinaire et quasi-intuitive de la mort. Une mort prématurée n'est mauvaise que parce qu'elle prive la Relation R d'une continuité ultérieure possible. Elle ne constitue point un mystère métaphysique terrifiant ou incompréhensible<ref>Parfit, ''Reasons and Persons'', p. 280-281</ref>. ''Troisième implication :'' Parfit propose une conception graduée de la mort. Au lieu de la concevoir comme une fin abrupte, totale et catégorique, il invite à la penser, dans les cas limites du remplacement progressif, de la fission ou de la fusion, comme une diminution par degrés de la continuité psychologique, au point qu'il puisse n'exister aucune réponse tranchée à la question de savoir si la personne a survécu. Cette gradation concerne la persistance ou l'affaiblissement de la Relation R entre une personne et ses propres continuateurs psychologiques. Elle ne s'étend pas aux traces qu'un défunt laisse dans la mémoire d'autrui ou à l'influence posthume de son œuvre : ces dernières, si elles adoucissent peut-être le sentiment de perte, ne constituent pas la Relation R au sens technique, puisque celle-ci relie un sujet à ses états mentaux futurs et non à l'esprit d'autres personnes<ref>Parfit, ''Reasons and Persons'', p. 281</ref>. ===== Critiques majeures et difficultés ===== Cette théorie, bien qu'influente et féconde, affronte plusieurs objections philosophiques sérieuses : ''L'objection tirée de l'asymétrie :'' on peut douter, dans la lignée des interrogations de Bernard Williams sur l'anticipation, que la Relation R suffise à rendre compte de nos craintes rationnelles face à la mort. Dans une mort ordinaire, la Relation R cesse entièrement ; dans la fission, elle se trouve au contraire préservée chez les deux continuateurs. Si seule comptait la Relation R, la fission devrait nous paraître au moins aussi désirable qu'une survie ordinaire, alors que beaucoup la jugent troublante. Cette asymétrie de nos attitudes laisse penser que l'identité numérique, et non la seule Relation R, pèse dans notre rapport à la persistance et à la mort. David Lewis cherche au contraire à dissoudre la difficulté : correctement analysées au moyen des parties temporelles, identité et Relation R coïncideraient, de sorte que l'identité resterait bien ce qui importe<ref>David Lewis, « Survival and Identity », dans ''The Identities of Persons'', University of California Press, 1976, p. 17-40</ref>. ''L'objection de la non-trivialité :'' Si la Relation R est ce qui compte vraiment, alors selon Parfit, la question « serai-je identique à quelqu'un dans le futur ? » n'est pas tranchée par des faits profonds et non-triviaux. Or, cela semble peu convaincant : que je survive ou non me paraît dépendre de faits bien plus fondamentaux que la simple absence de division cérébrale ou la présence de continuité psychologique<ref>Parfit, ''Reasons and Persons'', p. 264-265</ref>. ''L'objection de la perplexité conceptuelle :'' Si dans le cas de division je ne suis numériquement identique à aucune des deux personnes résultantes, mais que je survis néanmoins en un sens significatif, cela rend le concept même de survie perplexe et énigmatique. Qu'est-ce que « survivre » pourrait signifier si ce n'est précisément être identique à une personne future<ref>Derek Parfit, « We Are Not Human Beings », ''Journal of Consciousness Studies'', vol. 19, n° 5-6, 2012, p. 79-105</ref> ? ===== La révision ultérieure de Parfit ===== Une trentaine d'années après ''Reasons and Persons'', Parfit est revenu sur la question de ce que nous sommes. Dans « We Are Not Human Beings » (2012), il soutient que nous ne sommes pas des animaux de l'espèce humaine, mais la partie consciente et pensante de ces animaux, qu'il identifie au cerveau, ou plus précisément à la portion du cerveau qui sous-tend directement la conscience<ref>Parfit, « We Are Not Human Beings », p. 79-105</ref>. Cette thèse porte sur l'ontologie de la personne, c'est-à-dire sur la nature de ce que nous sommes, et non sur ce qui compte dans la survie : Parfit n'y abandonne pas l'idée, défendue dès 1984, que c'est la continuité psychologique, et non l'identité numérique, qui importe. La portée de ce déplacement est discutée. Olson y voit le signe que la distinction entre Relation R et identité numérique restait difficile à stabiliser, et lit ce texte comme un repli vers une forme d'animalisme centré sur le cerveau<ref>E. T. Olson, « On Parfit's View that We are not Human Beings », dans ''Journal of Philosophy'', vol. 112, n° 1, 2015, p. 5-22</ref>. On peut au contraire souligner la continuité du propos : en distinguant l'animal du sujet pensant, Parfit cherche moins à se rétracter qu'à préciser le support de la continuité psychologique déjà placée au centre de ce qui compte. Sa contribution garde en tout cas son intérêt, celui d'avoir montré que les intuitions ordinaires sur l'identité et la mort reposent sur des présupposés métaphysiques contestables qui appellent un examen critique. ==== 3.1.3 L'animalisme : la mort comme mort de l'organisme ==== Face aux théories psychologiques, une position rivale s'est progressivement imposée au cours des dernières décennies : l'animalisme. Selon cette approche, nous ''sommes'' des organismes biologiques appartenant à l'espèce ''Homo sapiens''<ref>Eric Olson, ''The Human Animal: Personal Identity Without Psychology'', Oxford University Press, 1997, p. 1-18</ref>. Ce que nous désignons par le terme « personne » constitue simplement un animal particulier, nous ne sommes pas composés d'un corps animal auquel s'ajouterait une personne psychologique ; nous ''sommes'' l'animal lui-même. Cette théorie possède des implications directes pour notre conception de la mort. Si je suis un organisme biologique, je meurs précisément quand cet organisme meurt, c'est-à-dire lorsque ses fonctions biologiques intégrées cessent de manière irréversible. L'animalisme semble offrir une réponse simple : la mort est littéralement la mort de l'organisme dont je suis, et c'est pourquoi elle constitue un mal pour moi<ref>Olson, ''The Human Animal'', p. 107-128</ref>. Il ne s'agit pas de chercher dans des abstractions psychologiques pour comprendre l'identité personnelle ; il suffit de reconnaître que je suis, ontologiquement, un animal. Cependant, l'animalisme affronte une objection majeure. Si je suis le même animal que le fœtus dans l'utérus maternel ou que le nourrisson que j'ai été, comment affirmer que je suis identique à ce nourrisson, doté maintenant de souvenirs, de croyances et de désirs que le nourrisson ne possédait nullement ? Kevin Sharpe a proposé une position intermédiaire : le « psychological animalism » selon laquelle nous sommes essentiellement à la fois des animaux et des personnes<ref>Kevin W. Sharpe, « Animalism and Person Essentialism », dans ''Metaphilosophy'', vol. 46, n° 1, 2015, p. 48-68</ref>. Selon cette approche plus nuancée, nos conditions de persistance sont à la fois biologiques (puisque nous sommes des organismes) et psychologiques (puisque nous sommes essentiellement des personnes conscientes). ==== 3.1.4 Paul Ricoeur et l'identité narrative ==== Une approche différente a été développée par le philosophe français Paul Ricoeur, qui propose le concept d'« identité narrative ». Ricoeur reconnaît que toutes les théories traditionnelles de l'identité personnelle affrontent des difficultés logiques fondamentales : elles tentent toutes de fonder l'identité sur une base objective (la continuité de substance, de conscience, ou d'organisme), alors que la réalité de l'identité personnelle est bien plus complexe et herméneutique<ref>Paul Ricoeur, ''Oneself as Another'', traduction de Kathleen Blamey, University of Chicago Press, 1992, p. 113-159</ref>. Ricoeur propose que l'identité personnelle s'établit plutôt à travers le récit que j'élabore de moi-même. Je suis la personne que je me raconte être, et cette identité narrative se constitue par la manière dont j'intègre les événements de ma vie, y compris ma conscience de ma finitude et de ma mortalité, dans une totalité cohérente<ref>Ricoeur, ''Oneself as Another'', p. 140-168</ref>. L'importance de cette approche pour la compréhension de la mort réside en ceci : ma relation à ma propre mortalité ne se réduit pas à une simple question de fait biologique ou de continuité psychologique ; elle constitue une dimension constitutive de la manière dont je me comprends moi-même en tant que sujet. La mortalité, selon Ricoeur, confère forme et sens à ma vie en lui donnant une trajectoire comprise entre naissance et mort. La conscience de ma finitude ne représente pas une simple information supplémentaire me concernant ; elle transforme de fond en comble le sens de mon identité<ref>Ricoeur, ''Oneself as Another'', p. 451-476</ref>. Cette approche narrative offre un avantage de poids : elle évite les apories des théories purement métaphysiques de l'identité en reconnaissant que l'identité personnelle constitue une construction herméneutique à la fois individuelle et collective, et qu'elle reste essentiellement liée au temps vécu et à la conscience de la finitude. === 3.2 La mort de l'autre et l'altérité irréductible === Un aspect trop souvent négligé de la philosophie de la mort concerne ma relation à la mort d'autrui, plutôt que ma relation anticipée à ma propre mort. Tandis que la tradition existentialiste insiste sur la manière dont l'anticipation de ma propre mort structure mon existence, une autre tradition philosophique, issue notamment d'Emmanuel Levinas, soutient que c'est précisément la mort de l'autre, et non la mienne, qui pose la question éthique fondamentale. ==== 3.2.1 Levinas et l'impossibilité d'approprier la mort de l'autre ==== Emmanuel Levinas, philosophe d'origine lituanienne qui a passé la majeure partie de sa vie en France, a mis en avant le caractère éminemment singulier et irréductible de la mort d'autrui. Dans son œuvre majeure ''Totalité et Infini'', Levinas critique explicitement les philosophies existentialistes (particulièrement Heidegger) qui tendent à ramener la mort à une structure constitutive de l'existence du Dasein : il n'existe, selon Levinas, aucun moyen pour moi d'anticiper ou de posséder la mort de l'autre de la même façon que je pourrais (du moins en principe) anticiper ma propre mort<ref>Emmanuel Levinas, ''Totalité et Infini. Essai sur l'Extériorité'', Martinus Nijhoff, 1961, p. 235-250</ref>. Levinas établit une distinction entre le mourir en tant que réalité que j'expérimente, acte que je pourrais en principe anticiper et intérioriser, et la mort d'autrui comme événement qui m'échappe entièrement. La mort du proche est ce qui me « résiste » de manière absolue, ce qui n'entre jamais dans le champ de ma compréhension ou de mon pouvoir<ref>Levinas, ''Totalité et Infini'', p. 238-240</ref>. Ce qui différencie foncièrement la position levinassienne de celle de Heidegger, c'est que pour Levinas, ce n'est pas ma mort qui me constitue éthiquement, mais ma responsabilité infinie face à la mort de l'autre. La vulnérabilité d'autrui face à la mort m'appelle à la responsabilité éthique. La mort possible de celui que j'aime, la fragilité absolue du proche, le fait qu'à tout moment il peut disparaître, autant de réalités qui me posent une obligation morale incontournable<ref>Emmanuel Levinas, « De la conscience à la veille » (1990), dans ''Dieu, la mort et le temps'', traduction de Michel Haerne, Grasset, 2007, p. 97-128</ref>. Cette responsabilité ne constitue pas quelque chose que j'aurais ''choisi'' de prendre, mais quelque chose auquel je suis d'emblée assigné du simple fait même de ma relation à autrui. ==== 3.2.2 Derrida et le deuil comme appropriation impossible ==== Jacques Derrida, philosophe franco-algérien qui a poursuivi certaines intuitions de Levinas, a accordé une importance philosophique centrale à la mort d'autrui, notamment à travers le phénomène du deuil. Dans son ouvrage ''Aporias'', Derrida pose des questions vertigineuses : la mort de l'autre peut-elle être anticipée ou redoutée de la même manière que ma propre mort ? N'existe-t-il pas une asymétrie entre mon rapport à ma propre mortalité et mon rapport à celle d'autrui<ref>Jacques Derrida, ''Aporias'', Galilée, 1996, p. 47-52</ref> ? Derrida établit une distinction conceptuelle fondamentale entre le « mourir » (''dying''), qui désigne mon expérience particulière de mon propre processus vers la mort, et le « périr » (''perishing''), qui désigne l'altérité absolue de l'événement de mort d'autrui. Le mourir peut posséder un caractère de ''mien'', en un sens ; le périr de l'autre ne peut jamais réellement m'appartenir, c'est précisément ce qui m'échappe de manière irréductible<ref>Derrida, ''Aporias'', p. 78-84</ref>. Cette distinction est déterminante pour comprendre le deuil : celui-ci porte essentiellement sur quelque chose d'irrémédiablement perdu et incommunicable. Derrida introduit une autre distinction conceptuelle importante : celle entre le travail du deuil (''mourning work'') et la mélancolie. Selon la tradition psychanalytique héritée de Freud, le travail du deuil consiste à progressivement désinvestir l'objet perdu pour réinvestir les relations vivantes. Cependant, Derrida soutient que ce modèle du deuil « réussi » passe sous silence quelque chose d'essentiel : la mort de la personne est unique, irremplaçable, incomparable. Aucun deuil ne peut être vraiment « complètement élaboré », car cela supposerait que la personne décédée puisse être finalement « intégrée » à mon univers psychique et émotionnel, ce qui constituerait une forme de trahison envers son absolue singularité<ref>Jacques Derrida, ''The Work of Mourning'', traduction d'Edmund Jephcott, Pascale-Anne Brault et Michael Naas, University of Chicago Press, 2001, p. 1-30</ref>. Plus précisément, Derrida soutient que le deuil doit rester « impossible » en un sens précis : il faut à la fois s'approprier d'une certaine manière la mort de celui que j'ai aimé (pour ne pas l'abandonner à l'indifférence totale) et en même temps ne pas l'approprier complètement (pour respecter son altérité absolue)<ref>Derrida, ''The Work of Mourning'', p. 169-175</ref>. Le deuil authentique oscille dans cette aporie, dans ce double lien impossible. C'est en cela que tout deuil porte en lui une dimension irréductiblement mélancolique, non pas comme pathologie psychologique, mais comme structure constitutive de la relation à celui qui meurt. ==== 3.2.3 La mort de l'autre et la transformation de mon identité ==== La mort d'autrui ne se limite pas à constituer un problème éthique abstrait ; elle bouleverse mon identité personnelle. Levinas affirme avec une force particulière que « la mort de l'autre affecte ma responsabilité »<ref>Emmanuel Levinas, ''Autrement qu'être ou au-delà de l'essence'', Martinus Nijhoff, 1974, p. 247-253</ref>. La mort d'un proche, d'une personne envers laquelle j'assumais une responsabilité, cela m'affecte ''en moi-même'', ce n'est pas une expérience que je pourrais simplement observer ou éprouver de manière neutre. La perte de celui qui meurt transforme ma relation à moi-même. Je ne suis plus la même personne après la mort de quelqu'un qui m'était cher. Mais cette transformation ne se réduit pas à une simple modification psychologique, ni même essentiellement affective, elle est d'abord éthique. J'ai perdu un vis-à-vis, quelqu'un à qui je devais rendre des comptes. Cette perte redéfinit constitutionnellement ce que je suis<ref>Paul Ricoeur, ''La Mémoire, l'Histoire, l'Oubli'', Éditions du Seuil, 2000, p. 523-538</ref>. Le deuil, dans cette perspective, ne constitue pas simplement un travail psychologique de séparation et d'élaboration ; il s'agit d'une reconstitution fondamentale de mon identité en l'absence de celui qui en était une part essentielle. ==== 3.2.4 La singularité irremplaçable de chaque mort ==== Une dernière dimension de l'importance philosophique de la mort de l'autre concerne sa singularité absolue et irremplaçable. Derrida insiste avec persistance sur le fait que chaque mort est unique, incomparable, singulière. Face à la mort de celui qu'on aime, ce que nous éprouvons c'est que « avec sa mort, c'est un monde entier qui disparaît »<ref>Derrida, ''The Work of Mourning'', p. 322-325</ref>. Cette affirmation peut sembler exagérée, car bien entendu le monde continue physiquement après la mort d'une personne. Mais Derrida entend souligner que du point de vue éthique et existentiel, quelque chose d'irréversible s'effondre. Cette singularité de chaque mort crée une tension philosophique majeure. D'un côté, nous cherchons à honorer la mémoire des morts en les intégrant à une histoire collective, à un récit communautaire qui préserve leur mémoire. De l'autre côté, cette intégration comporte un risque significatif : celui de « normaliser » ce qui était unique en son genre, de réduire le mort à une place dans une série identique<ref>Derrida, ''The Work of Mourning'', p. 140-160</ref>. C'est pourquoi le deuil authentique doit naviguer dans cette tension irrésolue : reconnaître l'unicité incomparable du disparu tout en le gardant présent dans la communauté des vivants, sans jamais complètement l'assimiler. Cette question de la singularité de chaque mort rejoint une dimension essentielle de ma relation à mon identité personnelle : je suis moi aussi unique et incomparable, et ce que je redoute dans la mort, c'est peut-être moins la perte abstraite de conscience que la cessation de cette singularité particulière qui est précisément la mienne. L'impossibilité pour autrui de me sauver de ma propre mort, tout comme mon impossibilité à sauver celui que j'aime de sa mort, constituent deux faces d'une même condition humaine : nous sommes chacun seul face à notre mort, dans une solitude sans partage. Et c'est paradoxalement cette solitude partagée qui constitue le fondement même de notre communauté éthique. == IV. Existentialisme et finitude == === 4.1 Martin Heidegger et l'être-vers-la-mort === La compréhension existentialiste de la mort s'enracine étroitement dans l'œuvre majeure de Martin Heidegger, ''Être et Temps'' (1927). Heidegger pose une question apparemment simple mais philosophiquement centrale : qu'est-ce que vivre authentiquement ? Sa réponse s'articule autour du concept du ''Sein-zum-Tode'', l'« être-vers-la-mort », qui ne constitue point une morbide obsession pour la mort, mais une élucidation fondamentale de ce que signifie exister en tant qu'être humain<ref>Martin Heidegger, ''Sein und Zeit'' (1927), traduction française de François Vezin, Gallimard, 1986, divisions II et sections 46-53, p. 279-304</ref>. Heidegger établit d'abord une distinction capitale entre le ''Dasein'' (littéralement « être-là »), terme qu'il utilise pour désigner spécifiquement l'existence humaine, et les autres formes d'être. Ce qui caractérise uniquement le Dasein, c'est que son être-même reste constamment une question pour lui. Tandis que les choses inanimées simplement sont, et tandis que les animaux existent selon des instincts programmés, le Dasein est l'étant pour lequel il y va, en son être, de cet être même : il a à être ce qu'il est<ref>Heidegger, ''Sein und Zeit'', Introduction, p. 9-20</ref>. C'est précisément dans cette ouverture à la mort que réside l'authenticité de l'existence. Heidegger affirme que la mort se situe à l'horizon de toute existence humaine, mais que nous la fuyons généralement. Dans la vie quotidienne, nous nous perdons dans le « On », ce que nous pourrions appeler le « on-dit », la doxa, la sagesse populaire partagée, et nous nous laissons absorber dans les préoccupations de la routine. Le Dasein se disperse dans ce qu'il fait, ce qu'il pense, ce que tout le monde pense<ref>Heidegger, ''Sein und Zeit'', section 27, p. 153-164</ref>. Heidegger énonce quatre caractéristiques fondamentales de la mort envisagée existentialement. Elle est d'abord « non-relationnelle » (unbeziehbar), nul ne peut mourir à ma place, car ma mort reste rigoureusement singulière et insubstituable. Ensuite, elle est « certaine », nous savons avec une certitude indubitable que nous mourrons. Elle est aussi « indéfinie », bien que la mort soit certaine, nous ignorons quand elle surviendra. Enfin, elle est « insurpassable » (unüberholbar), aucune possibilité future ne peut dépasser ou surpasser la mort, car elle termine toutes les possibilités<ref>Heidegger, ''Sein und Zeit'', section 50, p. 293-299</ref>. Mais pourquoi cette analyse minutieuse de la mort revêt-elle une importance ontologique pour Heidegger ? Parce que la conscience de la mort, loin de paralyser l'existence, la libère en réalité pour une authenticité. Confronté à la certitude absolue de sa mort, le Dasein peut se « ressaisir » face au flux inauthentique de la vie quotidienne. Cette prise de conscience s'accompagne généralement d'une émotion caractéristique que Heidegger appelle l'« angoisse » (Angst), non la peur devant un objet spécifique, mais plutôt une tonalité affective originaire face au néant et à la liberté<ref>Heidegger, ''Sein und Zeit'', section 40, p. 227-231</ref>. [[Dictionnaire de philosophie/Angoisse|L'angoisse]], pour Heidegger, ne constitue point une pathologie, elle demeure salutaire. Elle arrache le Dasein à son immersion commode dans les préoccupations triviales et le confronte à la nudité de son existence. En expérimentant cette angoisse face à sa propre finitude, le Dasein découvre ce que Heidegger appelle sa « possibilité la plus extrême ». Cette possibilité, c'est précisément de vivre en constante anticipation de la mort, non par morbidité, mais comme principe d'organisation de l'existence authentique<ref>Heidegger, ''Sein und Zeit'', sections 30-31, p. 176-189</ref>. Cette « anticipation authentique de la mort » (eigentliches Vorlaufen-zu-Tode) constitue ce que Heidegger appelle la « résolution authentique » ou « authenticité » (Eigentlichkeit). Elle ne paralyse point l'existence ; au contraire, elle nous permet de vivre de manière résolue, d'accepter nos responsabilités avec une lucidité nouvelle, et de nous approprier notre propre existence plutôt que de simplement la subir passivement<ref>Heidegger, ''Sein und Zeit'', section 53, p. 304-314</ref>. === 4.2 Jean-Paul Sartre : la liberté face à la facticité et la mort === Jean-Paul Sartre, bien qu'influencé par Heidegger, apporte une perspective toute différente sur la mort et l'existence. Le principe fondamental du système sartresque repose sur l'affirmation que « [[Dictionnaire de philosophie/Existence|l'existence]] précède l'essence », proposition qui inverse complètement la tradition métaphysique occidentale<ref>Jean-Paul Sartre, ''L'existentialisme est un humanisme'' (1945), Éditions Nagel, 1966, p. 15-49</ref>. Selon Sartre, aucune essence humaine fixe ne préexiste à notre entrée dans l'existence. Nous venons à l'existence d'abord, et ce n'est qu'ensuite, par nos choix et nos actions, que nous créons notre essence et définissons ce que nous sommes. Il n'existe pas de « nature humaine » en attente de réalisation ; il n'existe que la tâche constante de nous créer nous-mêmes<ref>Sartre, ''L'existentialisme est un humanisme'', p. 45-49</ref>. Cette liberté, toujours prise dans une situation concrète, engendre ce que Sartre appelle une « responsabilité absolue ». Nous sommes « condamnés à être libres », c'est-à-dire que nous ne pouvons nous échapper à la nécessité de choisir et de créer notre essence. Aucune instance divine, aucune nature fixe, aucune détermination externe ne peut nous exonérer de cette responsabilité<ref>Sartre, ''L'Être et le Néant'', Gallimard, 1943, p. 9-60</ref>. Comment la mort s'inscrit-elle dans cette philosophie de la liberté absolue ? Ici, Sartre adopte une position critique envers l'approche heideggérienne. Pour Sartre, la mort ne constitue pas une structure fondamentale de l'existence, c'est plutôt un fait brut, une contingence qui met fin à la possibilité d'existence sans pour autant structurer l'existence elle-même. Sartre affirme que « la mort n'est jamais ce qui donne sens à la vie ; c'est au contraire ce qui enlève tout sens à la vie »<ref>Sartre, ''L'Être et le Néant'', p. 615-617</ref>. Cette affirmation peut sembler étrange, mais elle exprime une intuition importante : contrairement à Heidegger qui voit dans la mort un principe d'organisation pour une vie authentique, Sartre soutient que la mort est simplement ce qui intervient du dehors, cessant abruptement toute possibilité de création de sens<ref>Sartre, ''L'Être et le Néant'', p. 619-623</ref>. Donc, plutôt que de nous interroger sur « comment vivre authentiquement en vue de la mort », nous devrions nous interroger sur « comment créer du sens et des valeurs dans une existence absurde qui sera inévitablement terminée »<ref>Sartre, ''L'existentialisme est un humanisme'', p. 37-44</ref>. Pour Sartre, la vraie question n'est donc pas celle de la finitude face à la mort, mais celle de la liberté face à la facticité, c'est-à-dire face aux conditions concrètes données de notre existence (notre classe sociale, notre époque historique, notre corps, etc.). Notre liberté consiste à transcender cette facticité, à la dépasser vers des projets futurs, à nous créer dans et par rapport à ces conditions<ref>Sartre, ''L'Être et le Néant'', p. 568-580</ref>. === 4.3 Søren Kierkegaard : l'angoisse comme condition de la liberté === Bien que Kierkegaard soit antérieur au mouvement existentialiste proprement dit, ses analyses de l'angoisse et de la liberté constituent une source majeure pour les existentialistes modernes. Dans son ouvrage ''Le Concept d'angoisse'' (1844), Kierkegaard propose une analyse psychologique et métaphysique de cette émotion première<ref>Søren Kierkegaard, ''Le Concept d'angoisse'', traduction de Knud Ferlov et Jean-J. Gateau, Éditions Gallimard, 1990, p. 45-120</ref>. Kierkegaard distingue soigneusement entre la « peur » et l'« angoisse ». La peur porte toujours sur quelque chose de spécifique, on a peur d'un chien, d'une maladie, d'une blessure physique. L'angoisse, en contraste, ne porte sur rien de précis. Elle constitue plutôt l'émotion devant la pure possibilité, devant la liberté elle-même et ses implications infinies<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 70-75</ref>. Kierkegaard illustre cette distinction par une image frappante. Un homme se tient au bord d'un précipice. Il craint certes de tomber, c'est une peur naturelle et rationnelle. Mais il éprouve aussi l'angoisse en réalisant qu'il reste libre de sauter. Rien dans le monde physique ne l'empêcherait de se jeter dans le vide si telle était sa volonté. C'est cette conscience de sa propre liberté, de cette possibilité absolue face à l'abîme, qui constitue l'angoisse, ce que Kierkegaard appelle « le vertige de la liberté »<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 61-65</ref>. Cruciale est l'observation de Kierkegaard selon laquelle cette angoisse ne constitue pas simplement un défaut à corriger, mais une dimension intrinsèque et inévitable de l'existence humaine. Chaque être conscient, chaque entité pourvue de liberté, doit expérimenter l'angoisse. Car la liberté elle-même consiste en la conscience d'une multiplicité infinie de possibilités, dont aucune n'est garantie, dont aucune ne s'impose avec une nécessité absolue<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 45-50</ref>. Or, cette angoisse est étroitement liée chez Kierkegaard à la conscience de la mort. Pourquoi ? Parce que la mort représente la limite absolue de ma liberté, le moment où l'ensemble des possibilités qui se déploient devant moi s'effondrera et prendra fin. La conscience de cette possibilité ultime de ne-plus-être confère à ma liberté une intensité particulière et une responsabilité accablante. Je dois choisir ma vie, créer mon essence, décider de mon être, sachant qu'une fin certaine viendra mettre un terme à ce processus<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 113-120</ref>. Pour Kierkegaard, l'angoisse peut mener à deux chemins opposés : ou bien elle inspire le désespoir, la démission face à la liberté, le refuge dans des certitudes factices, ou bien elle devient le catalyseur d'une existence authentique fondée sur la foi et la passion<ref>Kierkegaard, ''Étapes de la vie'', traduction de Jean-J. Gateau, Éditions Gallimard, 1943, p. 340-360</ref>. === 4.4 Albert Camus et la révolte face à l'absurde === Albert Camus, bien qu'il rejette l'étiquette d'« existentialiste » (notamment en raison de ses désaccords avec Sartre), offre une réflexion existentielle majeure sur la mort envisagée comme source de l'absurde. Dans son essai ''Le Mythe de Sisyphe'' (1942), Camus énonce une thèse frappante : « Il n'y a qu'un seul problème philosophique vraiment sérieux : c'est le suicide »<ref>Albert Camus, ''Le Mythe de Sisyphe'', Gallimard, 1942, p. 13-18</ref>. Cette affirmation peut sembler extrême, mais elle exprime une vérité existentielle profonde. Car si l'existence demeure absurde, c'est-à-dire si elle se confronte à une contradiction insurmontable entre nos exigences rationnelles et un univers qui reste par essence irrationnel, alors à quoi bon vivre ? Si nos vies sont destinées au néant, si tous nos projets, nos aspirations, nos créations finiront dans l'oubli et le silence de la mort, quel sens peuvent-ils posséder<ref>Camus, ''Le Mythe de Sisyphe'', p. 25-45</ref> ? Camus identifie trois réponses possibles à ce problème. Première réponse : le suicide physique, qui consiste à céder face au sentiment d'absurdité en mettant fin à sa propre vie. Seconde réponse : le « suicide philosophique », qui consiste à s'échapper dans la foi religieuse ou dans une philosophie qui promet un absolu, que ce soit Dieu, l'Idée, la Raison. Ces deux options, selon Camus, échouent : le suicide physique annule simplement la possibilité même d'existence ; le suicide philosophique constitue une forme de déshonnêteté envers la réalité<ref>Camus, ''Le Mythe de Sisyphe'', p. 47-80</ref>. Mais existe une troisième voie : la révolte. Camus propose d'« imaginer Sisyphe heureux ». Sisyphe, cet être mythologique condamné à repousser éternellement un rocher qui retombe toujours, devient pour Camus le symbole du héros absurde. Il ne se suicide point ; il ne s'échappe point non plus dans l'illusion d'une signification cosmique. Au lieu de cela, il accepte pleinement l'absurdité de sa condition, il reconnaît que ses efforts restent vains, que le rocher retombera toujours, mais il persiste néanmoins. Il accepte la lutte, non en espérant qu'elle produise un résultat final satisfaisant, mais pour la simple raison que vivre, persister, lutter constituent la réalité de l'existence<ref>Camus, ''Le Mythe de Sisyphe'', p. 168-180</ref>. Cette position camussienne face à la mort diffère significativement de celle de Heidegger. Pour Camus, il ne s'agit pas de se projeter authentiquement vers la mort pour donner une structure à l'existence. Au contraire, il s'agit de reconnaître clairement le caractère brut et inintelligible de la mort, et pourtant de continuer à vivre avec passion, solidarité et lucidité. La mort demeure un scandale, une injustice même, mais cette injustice ne nous autorise point à cesser d'exister<ref>Camus, ''Le Mythe de Sisyphe'', p. 120-140</ref>. === 4.5 Karl Jaspers et les « situations limites » === Karl Jaspers, philosophe allemand qui a influencé à la fois Heidegger et Sartre, apporte une perspective distincte sur la mort en la situant dans le contexte plus large de ce qu'il appelle les « situations limites » (Grenzsituationen). Ces situations constituent des moments où les limites de la compréhension rationnelle se heurtent à l'inévitable : la mort, la souffrance, la culpabilité, le hasard<ref>Karl Jaspers, ''Introduction à la pensée philosophique'', traduction d'Yvon Belaval, Éditions 10/18, 1970, p. 40-65</ref>. Jaspers établit une distinction importante entre deux significations de la mort. D'abord, la mort est un fait objectif, la cessation des fonctions vitales, une réalité biologique. Ensuite, la mort constitue une situation limite existentielle, une expérience que je dois affronter personnellement, qui me concerne d'une manière unique et irremplaçable<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 45-50</ref>. C'est précisément cette deuxième dimension qui revêt une importance existentielle cardinale. Confronté à sa propre finitude, à la conscience de sa propre mort, l'être humain peut soit se perdre davantage dans l'inauthenticité, soit accéder à un niveau plus profond d'existence que Jaspers appelle ''Existenz'', une forme d'auto-conscience critique et de transcendance<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 55-65</ref>. Pour Jaspers, c'est justement dans l'expérience authentique des situations limites que l'individu accède à ce qu'il appelle la « transcendance ». Cette transcendance ne signifie point un dépassement métaphysique vers un autre monde, mais plutôt une conscience aiguë de la « Totalité » englobante au sein de laquelle mon existence particulière trouve son sens relatif<ref>Jaspers, ''Introduction à la pensée philosophique'', p. 65-80</ref>. === 4.6 Simone de Beauvoir : mort, liberté et éthique de l'ambiguïté === Simone de Beauvoir offre une perspective existentialiste qui intègre les questions de genre, de liberté concrète et de responsabilité éthique. Dans son ouvrage ''Éthique de l'ambiguïté'' (1947) et son monumental ''Le Deuxième Sexe'' (1949), Beauvoir affirme que la liberté est la valeur normative première de toute éthique existentielle<ref>Simone de Beauvoir, ''Éthique de l'ambiguïté'', Éditions Gallimard, 1947, p. 9-30</ref>. Comment la mort s'inscrit-elle dans cette éthique de la liberté ? Beauvoir soutient que la mort, loin de constituer une structure ontologique donnant sens à l'existence comme chez Heidegger, représente plutôt une limite arbitraire imposée du dehors. Mais cette limite n'anéantit pas la liberté ; elle la redéfinit. La liberté consiste à créer du sens, à poursuivre des projets, à s'engager dans la construction d'un monde plus juste, tout en sachant que cette liberté reste finie, que cette création de sens sera finalement interrompue<ref>Beauvoir, ''Éthique de l'ambiguïté'', p. 40-60</ref>. Ce qui distingue Beauvoir des autres existentialistes, c'est son insistance sur le fait que cette liberté ne reste pas abstraite. Elle se fait concrète, incarnée, et inégalement distribuée parmi les êtres humains. Les femmes, les opprimés, les marginalisés se voient souvent refuser l'accès aux formes d'existence que les existentialistes masculins envisagent comme naturelles ou universelles<ref>Simone de Beauvoir, ''Le Deuxième Sexe'', tome I, Éditions Gallimard, 1949, p. 13-32</ref>. Beauvoir affirme que « l'on ne naît pas femme, on le devient », formule qui exprime en microcosme sa pensée : aucune essence féminine fixe n'existe, aucune nature donnée une fois pour toutes. Au lieu de cela, la féminité est une condition historiquement construite et socialement imposée. Mais puisque cette condition ne s'inscrit pas dans la nature, elle peut être transformée par une action libre et consciente<ref>Beauvoir, ''Le Deuxième Sexe'', tome I, p. 13-18</ref>. Quant à la mort, Beauvoir en reconnaît le caractère terrible et absurde. Mais elle refuse de permettre que cette absurdité justifie l'oppression, la domination ou le refus de reconnaître la liberté d'autrui. Au contraire, c'est précisément en raison de l'inévitabilité de la mort que nous devons créer de la solidarité, de la justice, de la fraternité pendant que nous vivons. La mort impose une urgence éthique à nos actions<ref>Beauvoir, ''Éthique de l'ambiguïté'', p. 115-145</ref>. === 4.7 Les thèmes transversaux de l'existentialisme face à la mort === Malgré les différences substantielles entre ces penseurs, certains thèmes existentialistes récurrents concernant la mort et la finitude émergent avec netteté : ''L'authenticité contre l'inauthenticité :'' Plusieurs philosophies de l'existence reviennent à une opposition entre une vie assumée et une vie fuyante, même si elles ne donnent pas toutes le même sens à l'authenticité. L'inauthenticité consiste généralement à fuir la responsabilité, à se réfugier dans les rôles sociaux prédéfinis, à nier la nécessité de créer sa propre essence. La mort, par sa certitude et son caractère inévitable, pose à chaque individu la question de savoir s'il vivra authentiquement ou s'il continuera de fuir<ref>Heidegger, ''Sein und Zeit'', sections 38-41, p. 214-225</ref>. ''L'angoisse existentielle :'' L'angoisse ne constitue point une pathologie à traiter mais une révélation existentielle salutaire. Elle exprime la conscience de la liberté sans entraves, la réalité de la contingence humaine, et la responsabilité absolue face à l'absence de fondement stable. C'est précisément dans l'expérience de l'angoisse que l'existant accède à la vérité de sa condition<ref>Kierkegaard, ''Le Concept d'angoisse'', p. 61-70</ref>. ''La singularité et l'irremplaçabilité :'' Ma mort reste pleinement mienne. Elle ne peut être confiée à personne d'autre, elle ne peut être vécue qu'en première personne. Cette singularité absolue me constitue en tant qu'individu unique et irremplaçable. Elle fonde une forme d'égalité originelle : devant la mort, tous les êtres humains se trouvent dans une situation métaphysiquement identique<ref>Camus, ''Le Mythe de Sisyphe'', p. 23-25</ref>. ''L'absence de fondement justificatif :'' L'univers ne fournit aucune justification à l'existence. Il n'existe pas de « pourquoi » cosmique qui expliquerait notre présence dans le monde. Cette absence de fondement définit précisément la condition absurde, et c'est cette absence qui confère une responsabilité absolue : si rien ne justifie notre existence de l'extérieur, nous devons créer cette justification de l'intérieur, par nos actions et nos choix<ref>Sartre, ''L'Être et le Néant'', p. 76-90</ref>. En conclusion, l'approche existentialiste de la mort refuse de la traiter comme un simple problème technique ou biologique. Elle la conçoit plutôt comme le moment de révélation par excellence où la vérité de l'existence humaine, sa liberté, sa responsabilité, son absurdité, sa dignité, se manifeste avec la plus grande clarté. Loin de constituer une réflexion morbide, la philosophie existentialiste de la mort invite à vivre plus authentiquement, plus lucidement, plus librement. == V. Dimensions éthiques et axiologiques == === 5.1 L'autonomie et le « droit de mourir » === La question du rapport entre autonomie et mort soulève des enjeux éthiques majeurs. La notion d'autonomie, entendue comme la capacité et le droit de chaque individu à orienter sa propre existence en accord avec ses valeurs, s'est imposée au cœur de la bioéthique contemporaine, notamment dans les débats relatifs à l'euthanasie et à l'assistance médicale à mourir<ref>Tom L. Beauchamp et James F. Childress, ''Principles of Biomedical Ethics'', Oxford University Press, 7e éd., 2013, p. 101-150</ref>. Les partisans d'un « droit de mourir » soutiennent que le respect de l'autonomie implique de reconnaître à chacun la faculté de décider des conditions de sa fin de vie, notamment le refus de traitements prolongeant artificiellement l'existence ou, là où la loi l'autorise, la demande d'une assistance médicale pour hâter la mort<ref>Ronald Dworkin, ''Life's Dominion'', Knopf, 1993, p. 190-237</ref>. Cette position repose sur un principe fondamental : il revient à chaque personne de déterminer le sens et la valeur de sa propre vie. Il serait dès lors contraire au respect d'imposer une manière de mourir qui contredit les convictions et les préférences de cette personne<ref>Beauchamp et Childress, ''Principles of Biomedical Ethics'', p. 135-140</ref>. Cette invocation de l'autonomie soulève néanmoins plusieurs difficultés. D'abord, le caractère réellement autonome de la demande d'aide à mourir reste problématique : lorsqu'une personne souffre intensément, déprimée, se vit comme un fardeau pour ses proches, peut-on raisonnablement tenir sa demande pour entièrement libre de pressions, explicites ou implicites<ref>Alexandra Mullock et Jonathan Lewis, « Assisted Dying, Vulnerability, and the Potential Value of Prospective Legal Authorization », ''Medical Law Review'', vol. 33, n° 2, 2025, article fwaf014</ref> ? Ensuite, même à supposer la demande authentiquement autonome, reste à déterminer si l'autonomie individuelle suffit à justifier l'intervention d'un tiers, le médecin, pour provoquer la mort, ou si d'autres considérations (protection des plus vulnérables, rôle de la médecine, répercussions sociales) doivent aussi entrer en compte<ref>Helga Kuhse et Peter Singer (dir.), ''A Companion to Bioethics'', Blackwell, 2009, p. 314-325</ref>. Plusieurs auteurs dénoncent un « autonomisme » excessif dans la [[Dictionnaire de philosophie/Bioéthique|bioéthique]] contemporaine, c'est-à-dire une surestimation du rôle que devrait jouer l'autonomie dans les décisions de fin de vie. Ils observent que l'autonomie n'existe jamais en isolation : elle s'exerce toujours prise dans des réseaux d'inégalités, de vulnérabilités et de rapports de pouvoir<ref>Mullock, « Assisted Dying, Vulnerability… », p. 12-18</ref>. Lorsque des personnes pauvres, sans domicile fixe, gravement handicapées ou incarcérées demandent à mourir, il devient nécessaire de se demander si cette demande reflète un choix authentiquement libre, ou si elle résulte de conditions sociales si désastreuses que la société aurait pu et dû améliorer<ref>Rebecca Dresser et Peter Singer, « Euthanasia and the Question of Justice », dans ''Choices at the End of Life'', 2002, p. 82-104</ref>. === 5.2 Dignité, qualité de vie et valeur de la vie === Le concept de « mort digne » revient constamment dans les débats bioéthiques sur l'euthanasie et l'assistance médicale à mourir. Ceux qui défendent ces pratiques soutiennent qu'il importe de permettre à chacun de mourir selon sa propre conception de la dignité, que refuser cette possibilité constituerait une atteinte à la valeur fondamentale de la personne<ref>Michael Tooley, Celia Wolf-Devine et James W. Diamond (dir.), ''Physician-Assisted Suicide: Expanding the Debate'', Routledge, 1997, p. 201-232</ref>. Mais que signifie exactement « mourir avec dignité » ? S'agit-il de conserver la maîtrise de ses décisions et de son corps jusque dans la mort ? De ne pas endurer une souffrance extrême ? Ou bien d'une valeur inconditionnelle, inhérente au seul fait d'être une personne, indépendamment de l'état physique ou mental<ref>Stephen Richards, « The Morality of Assisted Dying », ''The Journal of Medicine and Philosophy'', vol. 50, n° 4, 2025, p. 262-284</ref> ? Une longue tradition philosophique et juridique défend cette dernière conception : la dignité humaine serait intrinsèque, inaliénable, et ne pourrait donc ni se perdre ni se gagner. Une existence marquée par la douleur, la dépendance physique ou la démence ne serait pas, en elle-même, « indigne », car la dignité ne se mesure ni à la performance physique, ni au fonctionnement autonome, ni à la lucidité mentale<ref>Lydia Dugdale, ''The Lost Art of Dying'', Harper Wave, 2020, p. 145-180</ref>. Les partisans du droit à l'assistance au mourir rétorquent que cette approche, bien qu'elle protège contre les jugements méprisants sur la valeur des vies fragiles, risque de devenir insensible à la souffrance concrètement vécue. Ils observent aussi qu'une distinction entre dignité ontologique (égale pour tous) et dignité existentielle (comment se déploient les derniers moments d'une vie) s'impose : la manière dont s'écoulent les derniers instants influe sur le sens que l'existence entière revêt, rétrospectivement, pour la personne mourante et pour les proches<ref>Ronald Dworkin, ''Life's Dominion'', p. 187-240</ref>. === 5.3 Justice, équité et accès aux soins de fin de vie === Une dimension moins médiatisée mais politiquement névralgique concerne la justice et l'équité dans l'accès aux soins de fin de vie. Tandis que les débats théoriques portent volontiers sur l'euthanasie en contextes où une offre médicale existe déjà, la réalité révèle un scandale plus fondamental : l'inégalité d'accès aux soins palliatifs, au soulagement de la douleur et à l'accompagnement des mourants<ref>Marissa T. French et alii, « Exploring Socioeconomic Inequities in Access to Palliative and End-of-Life Care in the UK », ''Palliative Medicine'', vol. 35, n° 10, 2021, p. 1843-1856</ref>. Les personnes sans domicile, les détenus, les migrants sans statut légal et même certains patients souffrant de troubles psychiatriques graves restent largement écartés de dispositifs permettant un mourir apaisé, entouré, médicalement et humainement accompagné<ref>Kelli Stajduhar et Merryn Gott, « Closing the Health Equity Gap in Palliative Care: The Time for Action Is Now », ''Palliative Medicine'', vol. 37, n° 4, 2023, p. 424-425</ref>. L'accès à un « bon mourir » reste un privilège socioéconomique. Il en résulte une dissonance morale frappante : promouvoir un « droit à mourir » là où n'est pas garanti un droit effectif à bien vivre jusqu'au bout. Tant que l'accès universel à des soins palliatifs de qualité, à la prise en charge de la douleur et au soutien psychosocial n'est pas assuré, existe le risque que l'assistance médicale à mourir ne devienne une réponse aux carences sociales plutôt que l'expression d'un choix existentiel mûrement réfléchi<ref>Leon R. Kass, « 'I Will Give No Deadly Drug': Why Doctors Must Not Kill », dans ''The Case Against Physician-Assisted Suicide'', 2002, p. 17-39</ref>. === 5.4 Vulnérabilité, dépendance et éthique du care === Une éthique contemporaine de la vulnérabilité et du care rappelle que la dépendance ne constitue pas une anomalie réservée à certains groupes fragiles, mais une condition humaine universelle. Tout être humain se trouve exposé à la maladie, à l'accident, à la précarité du corps et, finalement, à la mort<ref>Martha Albertson Fineman, ''The Autonomy Myth: A Theory of Dependency'', The New Press, 2004, p. 1-30</ref>. L'éthique du care propose de déplacer le centre de gravité : au lieu de prendre l'individu abstraitement autonome comme modèle, elle met au premier plan les relations concrètes de soin, l'interdépendance et la responsabilité mutuelle. Personne ne meurt « seul » au sens existentiel : chaque mort affecte un tissu humain de proches, interpelle une communauté, suppose un ensemble de gestes, de présences, de paroles<ref>Nel Noddings, ''Caring: A Feminine Approach to Ethics and Moral Education'', University of California Press, 2e éd., 2003, p. 142-175</ref>. Dans cette perspective, les questions de fin de vie ne sauraient se réduire à un conflit binaire entre le « droit individuel » et les « interdits collectifs ». Il convient de tenir compte des responsabilités relationnelles, des liens de soin qu'il faut entretenir ou créer, et de ce que signifie pour une communauté d'accueillir et de soutenir ses mourants<ref>Siv Maj Jämterud, « Acknowledging Vulnerability in Ethics of Palliative Care », ''Nursing Ethics'', vol. 29, n° 2, 2022, p. 335-347</ref>. La vulnérabilité n'est pas un simple motif de protection paternaliste : elle constitue le point de départ d'une éthique de l'attention mutuelle. === 5.5 Finitude, signification de la vie et axiologie de la mort === Du point de vue axiologique, la mort ne se réduit pas à un « problème » moral qu'il faudrait encadrer. Elle joue un rôle de premier plan dans la valeur que peut prendre une vie. Une part importante de la philosophie contemporaine soutient que la finitude n'appauvrit pas nécessairement la signification de l'existence ; elle en constitue plutôt une condition<ref>Liudmila Baeva, ''Existential Axiology: A New Philosophical Paradigm'', Routledge, 2013, p. 1-40</ref>. Thaddeus Metz a défendu l'idée qu'une vie sans terme imaginable, infinie et interminable, perdrait une bonne part de ce qui rend l'existence précieuse : l'urgence des choix, la nécessité de hiérarchiser les projets, la conscience que tout ne pourra pas être accompli<ref>Thaddeus Metz, « The Meaning of Life », ''Stanford Encyclopedia of Philosophy'', 2021, sections 3-4</ref>. C'est précisément la finitude qui confère à l'amitié, l'amour, le travail créateur ou la quête de justice leur poids particulier. La reconnaissance lucide de la mortalité invite à une réorientation des priorités morales. Au lieu de rêver d'abolir la mort, ou de s'absorber exclusivement dans la maîtrise technique de ses modalités, il s'agit de se demander ce qui mérite d'être accompli dans le temps qui nous échoit : quels liens tisser, quelles œuvres entreprendre, quelle empreinte laisser<ref>Jonathan Noonan, « Mortality, Finitude, and Meaningful Lives », ''Journal of Philosophy of Life'', vol. 3, n° 1, 2013, p. 5-41</ref>. === 5.6 Responsabilité collective et conditions sociales du mourir === Enfin, la mort n'est jamais seulement affaire de choix privés. Elle reste inséparable de structures institutionnelles, de politiques publiques et d'allocations budgétaires. La manière dont on meurt dans une société dépend de systèmes de santé, de régimes d'assurance, de normes professionnelles, mais aussi de politiques de logement, de lutte contre la pauvreté, d'accompagnement du grand âge<ref>Courtney S. Campbell, « Mortal Responsibilities: Bioethics and Medical-Assisted Dying », ''Yale Journal of Biology and Medicine'', vol. 92, n° 4, 2019, p. 733-739</ref>. Il est révélateur que les pays ayant légalisé les formes les plus étendues d'assistance médicale à mourir (Pays-Bas, Belgique, Canada, certaines provinces australiennes) disposent tous d'un accès universel à des soins de santé de base<ref>Campbell, « Mortal Responsibilities… », p. 735-736</ref>. À l'inverse, il apparaît moralement troublant qu'une société qui ne garantit pas à tous un accès minimal aux soins puisse se prévaloir d'avoir légalisé la mort médicalement provoquée comme une avancée bioéthique majeure. Une éthique responsable de la mort exige que l'on dépasse la seule question : « Qu'ai-je le droit de décider pour moi-même ? ». Elle impose de se demander aussi : « Quelles conditions de vie créons-nous pour les vivants et pour les mourants ? » ; « Quelles vies estimons-nous suffisamment dignes pour être soutenues, accompagnées, soignées jusqu'au bout » ? Ces interrogations collectives ne peuvent rester sans réponse<ref>Stajduhar et alii, « Equity-Focused Palliative and End-of-Life Care… », p. 125-138</ref>. Dans cette perspective, l'enjeu ultime n'est pas d'opposer abstraitement un « droit de mourir » à un « devoir de vivre », mais de faire en sorte que chacun puisse vivre et mourir dans un cadre où l'assistance à la mort ne remplace jamais l'obligation collective de soulager la misère, la solitude et l'abandon. == VI. La mort et le sens de la vie == === 6.1 L'immortalité comme malédiction : la théorie de l'ennui infini === L'une des questions les plus intrigantes que pose la philosophie de la mort concerne l'hypothèse contrefactuelle (contraire aux faits) suivante : serait-il bon de vivre éternellement ? Au premier abord, cette question semble relever du domaine des jeux de l'esprit, mais elle révèle en réalité des enjeux profonds concernant la relation entre finitude et sens. Bernard Williams, philosophe analytique contemporain, a défendu une position controversée : contrairement à ce que l'on pourrait attendre, vivre éternellement serait en réalité indésirable<ref>Bernard Williams, « The Makropulos Case: Reflections on the Tedium of Immortality » (1973), dans ''Problems of the Self'', Cambridge University Press, 1973, p. 82-100</ref>. Williams prend appui sur la pièce de théâtre de Karel Čapek ''La Vie de Madame Macropulos'', où l'héroïne, qui a vécu trois cents ans grâce à un élixir, découvre que la vie immortelle devient irrémédiablement ennuyeuse. L'argument de Williams procède ainsi : d'une part, ce qui donne sens à nos projets et à nos engagements, c'est notamment leur caractère temporellement limité et urgent ; d'autre part, une vie infinie serait nécessairement monotone, car il n'y aurait jamais vraiment de nouvelles expériences (après un temps suffisamment long, tout s'épuiserait et se répéterait), ou bien nous devrions constamment avoir oublié nos expériences passées pour préserver l'impression de nouveauté (ce qui reviendrait à une discontinuité de la conscience et de l'identité)<ref>Bernard Williams, « The Makropulos Case », p. 88-99</ref>. Simone de Beauvoir avait déjà exploré cette possibilité dans ses analyses de l'ennui, affirmant que la mort, paradoxalement, peut être un bienfait en tant qu'elle introduit une limite nécessaire à l'existence<ref>Simone de Beauvoir, ''Tout compte fait'', Gallimard, 1972, p. 308-315</ref>. Cette position remet en question l'idée commune selon laquelle la mort serait un mal absolu qu'il faudrait à tout prix surmonter. Cependant, cette théorie a été vigoureusement contestée. Certains philosophes soutiennent que Williams confond l'immortalité corporelle avec une immortalité qui permettrait l'oubli régulier, ou que sa conception de l'ennui est trop restrictive<ref>Donald Bruckner, « Against the Tedium of Immortality », dans ''Journal of Philosophy'', vol. 109, n° 11, 2012, p. 628-645</ref>. D'autres objectent que nous ne pouvons tout simplement pas savoir ce que serait une vie infinie et que par conséquent cet argument reste hautement spéculatif. === 6.2 La mort comme condition de signification === Une autre approche insiste sur le lien constitutif entre finitude et signification. Ce qui nous motive, ce qui nous donne direction, c'est précisément le fait que le temps nous manque, que nos jours sont comptés. Heidegger lui-même en fait un élément central de sa pensée : c'est la conscience de ma mortalité qui me permet de ''vraiment'' décider, de ''vraiment'' m'engager dans un projet, plutôt que de vivre passivement au jour le jour<ref>Heidegger, ''Sein und Zeit'', § 67-72</ref>. De plus, la mort de l'autre donne sens à notre solidarité, à notre compassion. Si personne ne mourait, la distinction entre vraie bienveillance et simple échange utilitaire s'estomperait. Nos engagements les plus profonds envers les autres, ceux qui nous font accepter du sacrifice, du deuil, tirent leur sens de cette conscience partagée de la mortalité. Cette perspective a une résonance particulière dans les traditions existentialistes et notamment dans la pensée de Paul Ricœur, qui voit dans la finitude le fondement même de ce qui rend la vie digne d'être vécue : c'est une vie finie qui me demande de bien la vivre<ref>Paul Ricœur, ''Soi-même comme un autre'', Seuil, 1990, p. 453-476</ref>. Sans cette limitation, l'existence serait peut-être éternelle, mais elle risquerait de perdre cette tension, cette urgence qui la rend signifiante. === 6.3 Thomas Nagel et l'absurdité de la mort === [[Dictionnaire de philosophie/Thomas Nagel|Thomas Nagel]] a proposé une analyse novatrice en situant la mort parmi les sources majeures de ce qu'il appelle l'absurdité de l'existence humaine. L'absurdité naît, selon Nagel, non de la mortalité elle-même, mais du contraste entre l'importance subjective que nous conférons à nos vies et la relative insignifiance de ces vies au sein de l'univers cosmique<ref>Thomas Nagel, « The Absurd » (1971), dans ''Mortal Questions'', p. 11-32</ref>. La mort amplifie cette absurdité en ceci que la mort apparaît à la fois comme certaine et comme inimaginable pour le sujet vivant. Nous savons que nous mourrons, mais cette certitude reste abstraite ; nous ne pouvons vraiment imaginer notre non-existence. De ce contraste surgit une forme d'absurdité existentielle qui n'est pas directement accessible à la résolution rationnelle<ref>Nagel, « The Absurd », p. 27-30</ref>. Contrairement à Camus, qui voyait dans cette absurdité une occasion pour la révolte créative, Nagel y voit plutôt une condition inéluctable de la conscience réflexive : du moment que nous pouvons nous voir ''de l'extérieur'', que nous pouvons prendre du recul sur nos propres préoccupations, nous sommes confrontés à cette absurdité<ref>Nagel, « The Absurd », p. 31-32</ref>. La mort, dans ce contexte, est l'un des symptômes majeurs de notre condition d'êtres à la fois immergés dans la vie et capables de nous en distancier. == VII. Phénoménologie du mourir == === 7.1 Le mourir comme phénomène vécu === Bien que la mort elle-même, stricto sensu, échappe à toute expérience possible (puisque l'expérience présuppose la conscience et la mort sa cessation), le mourir, le processus qui mène à la mort, constitue une réalité vécue qui peut être objet de réflexion phénoménologique. La phénoménologie du mourir, dans la tradition heideggérienne et post-heideggérienne, cherche à décrire comment la proximité de la mort se manifeste dans l'expérience vécue. La peur de la mort, l'angoisse devant la finitude, l'acceptation progressive ou la dénégation, voilà autant de phénomènes psychologiques et ontologiques que la mort entraîne<ref>Heidegger, ''Sein und Zeit'', § 40</ref>. Jan Patočka, philosophe tchèque influencé par Husserl et Heidegger, a développé une approche phénoménologique particulière où le mourir apparaît comme ce qui révèle la structure fondamentale de la vie humaine. Pour Patočka, nous vivons constamment ''dans la proximité de la mort'', et c'est cette proximité qui confère à la vie son caractère de ''drame'' inéludable<ref>Jan Patočka, ''Platon et l'Europe'', Verdier, 1983, p. 157-198</ref>. Michel Henry a proposé une approche critique des phénoménologies heideggériennes de la mort, affirmant que l'accent mis sur l'être-vers-la-mort risque de passer sous silence l'expérience la plus profonde de la vie : la présence affective originaire (l'affectivité comme ''pathos'' primordial)<ref>Michel Henry, ''C'est moi la vérité. Pour une philosophie du christianisme'', Seuil, 1996, p. 129-145</ref>. De ce point de vue, toute tentative d'intelliger la mort par la seule réflexion existentiale reste insuffisante. === 7.2 L'angoisse face à la mort === L'angoisse (''Angst'' en allemand) constitue un thème central de la pensée existentialiste, notamment chez Kierkegaard, Heidegger et Sartre. L'angoisse face à la mort ne doit pas être confondue avec la peur de la mort, bien que les deux soient liées. La peur se rapporte à quelque chose de particulier et déterminé ; l'angoisse, en revanche, reste indéterminée, sans objet précis<ref>Søren Kierkegaard, ''Le Concept d'Angoisse'' (''Begrebet Angest'', 1844), traduction de Gilles Hanot, PUF, 2007, p. 53-87</ref>. Chez Heidegger, l'angoisse révèle l'essence de la mort comme possibilité absolue et singulière du Dasein. Dans l'angoisse, nous sommes face à face avec l'absurdité fondamentale de l'existence : que je sois plutôt que rien, c'est quelque chose qui ne se justifie pas et qui, un jour, s'arrêtera<ref>Heidegger, ''Sein und Zeit'', § 40-42</ref>. Cette approche a des implications profondes pour la psychologie et la psychiatrie. Si l'angoisse face à la mort est constitutive de la condition humaine et non une pathologie, comment faut-il la traiter ? La psychanalyse a proposé que refouler cette angoisse (l'inconscient humain dénie systématiquement la réalité de la mort) peut mener à des symptômes névrotiques. Certains thérapeutes, influencés par les existentialistes, affirment que l'acceptation progressive de la mortalité représente un élément clé de la maturation psychologique<ref>Irvin Yalom, ''Staring at the Sun: Overcoming the Terror of Death'', Jossey-Bass, 2008, p. 47-89</ref>. == VIII. La mort dans les traditions religieuses et spirituelles == === 8.1 L'au-delà et l'immortalité de l'âme === [[Fichier:The wheel of life, Buddhism Bhavachakra.jpg|vignette|upright=1.1|La roue de l'existence (''bhavacakra'') figure le cycle des renaissances (''saṃsāra'') dont le bouddhisme cherche la sortie.]] Historiquement, les traditions religieuses ont majoritairement affirmé que la mort n'est pas la fin absolue de la personne, mais une transition vers une autre forme d'existence (l'au-delà, le paradis, la réincarnation, le nirvana, etc.). Ces conceptions ne relèvent pas directement de la philosophie, mais elles constituent un contexte culturel et historique inévitable pour comprendre la réflexion philosophique occidentale sur la mort<ref>Mircea Eliade, ''Le Chamanisme et les Techniques archaïques de l'extase'', Payot, 1951, p. 401-437</ref>. Ces conceptions, qu'on regroupe trop vite, reposent en réalité sur des métaphysiques distinctes qu'il importe de séparer. La première est l'immortalité de l'âme : une partie immatérielle de la personne, son âme, survivrait par nature à la dissolution du corps. C'est la thèse du ''Phédon'', reprise par une longue tradition jusqu'à [[Dictionnaire de philosophie/René Descartes|Descartes]], pour qui l'âme est une substance pensante réellement distincte du corps étendu. L'identité du défunt y est portée par l'âme seule. La seconde, propre aux traditions juive, chrétienne et musulmane, est la résurrection des corps : ce n'est pas une âme spontanément immortelle qui assure la survie, mais un acte divin qui recrée la personne entière, corps compris, à la fin des temps. La nuance est de taille. Dans le premier cas, quelque chose en nous échappe par nature à la mort ; dans le second, la mort est bien réelle et complète, et seule une intervention extérieure peut la défaire. Saint Paul, qui parle d'un « corps spirituel » rendu à la vie, n'affirme pas l'immortalité de l'âme à la manière grecque, mais le relèvement de tout l'homme. Les traditions venues de l'Inde déplacent encore les termes du problème. La doctrine de la réincarnation, ou métempsycose, suppose un soi permanent, l{{'}}''ātman'', qui transmigre de corps en corps au fil des renaissances ; le but recherché, la délivrance (''mokṣa''), est la sortie hors de ce cycle (''saṃsāra''). Le bouddhisme, qui partage le cadre du cycle des renaissances, en retranche pourtant la pièce maîtresse : il nie l'existence d'un soi substantiel et permanent, c'est la thèse de l{{'}}''anātman'', le non-soi. Comment, dès lors, parler de renaissance sans personne qui renaisse ? La réponse bouddhique est subtile : ce qui se perpétue n'est pas un sujet identique, mais un flux causal d'états conditionnés, comparable à une flamme qui en allume une autre sans qu'aucune substance ne passe de l'une à l'autre. Le ''nirvāṇa'' n'est pas un paradis, mais l'extinction du désir et l'arrêt du cycle lui-même. On remarquera que cette idée d'une continuité sans sujet permanent rejoint, par un tout autre chemin, les analyses réductionnistes de l'identité personnelle examinées plus haut (section 3.1.2) ; Parfit lui-même reconnaissait la parenté de sa position avec la pensée bouddhique. Il s'agit toutefois d'une analogie, non d'une équivalence doctrinale : Parfit raisonne dans un cadre analytique contemporain, là où le bouddhisme inscrit le non-soi dans une visée de délivrance, éthique et méditative, qui déborde de loin la seule question de l'identité personnelle. La question philosophique spécifique que ces traditions soulèvent concerne la possibilité conceptuelle d'une immortalité personnelle. Si l'immortalité consiste en une simple survie de l'âme (entendue comme substance immatérielle), comment l'âme peut-elle persister sans rapport au corps ? Quel serait le contenu de cette expérience immortelle ? Ces questions ont occupé les plus grands penseurs, de Platon (notamment dans le ''Phédon'') à Descartes en passant par Leibniz et Kant<ref>Platon, ''Phédon'', traduction de Monique Dixsaut, GF Flammarion, 1991, p. 88-145</ref>. Kant refuse, dans la ''Critique de la raison pure'', les preuves théoriques de l'immortalité de l'âme ; dans la ''Critique de la raison pratique'', il lui accorde le statut de postulat de la raison pratique : nous ne pouvons progresser moralement à l'infini dans une vie finie, et il faut donc postuler une survie indéfinie de l'âme pour rendre intelligible la possibilité du progrès moral<ref>Immanuel Kant, ''Critique de la Raison Pratique'' (1788), traduction de François Picavet, PUF, 1943, p. 154-162</ref>. === 8.2 La mort et le sacré === Bien au-delà des doctrines spécifiques d'immortalité, la mort a toujours occupé une place privilégiée dans l'expérience religieuse et spirituelle. Des rites funéraires à travers le monde aux pratiques contemplatives des traditions mystiques, la mort demeure au cœur du rapport humain au sacré. Depuis les travaux du sociologue et anthropologue Émile Durkheim, la mort a été reconnue comme un moment privilégié de manifestation du sacré. Les rituels funéraires, bien qu'ils varient fortement selon les cultures, partagent souvent une fonction commune : marqueur de transition, affirmation de la continuité du groupe social face à la rupture qu'introduit le décès d'un de ses membres<ref>Émile Durkheim, ''Les Formes élémentaires de la vie religieuse'' (1912), traduction de Corinne Enaudeau, Seuil, 2003, p. 325-381</ref>. Certaines traditions spirituelles, notamment dans le bouddhisme tibétain (notamment le ''Bardo Thödol'' ou ''Livre des Morts Tibétain''), conçoivent le mourir et le moment qui suit comme une opportunité transformatrice majeure. La mort n'est pas considérée comme une fin, mais comme un passage initiatique potentiel offrant la possibilité d'une libération ou d'une meilleure réincarnation<ref>Jetsun Kalu Rinpoche, ''Le Chemin de la Lumière'', Claire Lumière, 1987</ref>. La philosophie contemporaine peut étudier ces phénomènes sans adopter les croyances qui les accompagnent, tout en reconnaissant que le rapport de l'humanité à la mort reste indissociable de la dimension spirituelle et rituelle de l'existence. Ignorer cet aspect serait réduire la mort à une simple question biologique, ce qui passerait sous silence une partie essentielle du phénomène<ref>Paul Tillich, ''Le Courage d'exister'', Centurion, 1967, p. 156-198</ref>. == IX. Questions métaphysiques et logiques == === 9.1 La mort et la causalité inversée : le problème du manque === Un problème logique subtil s'impose à la théorie déprivationniste : comment quelque chose qui n'existe pas (une vie non-vécue) peut-il être causal dans le monde ? Si je suis privé de certains biens parce que je suis mort, comment la mort (un événement qui produit mon inexistence) peut-elle être la cause d'une privation qui m'affecte ? Cette question de la ''causalité inversée'' a occupé les métaphysiciens de la mort contemporains<ref>George Pitcher, « The Misfortune of the Dead », dans ''The American Philosophical Quarterly'', vol. 21, n° 3, 1984, p. 183-188</ref>. Plusieurs solutions ont été proposées. Fred Feldman, par exemple, soutient que nous pouvons concevoir une relation de ''privation causale'' où la mort cause une privation sans que la mort elle-même agisse comme cause efficiente au sens traditionnel<ref>Fred Feldman, ''Confrontations with the Reaper'', Oxford University Press, 1986, chap. 1</ref>. D'autres, comme James Stacey Taylor, explorent une conception contrefactuelle : la mort m'est nuisible en ceci qu'elle rend faux un contrefactuel (s'il y avait continuité de vie, j'aurais expérimenté certains biens)<ref>James Stacey Taylor, ''Death, Positivism and Meaning'', Routledge, 2007, p. 42-71</ref>. === 9.2 La mort et le réalisme métaphysique === La mort soulève aussi des questions métaphysiques concernant le statut des entités qui cessent d'exister. Un objet matériel qui se désagrège au fil du temps semble persister en tant qu'objet jusqu'à un certain degré de désagrégation. Mais à quel point devient-il plus correct de dire que l'objet n'existe plus ? De la même façon, une personne meurt progressivement : ses fonctions cognitives s'altèrent, puis ses fonctions biologiques s'arrêtent. Y a-t-il un moment précis où la personne cesse d'être, ou s'agit-il plutôt d'un processus continu<ref>Dean Zimmerman, « The A-Theory of Time and the B-Theory », dans ''Stanford Encyclopedia of Philosophy'', 2011</ref> ? Ces questions se sont intensifiées avec les progrès biomédicaux contemporains. Les notions de mort cérébrale, de mort clinique et de possibilités de réanimation ont troublé les frontières autrefois claires entre vie et mort. Philosophiquement, ces développements nous forcent à reconnaître que la mort n'est pas une simple dichotomie (on vit ou on meurt), mais un spectre complexe<ref>Robert D. Truog, « Defining Death, Again », ''Hastings Center Report'', vol. 35, n° 6, 2005, p. 6</ref>. == X. Perspectives bioéthiques contemporaines == === 10.1 Mort clinique, mort cérébrale et statut du mourant === Les développements des technologies de maintien artificiel de la vie ont nettement modifié le paysage éthique et philosophique de la mort. Avant l'invention des respirateurs artificiels et autres dispositifs de soutien vital, la mort était un processus relativement rapide et, dans la plupart des cas, reconnaissable. Aujourd'hui, il est possible de maintenir certaines fonctions biologiques longtemps après que les fonctions cognitives ou toutes les fonctions biologiques aient cessé<ref>Robert D. Truog et James L. Bernat, « Ethical Guidelines for the Diagnosis and Management of Brain Death in Adults and Children », ''Critical Care Medicine'', vol. 38, n° 9, 2010, p. 1962-1978</ref>. La question de savoir qui est ''vraiment'' mort a acquis une nouvelle urgence pratique. La notion de mort cérébrale, adoptée depuis les années 1960, redéfinit la mort non plus comme arrêt du cœur et de la respiration, mais comme arrêt irréversible de toutes les fonctions du cerveau (ou du tronc cérébral, selon les juridictions)<ref>David M. Greer, Matthew P. Kirschen, Ariane Lewis et al., « Pediatric and Adult Brain Death/Death by Neurologic Criteria Consensus Practice Guideline », ''Neurology'', vol. 101, n° 24, 2023, p. 1112-1132</ref>. Cette redéfinition, bien que médicalement et scientifiquement justifiée, a des implications philosophiques majeures : elle privilégie le cerveau comme siège de l'identité personnelle, ce qui représente un choix métaphysique au-delà de la simple constatation empirique. Cette redéfinition rend indispensable de distinguer plusieurs états cliniques que le langage courant confond aisément. Le coma désigne une abolition de la vigilance et de la conscience, souvent transitoire, dont le patient peut émerger. L'état végétatif, ou état d'éveil non répondant, associe un retour de l'éveil, avec cycles veille-sommeil et ouverture des yeux, à l'absence de tout signe de conscience de soi ou de l'environnement. L'état de conscience minimale se caractérise par des manifestations de conscience fluctuantes mais reproductibles. Le syndrome d'enfermement (''locked-in'') laisse au contraire la conscience intacte alors que la motricité volontaire est presque entièrement abolie, le sujet ne pouvant souvent communiquer que par les mouvements oculaires<ref>Joseph T. Giacino, Douglas I. Katz, Nicholas D. Schiff et al., « Practice Guideline Update Recommendations Summary: Disorders of Consciousness », ''Neurology'', vol. 91, n° 10, 2018, p. 450-460</ref>. La mort encéphalique se sépare de tous ces états : elle suppose l'arrêt irréversible de l'ensemble des fonctions du cerveau, tronc cérébral compris, et n'autorise par définition ni éveil, ni conscience, ni respiration spontanée. Confondre ces situations, en particulier l'état végétatif et la mort encéphalique, expose à des erreurs cliniques et éthiques lourdes, qu'il s'agisse d'interrompre à tort des soins ou de les prolonger sans terme. === 10.2 L'allongement de la vie et l'anti-vieillissement === La bioéthique contemporaine est occupée par un dilemme : d'un côté, la mort demeure inévitable et, en un sens, souhaitable (sans elle, l'existence deviendrait infinie, monotone) ; de l'autre, les capacités technologiques contemporaines permettent d'envisager des vies bien plus longues, voire, dans certains scénarios futuristes, potentiellement infinies. Aubrey de Grey et d'autres chercheurs en biogérontologie soutiennent que le vieillissement est une maladie et qu'il est en principe possible de développer des thérapies susceptibles d'arrêter ou d'inverser les processus biologiques du vieillissement<ref>Aubrey de Grey et Michael Rae, ''Ending Aging'', St. Martin's Press, 2007</ref>. Cette perspective soulève immédiatement la question : si l'on pouvait techniquement éliminer le vieillissement, devrait-on le faire ? La réponse dépend largement de la manière dont on évalue les enjeux philosophiques et éthiques que nous avons discutés plus haut (la théorie de l'ennui infini, le rôle de la mort dans la signification de la vie, etc.)<ref>Nick Bostrom, « The Immortality Question », ''Journal of Medical Ethics'', vol. 31, n° 12, 2005, p. 682-686</ref>. === 10.3 L'équité d'accès et la justice distributive === Si l'allongement de la vie devient techniquement possible, une question majeure de justice se pose : qui aura accès à ces technologies ? L'histoire de la médecine et des technologies montre que les innovations émergent généralement dans les contextes de richesse et de privilège avant, éventuellement, de devenir plus largement accessibles. Il serait naïf de croire qu'une technologie de rupture comme l'extension massive de la durée de vie serait immédiatement disponible pour tous<ref>Eric Parens (éd.), ''Shaping Our Selves: On Technology, Flourishing, and a Habit of Thinking'', Oxford University Press, 2010, p. 78-104</ref>. Cela pose une question de justice : serait-il acceptable que certains accèdent à une très grande longévité tandis que d'autres mourraient à un âge ordinaire ? Cela reposerait-il sur une conception fortement inégalitaire de la justice ? Ou, au contraire, faudrait-il considérer que chacun est libre de décider si oui ou non il souhaite bénéficier des technologies de prolongement de la vie, indépendamment du fait que d'autres n'y auraient pas accès<ref>Michael J. Sandel, ''The Case Against Perfection: Ethics in the Age of Genetic Engineering'', Harvard University Press, 2007</ref> ? == XI. Mort et écriture : le mourir philosophique == === 11.1 L'ineffable de la mort et les limites du langage === Un dernier ensemble de questions, épistémologiquement et esthétiquement pertinent, concerne la possibilité de dire la mort, d'en écrire et d'en penser. La mort semble occuper une place singulière dans le langage : elle est à la fois ce dont on parle constamment (mort naturelle, meurtre, suicide, etc.) et ce qui échappe apparemment à la pensée conceptuelle quand nous nous confrontons à notre propre finitude. Blanchot, écrivain et philosophe français, a insisté sur ce point : la mort ne peut être pensée qu'à la limite du pensable, là où le langage frôle son ineffabilité. Pour Blanchot, il ne s'agit pas simplement de dire que la mort est au-delà des mots (ce qui serait un platonisme romantique), mais que la mort révèle les limites du langage de manière productive : c'est dans l'expérience de cette limite que survient une certaine clarté<ref>Maurice Blanchot, ''L'Entretien infini'', Gallimard, 1969, p. 123-152</ref>. === 11.2 Littérature et philosophie face à la mort === [[Fichier:Caspar David Friedrich - Abtei im Eichwald - Google Art Project.jpg|vignette|upright=1.1|''L'Abbaye dans une forêt de chênes'' (Caspar David Friedrich, 1809-1810) : ruine, cimetière et arbres dénudés, méditation romantique sur la mort.]] La littérature, particulièrement dans les traditions lyrique et épique, a souvent offert ce que la philosophie ne peut que pointer du doigt. Les poètes, de Gilgamesh à Baudelaire en passant par Rilke, ont exploré les dimensions existentielles, affectives et imaginaires de la mort d'une manière que les arguments philosophiques stricts ne peuvent qu'approximativement capturer. Heidegger lui-même, malgré son effort pour ''libérer'' la mort d'une réduction technoscientifique, reconnaît que la poésie peut révéler des dimensions de la mort que la seule analyse conceptuelle ne peut atteindre. Quand Rilke demande, dans ''Le Livre d'heures'', que soit donnée à chacun « sa propre mort », ou quand Hölderlin, dans l'élégie ''Pain et vin'', chante le retrait des dieux, ces œuvres ne ''démontrent'' rien philosophiquement, mais elles ''montrent'' : elles ouvrent une expérience différente du rapport à la mort<ref>Heidegger, ''Introduction à la Métaphysique'', traduction de Gilbert Kahn, PUF, 1967, p. 147-165</ref>. == XII. Synthèse et enjeux ouverts == === 12.1 La pluralité des approches et l'impossibilité d'une réduction === Ce qui émerge de cet examen détaillé de la philosophie de la mort, c'est d'abord l'impossibilité d'une réduction de la mort à une seule dimension (biologique, psychologique, existentielle, éthique, métaphysique). La mort se présente plutôt comme un phénomène polymorphe qui appelle des réponses philosophiques multiples, souvent en tension les unes avec les autres. La tension entre la théorie déprivationniste (qui insiste sur la mort comme privation de biens futurs) et l'argument épicurien (qui affirme que nous ne pouvons pas vraiment expérimenter la mort comme un mal) reste en grande partie non résolue. Cette tension n'est pas une imperfection de la philosophie, mais révèle quelque chose d'essentiel : que la mort échappe à nos catégories conceptuelles habituelles. De la même façon, la tension entre l'affirmation existentialiste selon laquelle la mort donne sens à la vie et la théorie que la mort rend la vie absurde (Camus) ne peut être ''résolue'' au sens d'une démonstration logique univoque. Ces deux positions reflètent plutôt deux aspects complémentaires et irréductibles de la condition humaine mortelle. === 12.2 La mort comme horizon de la pensée === Pour conclure, il importe de souligner que la question de la mort n'est pas une question parmi d'autres en philosophie. Elle constitue l'horizon ultime sur lequel se projette toute réflexion sur le sens, la valeur, l'authenticité et la responsabilité éthique. Aussi bien Heidegger qu'Épicure, Camus que Levinas, bien qu'ils arrivent à des conclusions différentes, s'accordent sur un point : la mort nous force à nous interroger sur ce qui compte vraiment, sur ce qui rend la vie vivable. Dans un contexte contemporain d'accélération technologique et de transformation de grande ampleur de la condition humaine, cette réflexion ancienne sur la mort demeure aussi nécessaire qu'elle l'a toujours été. Comment devons-nous concevoir nos rapports à la finitude face aux promesses d'allongement de la vie ? Comment construire une éthique du deuil et du respect des morts dans un monde de plus en plus fragmenté et délocalisé ? Comment penser la solidarité humaine sans la conscience partagée de notre mortalité commune<ref>Jonathan Glover, ''Humanity: A Moral History of the Twentieth Century'', Yale University Press, 1999, p. 234-267</ref> ? Ce sont les questions que les générations futures devront continuer à se poser, et c'est peut-être en cela que la mort, ce phénomène qui se dérobe toujours à l'expérience, demeure la question constitutive de toute réflexion sérieuse sur ce que c'est que d'être humain. == Notes et références == {{references|colonnes=2}} == Bibliographie indicative == Les références complètes figurent dans les notes. On regroupe ici, par grands domaines, les principaux ouvrages auxquels le lecteur peut se reporter. === Textes classiques === * Platon, ''Phédon'', traduction de Monique Dixsaut, GF Flammarion, 1991. * Épicure, ''Lettre à Ménécée'', dans ''Lettres et Maximes'', traduction de Marcel Conche, PUF, 1987. * Lucrèce, ''De la nature'', livre III, traduction de José Kany-Turpin, GF Flammarion, 1997. * Sénèque, ''Lettres à Lucilius''. * Marc Aurèle, ''Pensées pour moi-même''. * Montaigne, ''Essais'', I, 20 et III, 13. * Spinoza, ''Éthique'', partie IV. === Philosophie contemporaine de la mort === * Thomas Nagel, ''Mortal Questions'', Cambridge University Press, 1979. * Bernard Williams, « The Makropulos Case: Reflections on the Tedium of Immortality », dans ''Problems of the Self'', Cambridge University Press, 1973. * Fred Feldman, ''Confrontations with the Reaper'', Oxford University Press, 1986. * James Stacey Taylor, ''Death, Positivism and Meaning'', Routledge, 2007. * Steven Luper, ''The Philosophy of Death'', Cambridge University Press, 2009. * Ben Bradley, Fred Feldman et Jens Johansson (dir.), ''The Oxford Handbook of Philosophy of Death'', Oxford University Press, 2013. * Steven Luper, « Death », ''The Stanford Encyclopedia of Philosophy'' (sous la direction d'Edward N. Zalta), 2002. === Identité personnelle === * Derek Parfit, ''Reasons and Persons'', Oxford University Press, 1984. * John Locke, ''An Essay Concerning Human Understanding'', livre II, chapitre XXVII. * David Hume, ''A Treatise of Human Nature'', livre I, partie IV, section VI. * David Lewis, « Survival and Identity », dans ''The Identities of Persons'', University of California Press, 1976. * Eric Olson, ''The Human Animal: Personal Identity Without Psychology'', Oxford University Press, 1997. * Paul Ricœur, ''Soi-même comme un autre'', Seuil, 1990. === Existentialisme et finitude === * Martin Heidegger, ''Être et Temps'' (''Sein und Zeit'', 1927), traduction de François Vezin, Gallimard, 1986. * Albert Camus, ''Le Mythe de Sisyphe'', Gallimard, 1942. * Søren Kierkegaard, ''Le Concept d'Angoisse'' (1844), traduction de Gilles Hanot, PUF, 2007. * Simone de Beauvoir, ''Tout compte fait'', Gallimard, 1972. * Karl Jaspers, ''Introduction à la pensée philosophique'', traduction d'Yvon Belaval, 10/18, 1970. === Bioéthique et fin de vie === * Tom L. Beauchamp et James F. Childress, ''Principles of Biomedical Ethics'', Oxford University Press, 7e édition, 2013. * Helga Kuhse et Peter Singer (dir.), ''A Companion to Bioethics'', Blackwell, 2009. * David M. Greer, Matthew P. Kirschen, Ariane Lewis et al., « Pediatric and Adult Brain Death/Death by Neurologic Criteria Consensus Practice Guideline », ''Neurology'', vol. 101, n° 24, 2023. * President's Commission for the Study of Ethical Problems in Medicine, ''Defining Death: Medical, Legal and Ethical Issues'', Washington D.C., 1981. * Michael J. Sandel, ''The Case Against Perfection: Ethics in the Age of Genetic Engineering'', Harvard University Press, 2007. === Histoire sociale et anthropologie de la mort === * Philippe Ariès, ''L'Homme devant la mort'', Seuil, 1977. * Vladimir Jankélévitch, ''La Mort'', Flammarion, 1966. * Émile Durkheim, ''Les Formes élémentaires de la vie religieuse'' (1912), traduction de Corinne Enaudeau, Seuil, 2003. * Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', supplément au livre IV, chapitre 41. == Notions liées == * [[../Finitude/]] * [[../Âme/]] * [[../Conscience/]] * [[../Existence/]] * [[../Angoisse/]] * [[../Euthanasie/]] * [[../Bioéthique/]] {{AutoCat}} 84413sidmso56ufs2itzjng77k8q4od Fonctionnement d'un ordinateur/Les circuits pour l'addition et la soustraction 0 65787 768730 768677 2026-06-26T15:22:47Z Mewtow 31375 /* La propagation et la génération des retenues */ 768730 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur pour opérandes entiers=== Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. La table de soustraction nous dit quel est le résultat de la soustraction de deux bits. La voici : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] La table de soustraction peut servir de table de vérité pour construire un circuit qui soustrait deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] Comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. Il faut faire cela pour chaque demi-soustracteur, ce qui donne ceci pour un soustracteur complet. le résultat est alors appelé un '''additionneur-soustracteur complet'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> 4awewszb251aw4v09evt6k29nbut338 768737 768730 2026-06-27T00:27:44Z Mewtow 31375 /* Le soustracteur pour opérandes entiers */ 768737 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur pour opérandes entiers=== Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. Il faut faire cela pour chaque demi-soustracteur, ce qui donne ceci pour un soustracteur complet. le résultat est alors appelé un '''additionneur-soustracteur complet'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> 2quet2una2ke91udm6qnn80wqk2a8ff 768741 768737 2026-06-27T00:37:34Z Mewtow 31375 /* Le soustracteur pour opérandes entiers */ 768741 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur basé sur des demi-soustracteurs=== Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] Le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Le circuit obtenu s'appelle un '''demi-additionneur/soustracteur''', ou encore un ''demi-add/sub''. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Il est possible de rempalcer les demi-soustracteurs par des demi-add/sub. Le résultat est alors appelé un '''additionneur-soustracteur complet'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> 6snqac3k56ra1d80260u98fvf4bjdzg 768742 768741 2026-06-27T00:38:46Z Mewtow 31375 /* Le soustracteur basé sur des demi-soustracteurs */ 768742 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur basé sur des demi-soustracteurs=== [[File:Half Subtractor Vektor.svg|vignette|Demi-soustracteur.]] Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Le circuit obtenu s'appelle un '''demi-additionneur/soustracteur''', ou encore un ''demi-add/sub''. {| |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |[[File:Half-adder.svg|vignette|Demi-additionneur]] |} Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Il est possible de rempalcer les demi-soustracteurs par des demi-add/sub. Le résultat est alors appelé un '''additionneur-soustracteur complet'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> 37c9il50wefom6a2ctuzssns90o9v85 768744 768742 2026-06-27T00:45:35Z Mewtow 31375 /* Le soustracteur basé sur des demi-soustracteurs */ 768744 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur à propagation de retenue=== [[File:Half Subtractor Vektor.svg|vignette|Demi-soustracteur.]] Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Le circuit obtenu s'appelle un '''demi-additionneur/soustracteur''', ou encore un ''demi-add/sub''. {| |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |[[File:Half-adder.svg|vignette|Demi-additionneur]] |} Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Il est possible de rempalcer les demi-soustracteurs par des demi-add/sub. Le résultat est alors appelé un '''additionneur-soustracteur complet'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] Un défaut est que cela ne fonctionne bien que pour les additionneurs/soustracteurs à propagation de retenue, mais l'anticipation de retenue et les autres optimisations ne marchent pas bien avec des soustracteurs complets. L'anticipation de retenue ne marche pas de la même manière entre addition et soustraction, par exemple. Les signaux de propagation et de génération de retenue ne sont pas générés pareil, idem pour la manière de les combiner. Il est toujours possible de créer un soustracteur avec ces techniques, mais aucune mutualisation de circuit ne sera possible. Ce qui n'est pas le cas avec les solutions que nous allons voir dans ce qui suit. ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> 12w5sy8tmkmyx82i1c47tf7qi3r5wyq 768745 768744 2026-06-27T00:46:24Z Mewtow 31375 /* Le soustracteur à propagation de retenue */ 768745 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur à propagation de retenue=== [[File:Half Subtractor Vektor.svg|vignette|Demi-soustracteur.]] Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Un défaut est que cela ne fonctionne bien que pour les additionneurs/soustracteurs à propagation de retenue, mais l'anticipation de retenue et les autres optimisations ne marchent pas bien avec des soustracteurs complets. L'anticipation de retenue ne marche pas de la même manière entre addition et soustraction, par exemple. Les signaux de propagation et de génération de retenue ne sont pas générés pareil, idem pour la manière de les combiner. Il est toujours possible de créer un soustracteur avec ces techniques, mais aucune mutualisation de circuit ne sera possible. Ce qui n'est pas le cas avec les solutions que nous allons voir dans ce qui suit. ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> nl3o2mxaor03dhtxomeen37df3u191e 768746 768745 2026-06-27T00:49:01Z Mewtow 31375 /* Le soustracteur à propagation de retenue */ 768746 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur à propagation de retenue=== [[File:Half Subtractor Vektor.svg|vignette|Demi-soustracteur.]] Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Un défaut est que cela ne fonctionne bien que pour les additionneurs/soustracteurs à propagation de retenue, mais l'anticipation de retenue et les autres optimisations ne marchent pas bien avec des soustracteurs complets. L'anticipation de retenue ne marche pas de la même manière entre addition et soustraction, par exemple. Les signaux de propagation et de génération de retenue ne sont pas générés pareil, idem pour la manière de les combiner. Il est toujours possible de créer un soustracteur avec ces techniques, mais aucune mutualisation de circuit ne sera possible. Ce qui n'est pas le cas avec les solutions que nous allons voir dans ce qui suit. Il est possible de fusionner un additionneur à propagation de retenue et un soustracteur de même type. Pour cela, il suffit de remarquer que les demi-soustracteurs et les demi-additionneurs se ressemblent beaucoup. La seule différence entre les deux est une vulgaire porte NON. En remplaçant cette porte NON par un inverseur commandable, on obtient un circuit qui sert soit de demi-additionneur, soit de demi-soustracteur, suivant ce qu'on envoie sur l'entrée de commande. Ci-dessous est illustré ce que donne ce remplacement pour un soustracteur complet. Le résultat est un '''additionneur/soustracteur à propagation de retenue'''. [[File:Additionneur-soustracteur complet.png|thumb|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> ei5i2zjtkz7lmsz9pfewhrj6g0kmnr1 768747 768746 2026-06-27T00:49:16Z Mewtow 31375 /* Le soustracteur à propagation de retenue */ 768747 wikitext text/x-wiki Dans ce chapitre, nous allons voir les circuits capables de faire une addition ou une soustraction, ainsi que quelques circuits spécialisés. Précisons cependant que les fabricants de processeurs travaillent d'arrache-pied pour trouver des moyens de rendre ces circuits de calcul plus rapides et plus économes en énergie. Autant vous dire que les circuits que vous allez voir sont vraiment des circuits qui font pâle figure comparé à ce que l'on peut trouver dans un vrai processeur commercial ! ==Les circuits pour additionner 2 ou 3 bits== L'addition se fait en binaire de la même manière qu'en décimal. On additionne les chiffres/bits colonne par colonne, une éventuelle retenue est propagée à la colonne d'à côté. La soustraction fonctionne sur le même principe, sur le même modèle qu'en décimal. [[File:Binary Addition Demonstration.svg|centre|vignette|Exemple d'addition en binaire.]] En clair, additionner deux nombres demande d'additionner 2 bits et une retenue sur chaque colonne, et de propager les retenues d'une colonne à l'autre. La propagation des retenues est quelque chose de simple en apparence, mais qui est sujet à des optimisations extraordinairement nombreuses. Aussi, pour simplifier l'exposition, nous allons voir comment gérer une colonne avant de voir comment sont propagées les retenues. [[File:Full Adder Block.svg|vignette|upright=1|class=transparent|Additionneur complet.]] Si on effectue une addition en colonne, on doit additionner les deux bits sur la colonne, mais aussi additionner une éventuelle retenue. Il faut donc créer un circuit qui additionne trois bits : deux bits de données, plus une retenue. Ce circuit qui additionne trois bits est appelé un '''additionneur complet'''. Il fournit en sortie deux bits : un bit de somme et une retenue sortante. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- ||0||0||0|| ||0||0 |- ||0||0||1|| ||0||1 |- ||0||1||0|| ||0||1 |- ||0||1||1|| ||1||0 |- ||1||0||0|| ||0||1 |- ||1||0||1|| ||1||0 |- ||1||1||0|| ||1||0 |- ||1||1||1|| ||1||1 |} Il est possible d'utiliser un tableau de Karnaugh pour traduire la table de vérité, mais elle donne un résultat assez compliqué. La retenue et le bit de somme sont calculés à part. La retenue est calculée avec trois portes ET et une porte OU. Le bit de somme est calculé lui avec 4 portes ET, une porte OU, et trois portes NON. [[File:Full Adler with 3 entries.png|centre|vignette|upright=2|Additionneur complet, fabriqué à partir de la table de vérité.]] D'autres méthodes donnent des résultats plus compréhensibles. Nous allons les voir dans la suite de cette section. ===L'additionneur complet basé sur des demi-additionneurs=== [[File:1-bit half-adder.svg|class=transparent|vignette|Demi-addtionneur.]] Nous avons déjà vu comment additionner deux bits dans le chapitre sur les incrémenteurs, mais quelques rappels ne seront pas de trop. Le '''demi-additionneur''' est un circuit qui additionne deux bits. Il implémente la table d'addition, qui est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Mais un demi-additionneur n'additionne que deux bits, il manque de quoi additionner la retenue. Une solution pour cela est d'enchaîner deux demi-additionneurs : un qui additionne les deux bits de données, et un second qui additionne la retenue au résultat du précédent. La retenue finale se calcule en combinant les sorties de retenue des deux demi-additionneurs, avec une porte OU. Le résultat est un additionneur complet fabriqué avec deux demi-additionneurs. Pour vous en convaincre, établissez la table de vérité de ce circuit, vous verrez que ça marche. [[File:Full Adder Blocks.svg|centre|vignette|upright=2|Additionneur complet fabriqué avec deux demi-additionneurs.]] [[File:Half-adder.svg|vignette|upright=1|Circuit d'un demi-additionneur naïf.]] L'implémentation naïve d'un demi-additionneur utilise une porte XOR et une porte ET, comme illustré ci-contre. Le circuit s'obtient en faisant uen traduction littérale de la table de vérité du circuit. Si je dis qu'elle est naïve, c'est car il est possible de l'optimiser, de manière à éliminer des redondances cachées. Mais nous avions déjà vu cela dans le chapitre sur les incrémenteurs, aussi laissons cela pour plus tard. En combinant deux demi-additionneurs de ce type, on obtient l'additionneur complet suivant. Les deux sorties de retenue des demi-additionneurs sont combinées avec une porte OU, pour calculer la retenue finale. {| class="flexible" |[[File:Full Adder Modules.svg|class=transparent|Composition d'un additionneur complet. On voit bien que celui-ci est composé de deux demi-additionneurs, en rouge et en bleu, auxquels on a ajouté une porte OU pour calculer la retenue finale.]] |[[File:Full-adder.svg|300px|class=transparent|Circuit d'un additionneur complet.]] |} Le fait de combiner les deux retenues avec une porte OU n'est pas ce qu'il y a de plus intuitif. La table de vérité nous dit que ça fonctionne, mais on comprend mal pourquoi. Mais tout devient plus clair quand on sait que les deux retenues ne peuvent pas être à 1 en même temps. Même dans l'addition 1 + 1 + 1, seule une retenue est à 1. Soit l'addition des deux bits d'opérande donne naissance à une retenue, soit c'est l'addition ''résultat + retenue entrante''. La retenue sortant est donc à 1 quand une des deux addition donne une retenue. D'où l'usage d'une porte OU. Remarquez qu'une porte XOR donne le même résultat, vu que le cas où les deux retenues sont à 1 n'est jamais rencontré. ===La propagation et la génération des retenues=== L'additionneur complet que nous allons voir dans cette section sert à introduire les concepts de propagation, génération et absorption de retenue. Il s'agit de concepts très importants quand on étudie les additionneurs. l'idée part d'un principe très simple : la retenue sortante dépend de la retenue d'entrée. La relation entre les deux se résume à trois cas, qui dépendent de la valeur des deux bits additionnés, nommés A et B. * Dans le premier cas, la retenue entrante est égale à la retenue sortante. On dit que la retenue entrante est propagée par l'additionneur. * Dans le second cas, la retenue est forcée à 0 : la retenue sortante vaut 0, peu importe la valeur de la retenue entrante. * Dans le troisième cas, la retenue est forcée à 1 : la retenue entrante vaut 1, peu importe la valeur de la retenue entrante. [[File:Signaux P et G fournis par un demi-additionneur.png|vignette|Signaux P et G fournis par un demi-additionneur]] Maintenant, créons un circuit qui nous dise si une retenue est propagée ou générée. Il a deux bits de sortie, nommés P et G : P pour ''Propagate'', G pour ''Generate''. Le bit P est à 1 si la retenue entrante est propagée, il est à 0 sinon. Le bit G est à 1 si une retenue est générée, à 0 sinon. Une retenue est considérée comme absorbée si elle n'est pas ni propagée ni générée, pas besoin d'un troisième bit pour gérer ce cas. Il se trouve que ce circuit n'est autre qu'un demi-additionneur ! Pour vous en rendre compte, regardez la table de vérité d'un additionneur complet, illustrée ci-dessous. Lorsque les deux bits d'opérande sont à 0, la retenue sortante vaut toujours 0. Si ils sont tous deux à 1, alors la retenue sortante vaut 1. S'ils sont différents, alors retenues sortante et entrante sont égales. Le bit P est donc généré par une simple porte XOR. Quant au bit G, il est à 1 si les deux bits d'opérandes sont à 1, ce qui correspond à une porte ET. Il se trouve que ces deux portes forment un demi-additionneur ! {|class="wikitable" |- ! Opérande 1 !! Opérande 2 !! Retenue entrante !! !! Retenue sortante |- class="f_rouge" ||0||0||0|| ||0 |- class="f_rouge" ||0||0||1|| ||0 |- class="f_bleu" ||0||1||0|| ||0 |- class="f_bleu" ||0||1||1|| ||1 |- class="f_bleu" ||1||0||0|| ||0 |- class="f_bleu" ||1||0||1|| ||1 |- class="f_vert" ||1||1||0|| ||1 |- class="f_vert" ||1||1||1|| ||1 |} Ensuite, créons un circuit qui prend ces deux sorties P et G, et calcule la retenue sortante en fonction. Le circuit en question a trois entrées : la retenue entrante, les deux bits P et G. La retenue sortante vaut 1 soit si une retenue est générée, soit si la retenue entrante est propagée et qu'elle vaut 1. En notant <math>{C_{in}}</math> et <math>{C_{out}}</math> les retenues entrantes et sortante, on a : : <math>{C_{out}} = G + \left( P . C_{in} \right)</math> Le circuit est donc composé d'une porte OU et d'une porte ET. En combinant un demi-additionneur avec le circuit de calcul de retenue sortante vu plus haut, on a : [[File:Additionneur complet avec propagation et génération de retenue.png|class=transparent|centre|vignette|upright=2|Additionneur complet avec propagation et génération de retenue.]] Certes, on retombe sur le circuit vu plus haut. Mais il est possible de remplacer le circuit en orange par un autre. Par exemple, il est possible de le remplacer par multiplexeur, qui choisit entre la retenue générée et la retenue entrante (propagée). Le choix se fait selon la valeur du bit P, qui chosiit entre propager la retenue et la générer. [[File:Additionneur crée avec un multiplexeur.png|centre|vignette|upright=1.5|Additionneur crée avec un multiplexeur]] Le circuit exact est illustré ci-dessous. Il semble utiliser plus de portes logiques que l'additionneur complet précédent. Cependant, nous verrons dans quelques chapitres qu'il est possible d'implémenter un multiplexeur avec seulement 6 transistors, voire moins ! L'implémentation utilise des portes à transmission, mais nous en reparlerons dans le chapitre sur les transistors, quand nous verrons les additionneurs à ''Manchester Carry Chain''. Au passage, une variante de ce circuit a été utilisée dans le processeur processeur 8086 d'Intel, comme on le verra dans le chapitre suivant. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1|Additionneur complet basé sur un MUX]] [[File:FulladderPG.png|vignette|upright=1|Additionneur complet avec deux sorties P et G.]] Pour finir, sachez qu'il existe des additionneurs qui fournissent : le bit de résultat, deux sorties P et G qui indiquent si l'addition propage ou génère une retenue. Il ne s'agit pas d'additionneurs complets, car il manque de quoi calculer la retenue sortante. De tels additionneurs seront appelés des '''additionneurs partiels'''. De tels additionneurs sont utilisés dans certains additionneurs pour gagner en performance. Enfin, il existe aussi ce que j'ai décidé d'appeler des '''additionneurs P/G''', qui sont des additionneurs complets auxquels on a ajouté deux sorties P et G, en plus de la sortie de retenue. Leur circuit est le même que celui d'un additionneur complet, auquel on a ajouté deux fils. Vu que ces deux sorties sont fournies par le premier demi-additionneur, ajouter ces deux sorties demande d'ajouter des fils, pas de portes logiques. De tels additionneurs sont aussi utilisés dans certains additionneurs pour gagner en performance. [[File:FAwithGP.svg|centre|vignette|upright=2|Additionneur complet avec sorties P et G : circuit.Ç]] ===L'additionneur complet basé sur une porte à majorité=== Maintenant, voyons une dernière implémentation possible de l'additionneur complet. Mais avant de voir comment l'additionneur est implémenté, nous allons devoir faire un petit focus sur la retenue sortante. Reprenons la table de vérité, et regardons ce qu'il en est pour la retenue sortante uniquement. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante |- ||0||0||0|| ||0 |- ||0||0||1|| ||0 |- ||0||1||0|| ||0 |- ||0||1||1|| ||1 |- ||1||0||0|| ||0 |- ||1||0||1|| ||1 |- ||1||1||0|| ||1 |- ||1||1||1|| ||1 |} Vous remarquerez que la retenue sortante est égale au bit majoritaire, parmi les trois bits d'opérande. Si deux ou trois bits sont à 1, la retenue sortante vaut 1. Et réciproquement avec 0. Le circuit de calcul de la retenue peut donc être remplacé par une '''porte à majorité'''. [[File:Additionneur crée avec une porte à majorité.png|centre|vignette|upright=2|Additionneur crée avec une porte à majorité]] Mais une porte à majorité est assez gourmande en circuit, ce qui fait qu'un additionneur pareil ne serait pas pratique, ni utile. Du moins, ce serait le cas s'il n'y avait pas une possibilité d'optimisation extrêmement intéressante. Il est possible de calculer le 'bit de somme' à partir de la retenue sortante ! En effet, le bit de somme est l'inverse de la retenue sortante, sauf dans deux cas : les trois bits d'entrée sont à 0, où ils sont tous à 1. Le bit de somme vaut 0 dans le premier cas, 1 dans le second cas. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! Opérande 2 !! !! Retenue sortante !! Bit de somme |- class="f_bleu" ||0||0||0|| ||0||0 |- class="f_vert" ||0||0||1|| ||0||1 |- class="f_vert" ||0||1||0|| ||0||1 |- class="f_vert" ||0||1||1|| ||1||0 |- class="f_vert" ||1||0||0|| ||0||1 |- class="f_vert" ||1||0||1|| ||1||0 |- class="f_vert" ||1||1||0|| ||1||0 |- class="f_rouge" ||1||1||1|| ||1||1 |} En clair, 6 lignes de la table de vérité sur 8 peuvent se calculer avec une porte à majorité, le reste demandant quelques portes logiques pour faire la correction. L'implémentation en circuit demande donc trois choses : * de calculer la retenue sortante et de quoi l'inverser ; * un circuit qui vérifie si tous les bits opérande valent 0 : une porte NOR ou OU fait l'affaire ; * un circuit qui vérifie s'ils valent tous 1, à savoir une porte ET. Ensuite, on combine le résultat des trois circuits précédents pour obtenir le résultat final. La combinaison est le fait du circuit en jaune dans le schéma ci-dessous. [[File:Full adder basé sur une modification de la retenue.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue]] Le circuit en jaune est assez simple. Quand la porte ET sort un 1, la sortie doit être forcée à 1. Par contre, quand la porte OU sort un zéro, la sortie doit être forcée à 0. Il suffit donc d'enchainer un circuit de mise à 1 et un circuit de mise à 0. Nous avons vu dans le chapitre sur les opérations de masquage qu'il s'agit respectivement d'une porte OU et d'une porte ET. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Divers processeurs utilisaient des additionneurs complets de ce type : le fameux Z80, l'Intel 4004 et de l'Intel 8008 sont les exemples les plus notables. Pourtant, on pourrait s'étonner qu'un tel circuit ait existé. Il utilise beaucoup de portes logiques, a une profondeur logique supérieure : il n'a rien d'avantageux. Sauf qu'il était utilisé sur d'anciens processeurs, qui utilisaient la technologie dite TTL, différente de la technologie CMOS des transistors modernes. Et avec la technologie TTL, il est possible de fusionner plusieurs portes logiques ET et NOR en une seule porte logique ET/OU/NON ! Un additionneur complet construit ainsi ne prenait que deux portes logiques : une pour le calcul de la retenue sortante, une autre pour le reste du circuit. ==L'addition non signée== Voyons maintenant un circuit capable d'additionner deux nombres entiers: l''''additionneur'''. Dans la version qu'on va voir, ce circuit manipulera des nombres strictement positifs. L'addition des nombres codés en complètement à deux sera vu dans une section ultérieure. [[File:Full-adder-4bits-serial-CEI.svg|vignette|upright=0.5|Additionneur 4 bits, un bloc.]] L'interface d'un additionneur est illustrée ci-contre. Un additionneur prend deux opérandes sur deux entrées séparées, et fournit le résultat sur une sortie dédiée. De plus, il a une entrée sur laquelle envoyer une retenue entrante, et a une sortie pour la retenue sortante. La sortie de retenue indique que le résultat de l'addition a débordé (au sens d'un débordement d'entier). Pour l'entrée de retenue, son utilité deviendra plus claire dans ce qui suit, mais souvenez-vous qu'elle existe. L'entrée et la sortie de retenue sont parfois utilisées pour combiner plusieurs petits additionneurs, pour former un additionneur plus grand. Nous verrons de nombreux exemples dans ce qui suit. Il est assez commun de créer des additionneurs pour des opérandes de 16/32/64 bits, avec des additionneurs de 4/5 bits. ===L'additionneur série=== Il est possible d'additionner deux nombres bit par bit, grâce à un additionneur complet associé à plusieurs registres à décalages. Les opérandes sont placées chacune dans un registre à décalage, et l'additionneur complet utilise les bits sortants de ces registres à décalage. Le bit du résultat est envoyé au registre à décalage pour le résultat. La retenue de l'addition est stockée dans une bascule de 1 bit, en attente du prochain cycle d'horloge. Un tel additionneur est appelé un '''additionneur série'''. Il a été utilisé sur d'anciens ordinateurs dans les années 50-60, aussi bien des prototypes que des ordinateurs commerciaux. [[File:Additionneur série.jpg|centre|vignette|upright=2.5|Additionneur série.]] ===L'additionneur à propagation de retenue=== L''''additionneur à propagation de retenue''' est aussi appelé l'additionneur ''ripple carry'', c'est son nom anglais. J'utiliserais occasionnellement le nom anglais dans ce qui suit, car celui-ci est plus court. Ilutilise un additionneur complet pour chaque colonne de l'addition. Pour gérer les retenues, il suffit ainsi de câbler des additionneurs complets les uns à la suite des autres, chacun envoyant sa retenue à la colonne suivante. [[File:Ripplecarryadder.png|centre|vignette|upright=2.5|Additionneur à propagation de retenue.]] Notons la présence de la retenue sortante, qui est utilisée pour détecter les débordements d'entier, ainsi que pour d'autres opérations. Le bit de retenue final est souvent stocké dans un registre spécial du processeur (généralement appelé ''carry flag''). Notez aussi, à droite du schéma précédent, l'entrée de retenue <math>\text{R}_\text{Entrée}</math>. Elle est très utile pour l'implémentation de certaines opérations comme l'inversion de signe, la soustraction, l'incrémentation, etc. Certains processeurs sont capables de faire une opération appelée ADC, ADDC ou autre nom signifiant ''Addition with Carry'', qui permet de faire le calcul A + B + Retenue (la retenue en question est la retenue sortante de l'addition précédente, stockée dans le registre ''carry flag''). Son utilité principale est de permettre des additions d'entiers plus grands que ceux supportés par le processeur. Par exemple, cela permet de faire des additions d'entiers 32 bits sur un processeur 16 bits. [[File:Adder Network 3 Bit Sum Delay 003.svg|vignette|upright=0.5|Propagation de retenue dans l'additionneur.]] Cet additionneur utilise très peu de portes logiques, ce qui fait qu'il était utilisé sur certains processeurs 8 et 16 bits, dont le budget en portes logiques était limité. Bien que très simple, cet additionneur est cependant peu performant. Son temps de calcul est proportionnel à la taille des opérandes. Par exemple, additionner deux opérandes de 32 bits prendra deux fois plus de temps que pour des opérandes de 16 bits. La raison est que les retenues doivent se propager à travers le circuit, du premier additionneur jusqu'au dernier. L'addition étant une opération fréquente, d'autres additionneurs ont été inventés. Ils utilisent des optimisations qui utilisent plus de circuits pour gagner en rapidité. Mais avant de voir ces optimisations, nous allons voir s'il est possible d'optimiser les additionneurs à propagation de retenue. ===L'additionneur à saut de retenue=== L'additionneur à propagation de retenue peut être optimisé de deux manières. La première accélère la propagation de la retenue, en agissant au niveau des additionneurs complets. La ''Manchester carry chain'' est une optimisation de ce type, mais on ne peut pas encore expliquer à ce stade du cours, car elle optimisait les additionneurs complets au niveau des transistors eux-mêmes. Elle a été utilisée sur de nombreux processeurs connus, comme le 8086 d'Intel ou le Z80. La seconde manière rend l'addition plus rapide dans certains cas. Le résultat est un additionneur dont le temps de calcul est variable. Le calcul prendra quelques cycles d'horloges avec certains opérandes, mais d'autres opérandes ne verront aucune amélioration. Il n'améliore pas le pire des cas, dans lequel la retenue doit être propagée du début à la fin, du bit de poids faible au bit de poids fort. Mais dans d'autres cas, il permet d'avoir le résultat en avance. L'optimisation en question donne l''''additionneur à saut de retenue''' (''carry-skip adder''). Il est composé en enchainant plusieurs additionneurs plus petits, qui additionnent 4/5 bits, rarement plus. De tels additionneurs de petite taille sont appelés des '''blocs''', dans ce qui suit. L'idée est de détecter précocement si la retenue entrante est propagée à travers tout le bloc. Si la retenue est propagée dans tous le bloc, on peut directement l'envoyer sur la sortie de retenue, la retenue saute le bloc entier. Dans le cas contraire, on doit calculer la retenue normalement. Le choix entre les deux est le fait d'un multiplexeur. Toute la difficulté est de savoir comment commander le multiplexeur. [[File:Carry skip adder, principe de base.png|centre|vignette|upright=2.5|Carry skip adder : principe de base]] Pour savoir si une retenue est propagée dans un bloc entier, il faut utiliser des additionneurs complets, qui ont en plus une sortie P indiquant que l'additionneur propage la retenue. Le bloc propage une retenue si chaque additionneur complet propage la retenue, donc s'ils ont tous leur sortie P à 1. Un simple ET logique suffit à déterminer si c'est le cas. Le signal de commande du multiplexeur est donc un vulgaire ET entre toutes les sorties P des additionneurs complets du bloc. [[File:Additionneur à saut de retenue.png|centre|vignette|upright=2.5|Calcul de la commande du MUX.]] Voici ce que ça donne pour un bloc de 4 bits : [[File:CSAdder4Bit.svg|centre|vignette|upright=1.5|Additionneur ''carry skip'' : bloc de 4 bits.]] L'additionneur à saut de retenue est construit en assemblant plusieurs blocs de ce type. [[File:BCSAdder16Bit.svg|centre|vignette|upright=3|Additionneur à saut de retenue.]] Les blocs sont tous identiques dans le cas le plus simple, mais il est possible d'utiliser des blocs de taille variable. Par exemple, le premier bloc peut avoir des opérandes de 6 bits, le second des opérandes de 7 bits, etc. Faire ainsi permet de gagner un petit peu en performances, si la taille de chaque bloc est bien choisie. La raison est une question de temps de propagation des retenues. La retenue met plus de temps à se propager à travers 8 blocs qu'à travers 4, ce qui prend plus de temps qu'à travers 2 blocs, etc. En tenir compte fait que la taille des blocs tend à augmenter ou diminuer quand on se rapproche des bits de poids fort. ===L'additionneur à sélection de retenue=== L''''additionneur à sélection de retenue''' utilise aussi des blocs, comme les additionneurs précédents. L'addition se fait en deux versions : une avec la retenue du bloc précédent valant zéro, et une autre version avec la retenue du bloc précédent valant 1. Il suffira alors de choisir le bon résultat avec un multiplexeur, une fois cette retenue connue. On gagne ainsi du temps en calculant à l'avance les valeurs de certains bits du résultat, sans connaître la valeur de la retenue. Petit détail : sur certains additionneurs à sélection de retenue, les blocs de base n'ont pas la même taille. Cela permet de tenir compte des temps de propagation des retenues entre les blocs. [[File:Additionneur à sélection de retenue.png|centre|vignette|upright=1.5|Additionneur à sélection de retenue avec seulement deux blocs.]] Dans les exemples du dessus, chaque sous-additionneur étaient des additionneurs à propagation de retenue. Mais ce n'est pas une obligation, et tout autre type d’additionneur peut être utilisé. Par exemple, on peut faire en sorte que les sous-additionneurs soient eux-mêmes des additionneurs à sélection de retenue, et poursuivre ainsi de suite, récursivement. On obtient alors un '''additionneur à somme conditionnelle''', plus rapide que l'additionneur à sélection de retenue, mais qui utilise beaucoup plus de portes logiques. ===Les additionneurs à anticipation de retenue=== Les '''additionneurs à anticipation de retenue''' calculent chaque retenue sans avoir à propager les retenues précédentes. Au lieu de calculer les retenues une par une, ils calculent toutes les retenues en parallèle, à partir des bits des opérandes. Une fois les retenues pré-calculées, il suffit de les additionner avec les deux bits adéquats, pour obtenir le résultat. Ces additionneurs sont composés de deux parties : * un circuit qui pré-calcule les retenues, sans les propager, directement à partir des opérandes ; * d'une couche d'additionneurs complets, qui additionnent chacun deux bits d'opérande et la retenue pré-calculée. [[File:Additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Additionneur à anticipation de retenue.]] Le calcul des retenues se fait en deux étapes. La première détermine si les retenues sont propagées ou générées, pour chaque colonne. Elle détermine, pour chaque colonne, les bits P et G qui indiquent respectivement : qu'une retenue a été générée sur cette colonne, que la colonne propage la retenue précédente. La seconde étape utilise ces signaux P et G pour déterminer la retenue sur chaque colonne. Le circuit de calcul des retenues est donc composé de deux parties : une couche de demi-additionneurs pour générer les signaux P et G, un circuit de calcul des retenues proprement dit. [[File:Circuit complet d'un additionneur à anticipation de retenue.png|centre|vignette|upright=1.5|Circuit complet d'un additionneur à anticipation de retenue.]] Pour rappel, la retenue de la colonne i, notée <math>C_i</math> est égale à : : <math>G_i + (P_i . C_{i-1})</math>, avec G le signal de génération de retenue, P le signal de propagation de retenue. Si on utilisait cette formule sans trop réfléchir, on retomberait sur un additionneur à propagation de retenue inutilement compliqué. L'astuce des additionneurs à anticipation de retenue consiste à remplacer le terme Ci−1 par sa valeur calculée avant. Par exemple, je prends un additionneur 4 bits. Je dispose de deux nombres A et B, contenant chacun 4 bits : A3, A2, A1, et A0 pour le nombre A, et B3, B2, B1, et B0 pour le nombre B. Si j'effectue les remplacements, j'obtiens les formules suivantes : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Ces formules nous permettent de déduire la valeur d'une retenue directement : il reste alors à créer un circuit qui implémente ces formules, et le tour est joué. [[File:Four bit adder with carry lookahead.svg|centre|vignette|upright=1.5|Additionneur à anticipation de retenue de 4 bits.]] Plus haut, j'ai dit que le circuit était composé de trois couches : une couche de demi-additionneur pour les signaux P et G ; un circuit d'anticipation de retenue, puis l'addition finale. Mais les deux bits d'opérandes sont déjà additionnés dans la couche de demi-additionneur, autant réutiliser le résultat pour l'additionner à la retenue. Pour éliminer toute redondance de ce type, il est possible d'utiliser des additionneurs partiels (des additionneurs où la sortie de retenue a été remplacée par deux sorties P et G). L'additionneur final est alors composé de plusieurs additionneurs complets de ce type, couplé à un circuit d'anticipation de retenue. [[File:Cla4bits.png|centre|vignette|upright=2.5|Additionneur à anticipation de retenue de 4 bits.]] Les additionneurs à anticipation de retenue sont plus rapides que les additionneurs à propagation de retenue. La raison est que les retenues sont calculées rapidement, dans un temps plus petit qu'en propageant la retenue. Pour rentrer dans les détails mathématiques, le temps de calcul n'est pas proportionnel au nombre de bits, mais proportionnel au logarithme de ce nombre de bits. Par contre, le gain en temps de calcul s'accompagne d'un cout en portes logiques conséquent. Le circuit qui calcule les retenues anticipées utilise beaucoup de portes logiques. ===Les additionneurs à calcul parallèle de préfixe=== Du fait du cout en portes logiques, utiliser un additionneur à anticipation de retenue est une solution pratique pour additionner 4 ou 8 bits. Mais pour des opérandes plus grands, de 16 ou 32 bits, cela utiliserait trop de portes logiques. Une partie de ce cout en portes logiques est cependant lié à des redondances. Si on analyse deux retenues différentes, à des colonnes différentes. Les circuits qui calculent ces deux retenues seront différents, mais ils contiendront des sous-circuits identiques. Pour vous en rendre compte, reprenons les quatre équations obtenues précédemment et essayez de trouver des redondances : * C1 = G0 + ( P0 · C0 ) ; * C2 = G1 + ( P1 · G0 ) + ( P1 · P0 · C0 ) ; * C3 = G2 + ( P2 · G1 ) + ( P2 · P1 · G0 ) + ( P2 · P1 · P0 · C0 ) ; * C4 = G3 + ( P3 · G2 ) + ( P3 · P2 · G1 ) + ( P3 · P2 · P1 · G0 ) + ( P3 · P2 · P1 · P0 · C0 ). Vous devriez trouver : * le terme ''P0 · C0'' dans toutes les lignes ; * les termes ''P1 · P0 · C0'' et ''P1 · P0'' dans les trois dernières lignes ; * le terme ''P2 · P1 · P0 · C0'' ; ''P2 · P1 · G0'' et ''P2 · G1'' dans les deux dernières lignes. Il existe plusieurs manières d'exploiter de telles redondances, exploitées dans les '''additionneurs à calcul parallèle de préfixe'''. L'optimisation apportée est de générer des signaux ''propagate'' et ''generate'' pour des groupes de 2, 3, 4, ..., N colonnes. Par exemple, il est possible de générer un signal ''P 0 vers 3'', qui indique si la retenue de la première colonne est propagée jusqu'à la 4ème colonne. Un autre exemple est un signal qui indique qu'une retenue a été générée entre les colonnes 4 à 7 génèrent une retenue ou non. En clair, les signaux P et G ont maintenant un intervalle, qui précise de quelle colonne vers quelle colonne se fait la propagation, ou entre quelles colonnes se fait la génération. Il est possible de combiner les signaux P et G de deux groupes de colonne, s'ils sont contiguës (ils peuvent aussi se recouvrir). Par exemple, il est possible de calculer les bits P et G pour les colonnes 0 à 10, à partir des deux signaux P/G des colonnes 0-4 et 5-10. Pour cela, les équations sont assez simples. Si je prends deux groupes nommés A et B, avec A pour les colonnes de poids fort et B celles de poids faible, on a : : <math>P_{sortie} = P_A . P_B</math> : <math>G_{sortie} = G_A . P_A . G_B</math> Pour les bits des colonnes 2, 4, 8, 16, 32, 64, et autres, le calcul est simple. L'idée est de grouper les colonnes par groupes de 2. Puis, on calcule chaque groupe de 4 bits à partir de deux groupes de 2. Puis les groupes de 8 bits sont calculés à partir de deux groupes de 4 bits, et ainsi de suite pour toute puissance de deux. [[File:Squelette d'un additionneur à calcul parallèle de préfixe.jpg|centre|vignette|upright=2|Squelette d'un additionneur à calcul parallèle de préfixe]] Les seules difficultés surviennent pour les colonnes dont le nombre n'est pas une puissance de deux. Il y a plusieurs manières pour subdiviser ces colonnes en intervalles plus petits et combiner le tout. Et elles donnent chacune des additionneurs différents. Ils portent les noms d''''additionneur de Ladner-Fisher''', d''''additionneur de Brent-Kung''', d''''additionneur de Kogge-Stone''', etc. Dans le cas général, l'additionneur de Kogge-Stone est un des plus rapide, mais aussi un des plus gourmand en circuits, alors que c'est l'inverse pour l'additionneur de Brent-Kung. Les deux additionneurs sont illustrés ci-dessous, pour des opérandes de 8 bits. Dans ceux-ci, chaque losange calculent les bits P et G, à partir des signaux P et G de deux groupes précédents. {| |[[File:Brent-kung-8-bit.png|vignette|Brent-kung-8-bit]] |[[File:Kogge-stone-8-bit.png|vignette|upright=1.2|Kogge-stone-8-bit]] |} ===Le calcul parallèle de la retenue=== L'anticipation de retenue est très rapide, mais utilise beaucoup de circuits, même en utilisant le calcul parallèle de préfixe. Les additionneurs à propagation de retenue font eux le compromis inverse. Mais il existe des intermédiaires, qui visent à obtenir un compromis entre performance et cout en portes logiques. Un de ces compromis découpe un additionneur de 16/32/64 bits en additionneurs de 4/5 bits, qui sont enchainés en utilisant la propagation de retenue. Par contre, ces petits additionneurs de 4/5 bits utilisent l'anticipation de retenue. Ces additionneurs simples seront nommés ''blocs'' dans ce qui suit. Par exemple, on peut utiliser 4 additionneurs à anticipation de retenue de 4 bits, et propager les retenues entre eux. Le premier bloc calcule une retenue, qui est propagée au second bloc. Le second bloc calcule lui aussi une retenue, qui est propagée au troisième bloc, etc. [[File:4008 Functional Diagram.svg|vignette|upright=1|4008 Functional Diagram]] Le gain en performance est significatif, mais il est possible de faire presque aussi rapide, tout en économisant beaucoup de circuits. L'idée est de simplifier les additionneurs 4 bits, afin de ne pas utiliser une anticipation de retenue complète. L'anticipation de retenue n'est utilisée que pour la retenue sortante, alors que les bits de somme sont calculées avec propagation de retenue. La retenue sortante est donc calculée en parallèle de l'addition. Chaque bloc contient, à côté d'un additionneur proprement dit, un circuit qui calcule la retenue sortante. Il existe de nombreuses manières de calculer la retenue sortante. Le gain en portes logiques est assez significatif. En effet, on se passe de circuits d'anticipation de retenue pour les 4 bits de somme, on ne garde que celui pour la retenue sortante. Le fait d'utiliser la propagation de retenue pour calculer les 4 bits de somme est censé avoir un léger cout en performance, mais il se trouve que ce cout est très faible. En effet, le résultat n'est connu qu'une fois les retenues propagées jusqu'au dernier bloc. Et malgré l'anticipation des retenues, la propagation est assez lente. les additionneurs à propagation de retenue auront terminé leur travail bien avant. Un exemple est celui de l'additionneur CMOS 4008, un additionneur de 4 bit. Il est composé en trois sections. Une première couche de demi-additionneurs calcule les signaux P et G utilisés à la fois pour l'anticipation de la retenue sortante, que pour calculer les bits de somme. Le circuit de calcul de la retenue sortante utilise l'anticipation de retenue. Le reste du circuit fait l'addition en propageant les retenues. [[File:CMOS 4008, circuit découpé en sections.png|centre|vignette|upright=1.5|CMOS 4008, circuit découpé en sections]] ===Les additionneurs à anticipation de retenue multi-niveau=== Les additionneurs précédents mixent anticipation et propagation de retenue. Ceux que nous allons voir utilisent des blocs, mais utilisent l'anticipation de retenue entre les blocs. Les blocs utilisés peuvent être un additionneur à propagation de retenue, ou à anticipation de retenue, peu importe. Ce qui compte est que la retenue entrante de chaque bloc est calculée par anticipation de retenue. Par exemple, il est possible de créer un additionneur 16 bits en utilisant 4 additionneurs/blocs de 4 bits, couplé à un circuit d’anticipation de retenue par bloc. Pour cela, les additionneurs de 4 bits doivent fournir deux sorties P et G. Les deux sorties indiquent que le bloc soit a généré une retenue, soit a propagé la retenue entrante. Par propagé, on veut dire que la retenue entrante du bloc s'est retrouvée sur la sortie de retenue du bloc. C'est le cas si les 4 colonnes propagent la retenue, ce qui signifie que : : <math>P_\text{4 bits} = P_0 \cdot P_1 \cdot P_2 \cdot P_3</math> Pour la génération, cela veut dire qu'une colonne a générée une retenue, qui a été propagée jusqu'à la sortie. En clair, pour chaque colonne, il faut que le G = 1, et que les signaux P des colonnes soient à 1. Pour les 4 colonnes, cela donne : : <math>G_\text{4 bits} = G_3 + G_2 \cdot P_3 + G_1 \cdot P_3 \cdot P_2 + G_0 \cdot P_3 \cdot P_2 \cdot P_1</math> [[File:Cla4bitsPG.png|centre|vignette|upright=2|Additionneur à anticipation de retenue de 4 bits.]] Pour combiner 4 blocs de 4 bits, on devra donc combiner 4 bits P et G, avec un circuit d'anticipation de retenue. [[File:16-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 16 bits.]] Il est même possible d'aller plus loin et de combiner 4 additionneurs précédents pour obtenir un additionneur 64 bits. [[File:64-bit lookahead carry unit.svg|centre|vignette|upright=2|Additionneur à anticipation de retenue de 64 bits.]] Le résultat est un additionneur à plusieurs niveaux d’anticipation de retenue. Une anticipation de retenue dans un blocs de 4 bits (facultative), entre blocs de 4 bits, entre blocs de 16 bits. La même logique peut être utilisée avec des blocs de taille différente de 4, 16 et 64 bits. ==L'addition signée et la soustraction== Après avoir vu l'addition, il est logique de passer à la soustraction, les deux opérations étant très proches. Si on sait câbler une addition entre entiers positifs, câbler une soustraction n'est pas très compliqué. De plus, la soustraction permet de faire des additions de nombres signés. ===Le soustracteur à propagation de retenue=== [[File:Half Subtractor Vektor.svg|vignette|Demi-soustracteur.]] Dans le chapitre sur les incrémenteurs/décrémenteurs, nous avons vu un circuit qui peut soustraire deux bits. Celui-ci est appelé un '''demi-soustracteur'''. Il ressemble beaucoup à un demi-additionneur, les différences se résumant à une porte NON ajoutée pour le calcul de la retenue. Il implémente la table de soustraction, qui est très simple en binaire : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Pour soustraire deux nombres entiers, on peut adapter l'algorithme de soustraction utilisé en décimal, celui que vous avez appris à l'école. Celui-ci ressemble fortement à l'algorithme d'addition : on soustrait les bits de même poids, et on propage éventuellement une retenue sur la colonne suivante. À la différence de l'addition, la retenue est soustraite, et non ajoutée. En clair, une soustraction en binaire demande de faire deux soustraction : pour chaque bit de la première opérande, on soustrait le bit associé de la seconde, puis on soustrait la retenue entrante. [[File:Algebra1 05 fig014.svg|centre|vignette|Soustraction en binaire, avec les retenues en rouge.]] Pour cela, comme pour l'additionneur, deux demi-soustracteurs peuvent être combinés pour donner un '''soustracteur complet'''. Le calcul de la retenue se fait en combinant les deux retenues des demi-soustracteurs avec une porte OU. Les soustracteurs complets sont utilisés pour créer des soustracteurs à propagation de retenue ou tout autre circuit soustracteur, sur le même modèle que les additionneurs. [[File:FullSubtractor.svg|centre|vignette|upright=2|Soustracteur complet.]] Un défaut est que cela ne fonctionne bien que pour les additionneurs/soustracteurs à propagation de retenue, mais l'anticipation de retenue et les autres optimisations ne marchent pas bien avec des soustracteurs complets. L'anticipation de retenue ne marche pas de la même manière entre addition et soustraction, par exemple. Les signaux de propagation et de génération de retenue ne sont pas générés pareil, idem pour la manière de les combiner. Il est toujours possible de créer un soustracteur avec ces techniques, mais aucune mutualisation de circuit ne sera possible. Ce qui n'est pas le cas avec les solutions que nous allons voir dans ce qui suit. Il est possible de fusionner un additionneur à propagation de retenue et un soustracteur de même type. Pour cela, il suffit de remarquer que les demi-soustracteurs et les demi-additionneurs se ressemblent beaucoup. La seule différence entre les deux est une vulgaire porte NON. En remplaçant cette porte NON par un inverseur commandable, on obtient un circuit qui sert soit de demi-additionneur, soit de demi-soustracteur, suivant ce qu'on envoie sur l'entrée de commande. Ci-dessous est illustré ce que donne ce remplacement pour un soustracteur complet. Le résultat est un '''additionneur/soustracteur à propagation de retenue'''. [[File:Additionneur-soustracteur complet.png|centre|vignette|upright=2|Additionneur-soustracteur complet]] ===L'additionneur-soustracteur pour opérandes codées en complément à deux=== Étudions le cas de la soustraction en complément à deux, dans l'objectif de créer un circuit soustracteur. Vous savez sûrement que a−b et a+(−b) sont deux expressions équivalentes. Et en complément à deux, − b = not(b) + 1. Dit autrement, a − b = a + not(b) + 1. On pourrait se dire qu'il faut deux additionneurs pour faire le calcul, mais la majorité des additionneurs possède une entrée de retenue pour incrémenter le résultat de l'addition. Un soustracteur en complément à deux est donc simplement composé d'un additionneur et d'un inverseur. [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Soustracteur en complément à deux.]] Il est possible de créer un circuit capable d'effectuer soit une addition, soit une soustraction : il suffit de remplacer l'inverseur par un inverseur commandable, qui peut être désactivé. On a vu comment créer un tel inverseur commandable dans le chapitre sur les circuits combinatoires. On peut remarquer que l'entrée de retenue et l'entrée de commande de l'inverseur sont activées en même temps : on peut fusionner les deux signaux en un seul. [[File:Additionneur-soustracteur en complément à deux.png|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux.]] Une implémentation alternative est la suivante. Elle remplace l'inverseur commandable par un multiplexeur. [[File:4-bit ripple carry adder-subtracter.svg|centre|vignette|upright=2|Additionneur-soustracteur en complément à deux, version alternative.]] ===L'additionneur-soustracteur pour opérandes codées en signe-magnitude=== Passons maintenant aux nombres codés en signe-valeur absolue, les deux opérandes étant notées A et B. Suivant les signes des deux opérandes, on a quatre cas possibles : A + B, A − B (B négatif), −A + B (A négatif) et −A − B (A et B négatifs). Une astuce est que le circuit n'a besoin que de calculer A + B et A − B : il peut les inverser pour obtenir − A − B ou B − A. A + B et A − B peuvent se calculer avec un additionneur-soustracteur, reste à corriger le résultat. Il suffit de lui ajouter un inverseur commandable pour obtenir le circuit d'addition finale. [[File:Additionneur en signe-valeur absolue.png|centre|vignette|upright=2|Additionneur en signe-valeur absolue.]] Toute la difficulté tient dans le calcul du bit de signe du résultat, quand interviennent des soustractions. Autant l'addition de deux nombres de même signe (A + B et −A − B) ne pose aucun problème, autant les soustractions posent problème (A − B et −A + B). Suivant que <math>A<B</math> ou que <math>A>B</math>, le signe du résultat ne sera pas le même. Déterminer le signe du résultat se fait en regardant les bits de débordement d'entier, comme on le verra plus bas. ===L'additionneur-soustracteur pour opérandes codées en représentation par excès=== Passons maintenant aux nombres codés en représentation par excès. On pourrait croire que ces nombres s'additionnent comme des nombres non-signés, mais ce serait oublier la présence du biais, qui pose problème. Dans les cas de nombres signés gérés avec un biais, voyons ce que donne l'addition de deux nombres : : <math>( n_1 + biais ) + ( n_2 + biais ) = n_1 + n_2 + 2 \times biais</math> Or, le résultat correct serait : : <math>n_1 + n_2 + biais</math> En effectuant l'addition telle quelle, le biais est compté deux fois. On doit donc le soustraire après l'addition pour obtenir le résultat correct. Même chose pour la soustraction qui donne ceci : : <math>(n_1 + biais) - (n_2 + biais) = n_1 - n_2</math> Or, le résultat correct serait : : <math> ( n_1 - n_2 ) + biais </math> Il faut rajouter le biais pour obtenir l'exposant correct. On a donc besoin de deux additionneurs/soustracteurs : un pour additionner/soustraire les représentations binaires des opérandes, et un autre pour ajouter/retirer le biais en trop/manquant. ==L'additionneur BCD== Maintenant, voyons un additionneur qui additionne deux entiers au format BCD. Pour cela, nous allons devoir passer par deux étapes. La première est de créer un circuit capable d'additionneur deux chiffres BCD. Ensuite, nous allons voir comment enchaîner ces circuits pour créer un additionneur BCD complet. ===L'additionneur BCD qui fait l'opération chiffre par chiffre=== Nous allons commencer par voir un additionneur qui additionne deux chiffres en BCD, une sorte d'équivalent BCD de l'additionneur complet. Il fournit un résultat sur 4 bits et une retenue qui est mise à 1 si le résultat dépasse 10 (la limite d'un chiffre BCD). Les deux opérandes sont des chiffres BCD codés sur 4 bits et sont additionnés en binaire par un additionneur des plus normaux, similaire à ceux vus plus haut. Le résultat est alors un entier codé en binaire, sur 5 bits, qu'on corrige/convertit pour obtenir un chiffre BCD et une retenue sortante. Pour corriger le résultat, une idée intuitive serait de prendre le résultat et de faire une division par 10. Le quotient donne la retenue, alors que le reste est le résultat, le chiffre BCD. Mais un circuit diviseur par 10 utilise beaucoup de portes logiques, ce qui ne vaut pas le coup. Une autre méthode détecte si le résultat est égal ou supérieur à 10, ce qui correspond à un "débordement" (on dépasse les limites d'un chiffre BCD). Si le résultat est plus petit que 10, il n'y a rien à faire : le résultat est bon et la retenue est de zéro. Par contre, si le résultat vaut 10 ou plus, il faut corriger le résultat et générer une retenue à 1. Il faut donc ajouter un circuit qui détecte si le résultat est supérieur à 9, qui calcule directement la retenue. Ce circuit peut se fabriquer simplement à partir de sa table de vérité, ou en utilisant les techniques que nous verrons dans un chapitre ultérieur sur les comparateurs. La solution la plus simple est clairement d'utiliser la table de vérité, ce qui est très simple, assez pour être laissé en exercice au lecteur. Pour comprendre comment corriger le résultat, établissons une table de vérité qui associe le résultat et le résultat corrigé. L'entrée vaut au minimum 10 et au maximum 9 + 9 = 18. On considère la sortie comme un tout, la retenue étant un 5ème bit, le bit de poids fort. {|class="wikitable" |- ! colspan="5" | Entrée ! ! rowspan="10" | ! Retenue ! Résultat corrigé (sans retenue) ! interprétation de la sortie en binaire (retenue inclue) |- | 0 || 1 || 0 || 1 || 0 | (10) | 1 || 0000 | (16) |- | 0 || 1 || 0 || 1 || 1 | (11) | 1 || 0001 | (17) |- | 0 || 1 || 1 || 0 || 0 | (12) | 1 || 0010 | (18) |- | 0 || 1 || 1 || 0 || 1 | (13) | 1 || 0011 | (19) |- | 0 || 1 || 1 || 1 || 0 | (14) | 1 || 0100 | (20) |- | 0 || 1 || 1 || 1 || 1 | (15) | 1 || 0101 | (21) |- | 1 || 0 || 0 || 0 || 0 | (16) | 1 || 0110 | (22) |- | 1 || 0 || 0 || 0 || 1 | (17) | 1 || 0111 | (23) |- | 1 || 0 || 0 || 1 || 0 | (18) | 1 || 1000 | (24) |} En analysant le tableau, on voit que pour corriger le résultat, il suffit d'ajouter 6. La raison est que le résultat déborde d'un nibble à 16 en binaire, mais à 10 en décimal : il suffit d'ajouter la différence entre les deux, à savoir 6, et le débordement binaire fait son travail. Donc, la correction après une addition est très simple : si le résultat dépasse 9, on ajoute 6. On peut maintenant implémenter l'additionneur BCD, en combinant le comparateur avec 10, le circuit de correction, et l'additionneur. La première solution calcule deux versions du résultat : la version corrigée, la version normale. Le choix entre les deux est réalisée par un multiplexeur, commandé par le comparateur. [[File:Additionneur BCD.png|centre|vignette|upright=1.5|Additionneur BCD]] L'autre solution utilise un circuit commandable qui soit additionne 6, soit ne fait rien. Le choix entre les deux est commandé par le bit calculé par le comparateur. [[File:Additionneur BCD, seconde version.png|centre|vignette|upright=1.5|Additionneur BCD, seconde version.]] Une version alternative du circuit précédent est la suivante. Il contient deux additionneurs : un pour additionner les deux chiffres BCD, un autre pour additionner 6 si besoin. Le résultat du comparateur est directement utilisé pour générer l'opérande du second additionneur : 0 ou 6. Le circuit est simple à concevoir, mais gaspille beaucoup de circuit. Idéalement, il vaudrait mieux utiliser un circuit combinatoire d'addition avec une constante. [[File:Adder 4 Bit BCD.svg|centre|vignette|upright=2|Additionneur BCD, circuit complet.]] Pour obtenir un additionneur BCD complet, il suffit d’enchaîner les additionneurs précédents, comme on le ferait avec les additionneurs complets dans un additionneur à propagation de retenue. Au final, l'additionneur BCD est beaucoup plus compliqué qu'un additionneur normal, car il rajoute un comparateur ">9", un petit additionneur pour ajouter 6 et éventuellement d'autres circuits. De plus, il est difficile d'appliquer les optimisations disponibles sur les additionneurs non-BCD. Notamment, les circuits d'anticipation de retenue sont totalement à refaire et le résultat est relativement compliqué. C'est ce qui explique pourquoi le BCD a progressivement été abandonné au profit du binaire simple. La soustraction en BCD se fait comme en binaire : le nombre à soustraire est remplacé par son complément, le circuit additionne le complément et l'autre opérande, le débordement d'entier fait que le résultat marche. Sauf qu'ici, le complément est un complément à 9. Il se calcule chiffre par chiffre : chaque chiffre est remplacé par (9 - le chiffre en question). ===L'additionneur BCD par ajustement décimal=== L'additionneur BCD précédent effectuait son travail chiffre BCD par chiffre BCD, mais il existe des additionneurs BCD qui font autrement. Sur les premiers processeurs x86, il n'y avait pas d'opération d'addition BCD proprement dit, seulement une addition binaire normale de 8, 16 ou 32 bits. Par contre, elle était secondée par une opération dite d''''ajustement décimal''' qui transformait un nombre binaire en nombre codé en BCD. L'opération d'ajustement décimal prenait un opérande de 8 bits codé en binaire et fournissait un résultat de la même taille, c'est à dire deux chiffres BCD. Effectuer une addition BCD demandait donc de faire deux opérations à la suite : une addition binaire simple, suivie par l'opération d'ajustement décimal. Cela permettait de gérer des nombres entiers en binaire usuel et des entiers BCD sans avoir deux instructions d'addition séparées pour les deux, sans compter que cela simplifiait aussi les circuits d'addition. L'ajustement décimal s'effectue en ajoutant une constante bien précise à l'opérande à convertir en BCD. L'idée est que la constante est découpée en morceaux de 4 bits, correspondant chacun à un chiffre BCD de l'opérande, chaque morceau contenant soit un 0, soit 6. Cela permet d'ajouter soit 0, soit 6, à chaque chiffre BCD, et donc de le corriger. La propagation des retenues d'un chiffre à l'autre est effectuée automatiquement par l'addition binaire de la constante. L'opération d'ajustement décimal calcule automatiquement la constante. Elle découpe l'opérande en ''nibbles'', vérifie si chaque ''nibble'' est supérieur ou égal à 10, puis détermine la valeur de chaque ''nibble'' de la constante finale. Par exemple, si je prends l'opérande 1001 1110, le ''nibble'' de poids faible déborde, alors que celui de poids fort non. La constante sera donc 0000 0110 : 0x06. Inversement, si le ''nibble'' de poids fort déborde et pas celui de poids faible, la constante sera alors 0x60. Et la constante est de 0x66 si les deux ''nibbles'' débordent, de 0x00 si aucun ne déborde. Le circuit d’ajustement décimal est donc composé de trois étapes : deux étapes pour calculer la constante, et un circuit d'addition pour additionner cette constante au nombre de départ. La première étape découpe l'opérande en morceaux de 4 bits, en chiffres BCD, et vérifie si chacun d'entre eux vaut 10 ou plus. La seconde étape prend les résultats de la première étape, et les combine pour calculer la constante. Enfin, on trouve l'addition finale, qui était réalisée par un circuit d'addition utilisé à la fois pour l'ajustement décimal et l'addition binaire. La différence entre une addition normale et une opération d'ajustement décimal tient dans le fait que les deux premières étapes sont désactivées dans une addition normale. [[File:Additionneur BCD parallèle.png|centre|vignette|upright=1.5|Additionneur BCD parallèle]] ===L'additionneur biquinaire=== Les entiers BCD ne sont qu'un des encodages hybrides entre décimal et binaire. L'encodage biquinaire est l'un d'entre eux et nous allons faire un rappel rapide à ce sujet. Pour simplifier, un chiffre encodé en biquinaire est composé de deux parties : un bit, couplé à une partie quinaire encodée en représentation ''one-hot''. La partie quinaire encode un nombre allant de 0 à 4, ce qui prend 5 bits (0, 1, 2, 3 et 4). Le bit indique s'il faut ou non ajouter 5 à la valeur encodée par la partie quinaire. Ainsi, on peut coder tous les nombres de 0 à 9. Additionner deux nombres de biquinaire demande donc d'additionner deux parties quinaires encodées en ''one-hot'' et d'additionner deux bits. Mais attention : il faut tenir compte de la retenue de l'addition des parties quinaires. Et idéalement, il faut aussi tenir compte d'une retenue entrante, provenant de l'addition de la colonne de chiffres précédente. Toute la difficulté vient de la création de l'additionneur ''one-hot''. Heureusement, vu qu'il n'y a que 4-5 bits à additionner, il est souvent fabriqué à partir de sa table de vérité. [[File:Additionneur bi-quinaire.png|centre|vignette|upright=2|Additionneur bi-quinaire]] Un avantage du biquinaire est que le calcul du complément à 9 est très simple. Il faut pour cela : inverser la partie binaire avec une porte NON, puis inverser l'ordre des bits de la partie quinaire. Concrètement, le bit de poids faible devient le bit de poids fort, et ainsi de suite. Par exemple, une partie quinaire 01000 devient 00010, 10000 devient 00001, 00100 ne change pas, etc. Le tout peut se calculer avec une porte NON et 5 multiplexeurs. ===L'additionneur BCD avec calculs intermédiaires en biquinaire=== L'ordinateur IBM 1401, un ancien ''mainframe'' des années 60, utilisait un additionneur BCD un peu particulier. Les nombres étaient encodés en BCD dans la mémoire de l'ordinateur, mais les circuits de calcul utilisaient la représentation biquinaire. Lors d'un calcul, le processeur de l'ordinateur traduisait les chiffres BCD en représentation biquinaire, faisait une addition en biquinaire, avant de traduire le résultat en BCD normal. Pour être précis, l'IBM 1401 utilisait une variante du biquinaire. L'encodage biquinaire de l'IBM 1401 est le suivant : la partie binaire disait si le chiffre était pair ou non, la partie quinaire encodait les valeurs 0, 2, 4, 6 et 8. Le chiffre se calculait en additionnant la partie binaire (0 ou 1) au nombre pair encodé par la partie quinaire. Si l'IBM 1401 utilisait cette variante du biquinaire, c'est car elle donnait des circuits de conversion BCD-biquinaire plus économes en portes logiques et plus rapides. La partie binaire est le bit de poids faible du chiffre BCD, la partie biquinaire est calculée par un simple décodeur qui prend en entrée le chiffre BCD, amputé de son bit de poids faible. La traduction inverse demande d'utiliser un encodeur, à la place du décodeur. Par contre, le circuit d'addition biquinaire était plus compliqué du fait de la gestion des retenues. L'addition des parties binaires et quinaires se faisait en parallèle, dans deux additionneurs séparés. Cependant, l'addition des parties binaire fournit une retenue, qu'il faut prendre en compte. Pour cela, l'IBM 1401 disposait d'un troisième additionneur qui fournissait le résultat final, encodé en biquinaire. [[File:Additionneur bi-quinaire de l'IBM 1401.png|centre|vignette|upright=2|Additionneur biquinaire de l'IBM 1401]] Une implémentation moderne demanderait d'utiliser des portes ET combinées à des portes OU, le circuit pouvant être construit simplement à partir de sa table de vérité. Sur l'IBM 1401, le circuit était cependant différent, en raison de l'utilisation de OU câblés, des croisements de fils qui fonctionnent comme des portes OU, que nous n'avons pas encore vu pour le moment, mais qui seront détaillés dans quelques chapitres. Les OU câblés étaient utilisés pour simplifier le design du circuit, mais demandaient des portes logiques spécifiques, ce qui collait avec le fait que ce ''mainframe'' utilisait des transistors en Germanium. L'implémentation exacte est décrite dans cet article de blog, mais je ne recommande sa lecture qu'à ceux qui savent ce qu'est un OU câblé : * [https://www.righto.com/2015/10/qui-binary-arithmetic-how-1960s-ibm.html Qui-binary arithmetic: how a 1960s IBM mainframe does math]. ==Les débordements d'entier lors d'une addition/soustraction== Les instructions arithmétiques manipulent des entiers codés sur un nombre fixe de bits, qui ne peuvent prendre leurs valeurs que dans un intervalle. Pour les nombres positifs, un ordinateur qui code ses entiers sur n bits pourra coder tous les entiers allant de 0 à <math>2^n -1</math>. Pour les nombres négatifs, l'intervalle est différent et dépend de la représentation utilisée. Dans le cas général, l'ordinateur peut coder les valeurs comprises de <math>N_\text{min}</math> à <math>N_\text{max}</math>. Si le résultat d'un calcul sort de cet intervalle, il ne peut pas être représenté par l'ordinateur et il se produit ce qu'on appelle un '''débordement d'entier'''. La '''valeur haute de débordement''' désigne la première valeur qui est trop grande pour être représentée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 0 et 7, la valeur haute de débordement est égale à 8. On peut aussi définir la '''valeur basse de débordement''', qui est la première valeur trop petite pour être codée par l'ordinateur. Par exemple, pour un ordinateur qui peut coder tous les nombres entre 8 et 250, la valeur basse de débordement est égale à 7. Pour les nombres entiers, la valeur haute de débordement vaut <math>N_\text{max} + 1</math> , alors que la valeur basse vaut <math>N_\text{min} - 1</math> (avec <math>N_\text{max}</math> et <math>N_\text{min}</math> respectivement la plus grande et la plus petite valeur codable par l'ordinateur). ===La correction des débordements d'entier : l'arithmétique saturée=== Quand un débordement d'entier survient, tous les circuits de calcul ne procèdent pas de la même manière. Dans les grandes lignes, il y a deux réactions possibles : soit on corrige automatiquement le résultat du débordement, soit on ne fait rien et on se contente de détecter le débordement. Si le débordement n'est pas corrigé automatiquement, le circuit ne conserve que les bits de poids faibles du résultat. Les bits en trop sont simplement ignorés. On dit qu'on utilise l''''arithmétique modulaire'''. Le problème avec ce genre d'arithmétique, c'est qu'une opération entre deux grands nombres peut donner un résultat très petit. Par exemple, si je dispose de registres 4 bits et que je souhaite faire l'addition 1111 + 0010 (ce qui donne 15 + 2), le résultat est censé être 10001 (17), ce qui est un résultat plus grand que la taille d'un registre. En conservant les 4 bits de poids faible, j’obtiens 0001 (1). En clair, un résultat très grand est transformé en un résultat très petit. Cela peut poser problèmes si on travaille uniquement avec des nombres positifs, mais c'est aussi utilisé pour coder des nombres en complément à deux. D'autres circuits utilisent ce qu'on appelle l''''arithmétique saturée''' : si un calcul génère un débordement, on arrondi le résultat au plus grand entier supporté par le circuit. Les circuits capables de calculer en arithmétique saturée sont un peu plus complexes, vu qu'il faut rajouter des circuits pour corriger le résultat en cas de débordement. Il suffit généralement de rajouter un ''circuit de saturation'', qui prend en entrée le résultat et le corrige en cas de débordement. Ce circuit de saturation met la valeur maximale en sortie si un débordement survient, mais se contente de recopier le résultat du calcul sur sa sortie s'il n'y a pas de débordement. Typiquement, il est composé d'une couche de multiplexeurs, qui sélectionnent quelle valeur mettre sur la sortie : soit le résultat du calcul, soit le plus grand nombre entier géré par le processeur, soit le plus petit (pour les nombres négatifs/soustractions). L'arithmétique saturée est utilisée pour les additions et soustractions, mais c'est plus rare pour les multiplications/divisions. Une des raisons est que le résultat d'une addition/soustraction prend un bit de plus que le résultat, là où les multiplications doublent le nombre de bits. Quand une addition déborde, le résultat réel est proche de la valeur maximale codable. mais quand une multiplication déborde, le résultat peut parfois valoir 200 à 60000 fois plus que la valeur maximale codable. Les calculs avec une valeur saturée/corrigée sont donc crédibles pour une suite d'additions, mais pas pour une suite de multiplications. ===La détection des débordements entiers=== Quand un débordement d'entier a eu lieu, il vaut mieux que l'additionneur prévienne ! Pour cela, l'additionneur a une '''sortie de débordement''', parfois nommée ''Overflow'', dont la valeur indique si l'addition a généré un débordement d'entier ou non. Reste que détecter un débordement ne se fait pas de la même manière selon que l'on parle d'un additionneur non-signé ou signé. Pour les additionneur non-signés, l'additionneur calcule un bit de plus que ce qui est supporté par l'ordinateur. Par exemple, un additionneur 32 bits fournit un résultat sur 33 bits, un débordement d'entier a lieu quand le 33ème bit est à 1. Précisément, la sortie de débordement n'est autre que la retenue finale, celle fournie par le dernier additionneur complet. Le seul type de débordement possible est un débordement par le haut, où le résultat dépasse la valeur maximale. Avec l'arithmétique saturée, le circuit de saturation consiste en une seule couche de multiplexeurs, voire en un circuit de mise à la valeur maximale tel que vu dans le chapitre sur les opérations bits à bits. [[File:Gestion des débordements d'entiers.png|centre|vignette|upright=2.5|Gestion des débordements d'entiers lors d'une addition non-signée.]] Pour les additionneurs non-signés, la gestion des débordements d'entiers dépend fortement de la représentation signée. Nous allons étudier le cas du complément à deux. Si vous vous rappelez le chapitre 1, les calculs sur des nombres en complètement à deux utilisent les règles de l'arithmétique modulaire, c'est une condition nécessaire. À priori, on peut penser que dans ces conditions, les débordements d'entiers sont une chose parfaitement normale, qui nous permet d'avoir des résultats corrects. Néanmoins, certains débordements d'entiers peuvent survenir malgré tout et produire des bugs assez ennuyeux. Si l'on tient en compte les règles du complément à deux, on sait que le bit de poids fort (le plus à gauche) permet de déterminer si le nombre est positif ou négatif : il indique le signe du nombre. Tout se passe comme si les entiers en complément à deux étaient codés sur un bit de moins, et avaient leur longueur amputé du bit de poids fort. Si le résultat d'un calcul écrase le bit de poids fort, il y a un débordement d'entiers. Il existe une règle simple qui permet de détecter ces débordements d'entiers. L'addition de deux nombres positifs ne peut pas être un nombre négatif. Si on additionne deux nombres dont le bit de signe est à 0 et que le bit de signe du résultat est à 1, on est en face d'un débordement d'entiers. Même chose pour deux nombres négatifs : le résultat de l'addition ne peut pas être positif. On peut résumer cela en une phrase : si deux nombres de même signe sont ajoutés, un débordement a lieu quand le bit du signe du résultat a le signe opposé. Modifier les circuits d'au-dessus pour qu'ils détectent les débordements en complément à deux est simple comme bonjour : il suffit créer un petit circuit combinatoire qui prenne en entrée les bits de signe des opérandes et du résultat, et qui fasse le calcul de l'indicateur de débordements. Si l'on rédige sa table de vérité, on doit se retrouver avec la table suivante : {|class="wikitable" |- !Entrées !Sortie |- |000||0 |- |001||1 |- |010||0 |- |011||0 |- |100||0 |- |101||0 |- |110||1 |- |111||0 |} L'équation de ce circuit est la suivante, avec <math>S_a</math> et <math>S_b</math> les signes des deux opérandes, et <math>C_i</math> la retenue de la colonne précédente : : <math> ( S_a . S_b . \overline{C_i} ) + ( \overline{S_a} . \overline{S_b} . C_i )</math> En simplifiant, on obtient alors : : <math>( S_a . S_b ) \oplus C_i</math> Or, il se trouve que <math>S_a . S_b</math> est tout simplement la retenue en sortie du dernier additionneur, que nous noterons <math>C_o</math>. On trouve donc : : <math>C_o \oplus C_i</math> Il suffit donc de faire un XOR entre la dernière retenue et la précédente pour obtenir le bit de débordement. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de décalage et de rotation | prevText=Les circuits de décalage et de rotation | next=Les circuits de comparaison | nextText=Les circuits de comparaison }} </noinclude> j3pc84gk1f4pzs709cagv35wc4k85yp Mathc matrices/Sommaire 0 69175 768758 768473 2026-06-27T09:38:20Z Xhungab 23827 768758 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc matrices (livre)]] : * [[Mathc matrices/Introduction|Introduction]] ---- ---- : {{Partie{{{type|}}}| '''Propriétés et Applications'''}} {| class="wikitable" |+ |- | '''Utilitaires pour Octave''' * [[Mathc matrices/a27| Fonctions pour les matrices]] * [[Mathc matrices/04g| Le code de quelques fonctions]] * [[Mathc matrices/03b| Utilitaires graphiques]] * [[Mathc matrices/04m| Exemples d'applications]] * [[Mathc matrices/04l| Ecrire des fonctions mathématiques]] || '''Utilitaires pour le langage C''' * [[Mathc matrices/a33|'''Utilitaires pour le langage C''']] *. *. *. *. |- | '''Les matrices''' [https://youtube.com/playlist?list=PLi6peGpf8EPOx2Pm_rspnagtdkBYe1t6J&feature=shared '''Playlist'''] : * [[Mathc matrices/05q|Créer une matrice ]] : * [[Mathc matrices/e12d2|Afficher une matrice ]] : * [[Mathc matrices/a03c|Afficher une matrice dans un fichier]] : * [[Mathc matrices/Fichiers c : mul_tran|Afficher une matrice pour Octave:]] : * [[Mathc matrices/a07|Copier une matrice]] : * [[Mathc matrices/c12eb1|Matrices aléatoires]] : * [[Mathc matrices/01p|Éntrez vos données]] : * [[Mathc matrices/c12bn|Tableaux de matrices]] : * [[Mathc matrices/a94|Afficher des vecteurs d'une colonne]] : : '''Opérations de bases''' : * [[Mathc matrices/c12ea2|Opérations sur les matrices]] : * [[Mathc matrices/c12ea1|La fonction trace_R();]] : * [[Mathc matrices/03o|La fonction transpose_R();]] *. *. *. *. : : || '''Les matrices spécifiques''' : * [[Mathc matrices/c12fn17|Matrice identité]] : * [[Mathc matrices/c12b8|Matrices triangulaires]] : * [[Mathc matrices/e02a|Matrices commutatives]] : * [[Mathc matrices/a90|Matrices semblables]] : * [[Mathc matrices/c12b3|Matrices symétriques]] : * [[Mathc matrices/c12b1|Matrices anti-symétriques]] : * [[Mathc matrices/02h|Matrice centrosymétrique]] : * [[Mathc matrices/02v|Matrices définies positives]] : * [[Mathc matrices/035|Matrices définies négatives]] : * [[Mathc matrices/008|Matrices de Hankel]] : * [[Mathc matrices/009|Matrices de Toeplitz]] : * [[Mathc matrices/09i|Matrices de Markov]] : * [[Mathc matrices/a76|La fonction exponentielle]] : : '''Application Graphiques''' : * [[Mathc matrices/e02|Matrices de transformation [2x2]]] : * [[Mathc matrices/a133|Matrices de transformation [3x3]]] : : |- | '''Déterminant''' [https://youtube.com/playlist?list=PLi6peGpf8EPO6GuKOJERdVXKu_zdExd9_&si=1P0vkGzm5Mrf9Vf2 '''Playlist'''] : * [[Mathc matrices/b03|Le déterminant]] : * [[Mathc matrices/Fichiers c : fp_e_mr| Opérations élémentaires]] : * [[Mathc matrices/e12d9|Les fonctions intermédiaires]] : * [[Mathc matrices/c21n|Quelque propriétés ]] : : '''Applications en mathématique ''' : * [[Mathc matrices/149|Matrice Adjointe]] : * [[Mathc matrices/e12d7|L'inverse par le déterminant]] ; * [[Mathc matrices/a235|Produit en croix]] : : || '''Applications en géométrie ''' : * [[Mathc matrices/25a|L'équation d'une droite]] : * [[Mathc matrices/25b|L'équation d'un plan]] : * [[Mathc matrices/25c|L'équation d'une parabole]] : * [[Mathc matrices/25d|L'équation d'un cercle]] : * [[Mathc matrices/25e|L'équation d'une sphère]] * . * . * . * . : : |- | '''Gauss-Jordan ''' [https://youtube.com/playlist?list=PLi6peGpf8EPODYQZ0fosFTZZqKB9-CkHi '''Playlist'''] : * [[Mathc matrices/a205|Gauss-Jordan Total Pivoting]] : * [[Mathc matrices/a207|L'inverse]] : : '''Application ''' : * [[Mathc matrices/a209|Analyse d'un '''réseau''']] : * [[Mathc matrices/a216|Analyse d'un circuit '''électrique''']] : : '''Applications en géometrie ''' : * [[Mathc matrices/26a|L'équation d'un '''polynôme''']] : * [[Mathc matrices/26b|L'équation d'un '''conique''']] : * [[Mathc matrices/26c|L'équation d'un '''cercle''']] : : '''Applications en mathématique ''' : * [[Mathc matrices/a208|Systèmes '''non linéaire''' ]] : * [[Mathc matrices/a32|Choisir les solutions d'un système]] : : || '''Gauss-Jordan Partial Pivoting ''' : * [[Mathc matrices/a203|Gauss-Jordan Partial Pivoting]] : * [[Mathc matrices/a204|Variables libres]] : : '''Application ''' : * [[Mathc matrices/a201|Équation '''chimique''']] : : '''Applications mathématiques ''' : * [[Mathc matrices/c21s|Trouver une base pour ...]] : * [[Mathc matrices/c24f|Matrices de changement de base]] : * [[Mathc matrices/c24k|Matrice d'une application linéaire]] : * [[Mathc matrices/e05b|Projection sur un sous-espace vectoriel]] *. *. *. *. : : |- | '''Produits scalaires''' [https://youtube.com/playlist?list=PLi6peGpf8EPM0AMbdj2DOnyFYP97-93Ry '''Playlist'''] : * [[Mathc matrices/Fichiers h : a03d0|Produit scalaire]] : * [[Mathc matrices/e05c| Quelques Propriétés]] : * [[Mathc matrices/08o| Calculer les vecteurs orthogonaux]] : : '''Orthogonalisation ''' : * [[Mathc matrices/e05a|Les matrices ortho'''normales''']] : * [[Mathc matrices/c25b|Quelques '''propriétés''']] : : '''La QR Décompositions ''' : * [[Mathc matrices/c12an8|'''La QR décomposition:''']] : : '''Application ''' : * [[Mathc matrices/c22m|Analyse d'un réseau]] : * [[Mathc matrices/c22t|Analyse d'un circuit électrique]] : : '''Applications en mathématique ''' : * [[Mathc matrices/00u|Les coefficients d'un polynôme]] : * [[Mathc matrices/00z|Les coefficients d'un conique]] : * [[Mathc matrices/c23l|Les coefficients d'un cercle]] : * . : * . : * . : : || '''Vecteurs propres ''' : * [[Mathc matrices/e12d6|Vecteurs et valeurs propres]] : * [[Mathc matrices/a147|Quelques '''propriétés''']] : * [[Mathc matrices/03h|Valeurs propres '''multiples'''.]] : : '''Applications en mathématique ''' : * [[ Mathc matrices/01z|Conditionnement matriciel]] : * [[Mathc matrices/e050c|'''Fonctions matricielles''']] : * [[Mathc matrices/09b|'''Système dynamique linéaire discret''']] : * [[Mathc matrices/a29|La décomposition spectral]] : : '''Applications graphique ''' : * [[Mathc matrices/060|'''Formes quadratiques : 2D''']] ; * [[Mathc matrices/061|'''Formes quadratiques : 3D''']] : * [[Mathc matrices/08p| '''Choisir''' les valeurs propres]] : * [[Mathc matrices/03g|'''Projection du plan'''(1)]] : * [[Mathc matrices/08u|'''Projection du plan'''(2)]] : * [[Mathc matrices/a257|'''Projection de l'espace'''(1)]] : * [[Mathc matrices/090|'''Projection de l'espace'''(2)]] : * [[Mathc matrices/062|''' Projection de l'hyperespace'''(1)]] : * [[Mathc matrices/096|'''Projection de l'hyperespace'''(2)]] : : |- | '''Valeurs singulière''' : * [[Mathc matrices/c12an7|Calculer les Valeurs Singulières]] : : '''SVD décomposition''' : * [[Mathc matrices/e12a|Plus de lignes que de colonnes]] : * [[Mathc matrices/02q|Quelques propriétés ]] : * [[Mathc matrices/e12b|Plus de colonnes que de lignes]] *. *. *. *. : : || '''Pseudo inverse: ''' : * [[Mathc matrices/26d|'''Pseudo inverse:''']] : : '''Application ''' : * [[Mathc matrices/00t|Analyse d'un réseau]] : * [[Mathc matrices/00i|Analyse d'un circuit électrique]] : : '''Applications en mathématique ''' : * [[Mathc matrices/088|Étude d'un polynôme]] : * [[Mathc matrices/08b|Étude d'un conique]] : * [[Mathc matrices/00k|Étude d'un cercle]] : : |} : : ---- {{Partie{{{type|}}}| '''La bibliothèque'''}} : {{Partie{{{type|}}}|[[Mathc matrices/c21r| '''La bibliothèque.''']]}} : ---- {{Partie{{{type|}}}| '''Gnuplot.'''}} : * [[Mathc matrices/c21q|Gnuplot:]] {{Lien modifier|Mathc matrices/Sommaire|modifier le sommaire}} {{AutoCat}} dhc8q4qj1gi493sttlpane02npgxkjz Python pour le calcul scientifique/Éléments de programmation 0 72883 768733 768400 2026-06-26T16:14:20Z Cdang 1202 /* Utilisation de Pandas */ sans entête 768733 wikitext text/x-wiki Rappel : les programmes commencent par : <syntaxhighlight lang="python"> #!/usr/bin/python3 import numpy as np import matplotlib.pyplot as plt </syntaxhighlight> == Entrées et sorties == Pour permettre à l'utilisateur ou à l'utilisatrice d'entrer une valeur, nous utilisons la fonction <code lang="python">input()</code> comme évoqué précédemment (chapitre ''[[../Premiers programmes|Premiers programmes]]''), avec la syntaxe <code lang="python">''variable'' = input(''texte'')</code>. Notez que la valeur renvoyée par <code lang="python">input()</code> est une chaîne de caractères. Si vous voulez autre chose, typiquement un nombre, il faut convertir cette chaîne. Par exemple, nous demandons ici d'entrer une longueur sous la forme d'une valeur numérique : <syntaxhighlight lang="python"> longueurDefaut = 10.0 texteDemandeLongueur = f"Veuillez entrer la longueur en millimètres (valeur par défaut {longueurDefaut} mm) : " longueur = input(texteDemandeLongueur) if longueur=="": longueur=longueurDefaut else: longueur=float(longueur) print(longueur) </syntaxhighlight> {{voir|https://docs.python.org/3/library/functions.html#input}} Pour afficher un texte, on utilise la fonction <code lang="python">print()</code>, également présentée dans le chapitre ''[[../Premiers programmes|Premiers programmes]]'', avec la syntaxe <code lang="python">print(''texte'')</code>. Le texte à afficher peut être de n'importe quel type (entier, réel en virgule flottante, booléen, chaîne de caractères…). On peut « mélanger » les types en les séparant par des virgules, par exemple <syntaxhighlight lang="python"> print("La longueur vaut : ", longueur, " mm.") </syntaxhighlight> ou bien <syntaxhighlight lang="python"> print("Essai de mélange ", 1, True, 10.0, " insensé.") </syntaxhighlight> Mais si l'on veut faire ça de manière harmonieuse, on a intérêt à tout convertir en chaînes de caractères, avec la fonction <code lang="python">str()</code>, et concaténer les chaînes avec <code lang="python">+</code>. Par exemple : <syntaxhighlight lang="python"> print("La longueur vaut : "+str(longueur)+" mm.") </syntaxhighlight> Nous pouvons aussi utiliser une « chaîne “f” » ''({{lang|en|f-string}})'' : on met un le <code lang="python">f</code> devant le guillemet ouvrant et dans la chaîne, on met un champ sous la forme <code lang="python">{''nomDeVariable''}</code>. L'exemple ci-dessus devient alors : <syntaxhighlight lang="python"> print(f"La longueur vaut : {longueur} mm.") </syntaxhighlight> Les chaînes « f » sont détaillées dans la section ''[[#Chaînes de caractères|Chaînes de caractères]]'' ci-dessous. Si l'on veut introduire un retour à la ligne dans la chaîne, on utilise les caractères <code lang="python">\n</code> (contre-oblique suivie de la lettre N minuscule). Par exemple <syntaxhighlight lang="python"> print("Ceci est un texte\navec un retour à la ligne.") </syntaxhighlight> La commande <code>print()</code> admet les paramètres suivants (nous indiquons la valeur par défaut= : * <code>end = "\n"</code> : détermine la fin de ligne ; on peut mettre <code>end = ""</code> si l'on ne veut pas de retour de ligne, ou bien <code>end = "\r"</code> ''({{lang|en|return}})'' si l'on veut revenir au début de la ligne pou repasser par-dessus ; * <code>sep = " "</code> : séparateur des différents objets. {{voir|https://docs.python.org/3/library/functions.html#print}} Si vous voulez passer un argument directement au script Python, vous pouvez utiliser le module <code>sys</code>. L'argument est alors contenu dans la variable <code>sys.argv[1]</code> ; la variable <code>sys.argv[0]</code> contient le nom du scirpt lui-même. Par exemple <syntaxhighlight lang="python"> import sys print("Script : ", sys.argv[0]) print("Entrée : ", sys.argv[1]) </syntaxhighlight> Si vous exécutez le script depuis une console (fenêtre de commande), le nom du fichier de script étant <code>monscript.py</code> : <syntaxhighlight lang="text"> $ python monscript.py blabla Script : monscript.py Entrée : blabla $_ </syntaxhighlight> == Types de variables == === Généralités === Python définit « tout seul » le type de la variable : « <code>3</code> » sera un entier ''({{lang|en|integer}})'', « <code>3.0</code> » sera un réel à virgule flottante ''({{lang|en|float}})'', « <code>"3"</code> » sera une chaîne de caractères ''({{lang|en|string}})''. On peut connaître le type d'une variable avec la fonction <code>type()</code>. On peut tester certaines valeurs, avec le module <code>NumPy</code> : * <code>np.isnan(x)</code> indique si les valeurs de ''x'' sont des NaN ''({{lang|en|not a number}})'' ; si ''x'' est une matrice, le résultat est une matrice de booléens, l'élément [''i'', ''j''] est <code>True</code> si <code>x[i, j]</code> est un NaN ; * <code>np.isinf(x)</code> indique si les valeurs de ''x'' sont ±∞ ; si ''x'' est une matrice, le résultat est une matrice booléenne de même dimension. On peut forcer un type : * <code>int(x)</code> : transforme la valeur ''x'' en nombre entier ; * <code>long(x)</code> : " en entier long (précision illimitée) ; * <code>float(x)</code> : " en nombre réel à virgule flottante ; * <code>str(x)</code> : " en chaîne de caractères ; * <code>complex(Re, Im)</code> : crée le nombre complexe ''Re'' + ''Im''·j, j désignant la racine carrée de –1 ; * <code>list()</code> : crée une liste ; * <code>tuple()</code> : crée un n-uplet. Par exemple <syntaxhighlight lang="python"> type(3) # <class 'int'> type(float(3)) # <class 'float'> complex(1, 1) == 1 + 1j # True list("blabla") # ['b', 'l', 'a', 'b', 'l', 'a'] </syntaxhighlight> Python distingue plusieurs genres de types : * Un itérable est un objet dont on peut extraire les éléments un par un ; ce sont les objets pour lesquels on peut écrire <code> for i in ''iterable'':</code>. Il s'agit essentiellement des listes, n-uplets, chaînes de caractères, ensembles, dictionnaires et fichiers. * Un modifiable ''({{lang|en|mutable}})'' est un objet que l'on peut modifier ; par exemple une liste est modifiable — on peut changer la valeur d'un élément, en ajouter ou en enlever un — mais les n-uplets non, pas plus qu'une chaîne de caractères ou un nombre. * Un identifiable (''{{lang|en|hashable}}'', le ''{{lang|en|hashage}}'' étant une signature caractéristique d'un objet) : objet possédant un identifiant unique. Un objet identifiable est toujours non-modifiable ''({{lang|en|unmutable}})''. === Types numériques === ==== Entiers ==== Nous pouvons définir les entiers au format octal ou hexadécimal : il faut débuter le nombre par respectivement <code>0o</code> (le chiffre zéro et la lettre o) et <code>0x</code> (le chiffre zéro et la lettre x). À l'inverse, la fonction <code>hex()</code> renvoie une chaîne correspondant à l'écriture d'un entier au format hexadécimal, et <code>oct()</code> renvoie la chaîne correspondant à l'éciture en octal. Par exemple : <syntaxhighlight lang="python"> print(0o10, ";", 0x10) # 8 ; 16 print(hex(20)) # 0x14 </syntaxhighlight> ==== Réels ==== Les réels disposent de fonctions spécifiques appelées « méthodes ». Une méthode est une fonction spécifique à un type d'objets. Étant conçue ''ad hoc'', elle est souvent plus économe en ressource et en temps qu'une fonction générique. Pour appliquer la méthode <code>meth()</code> à la variable <code>x</code>, on écrit : <code>x.meth()</code>. Nous avons déjà présenté la méthode <code>''float''.as_integer_ratio()</code> qui donne la fraction réduite égale à la valeur du nombre. Les réels disposent de plusieurs autres méthodes : * <code>''float''.is_integer()</code> : indique si le nombre est un entier (<code>true</code> dans ce cas-là, <code>False</code> sinon) ; * <code>''float''.from_number(''x'')</code> : transforme le nombre ''x'' en un réel (permet de convertir un entier en réel) ; * <code>''float''.hex()</code> : renvoie une chaîne de caractères correspondant à l'écriture du nombre en hexadécimal ; * <code>''float''.fromhex(''c'')</code> : transforme une chaîne de caractères, correspondant à l'écriture d'un nombre en hexadécimal, en un nombre réel correspondant. Par exemple : <syntaxhighlight lang="python"> a = 20. print(a.hex()) # 0x1.4000000000000p+4 print(10..hex()) # 0x1.4000000000000p+3 </syntaxhighlight> Dans le deuxième exemple, nous appliquons la méthode <code>''float''.hex()</code> directement au nombre <code>10.</code> ; le point est obligatoire car sinon, c'est un entier, pour lequel la méthode n'est pas définie. On aurait pu aussi écrire <code>print(10.0.hex())</code>. Notez que la ''méthode'' <code>''float''.hex()</code> est différentes de la ''fonction'' <code>hex()</code> : la première concerne les réels, la seconde les entiers. ==== Complexes ==== Nous avons déjà mentionné la méthode <code>''complex''.conjugate()</code> qui donne le conjugué du nombre. Un nombre complexe dispose de deux attributs : * <code>''complex''.real</code> : sa partie réelle ; * <code> ''complex''.imag</code> : sa partie imaginaire. Par exemple : <syntaxhighlight lang = "python"> a = 5+2j print(a.conjugate(), ";", a.real, ";", a.imag) # (5-2j) ; 5.0 ; 2.0 </syntaxhighlight> === Chaînes de caractères === ; Ressources : {{lien web | url = https://docs.python.org/3/tutorial/inputoutput.html | titre = 7. Input and Output | site = Python Documentation | consulté le = 2019-04-06 }} : {{lien web | url = https://docs.python.org/3/library/string.html | titre = <code>string</code> — Common string operations | site = Python Documentation | consulté le = 2026-06-05 }} ==== Généralités ==== Il existe en fait trois manières de définir une chaîne de caractères : * avec des guillemets simples ou doubles comme vu précédemment : <code>"…"</code> ou bien <code>'…'</code> ; * avec trois guillemets doubles : <code>"""…"""</code> : cela permet d'avoir une chaîne de caractères s'étendant sur plusieurs lignes, les retours de ligne étant pris en compte ; c'est utilisé en particulier pour la description des fonctions (''{{lang|en|docstrings}}'', voir ci-après) ; * avec des guillemets précédés d'un « r », <code>r"…"</code> ou <code>r'…'</code> : cela permet d'interpréter les barres de fraction inverses « \ » comme un caractère « normal » et non comme un caractère d'échappement (voir ci-après) ; cela est utile lorsque l'on utilise les possibilités LaTeX dans le tracé de graphiques (voir plus loin) ; * avec des guillemets précédés d'un « f », <code>f"…"</code> ou <code>f'…'</code> : cela permet d'utiliser des variables formatées (voir ci-après). Une chaîne de caractères n'est pas modifiable. Si l'on veut remplacer un caractère, l'insérer ou le supprimer, il faut transformer la chaîne en liste, avec la commande <code>list()</code>, puis rassembler la liste en la joignant ''({{lang|en|join}})'' à une chaîne vide : <syntaxhighlight lang="python"> chaine = "blabla" chaineList = list(chaine) chaineList[2] = "c" chaine = "".join(chaineList) print(chaine) # blcbla </syntaxhighlight> Dans une chaîne simple <code>"…"</code> ou <code>'…'</code>, on peut introduire un retour à la ligne avec <code>\n</code>. Chaque caractère possède un code ''({{lang|en|code point}})'' définit par la norme Unicode ''({{lang|en|Unicode code point}})''. Pour afficher le caractère correspondant à un code, on utilise <code>chr()</code>. Pour afficher le code correspondant à un caractère, on utilise <code>ord()</code> <syntaxhighlight lang="python"> print(ord("a")) # 97 print(hex(ord("a"))) # 0x61 print(chr(97)) # a print(chr(0x61)) # a </syntaxhighlight> ==== Substitution de variables ==== Lorsque l'on veut utiliser des variables, on fait précéder les guillemets d'un « f » et l'on écrit les noms de variables entre accolades ; on parle de « chaîne f » ''(f-string)''. Par exemple : <syntaxhighlight lang="python"> monde = "world" chaine = f"Hello {monde}!" print(chaine) # Hello world! </syntaxhighlight> On peut indiquer la taille de la chaîne générée à partir de la variable sous la forme <code>{nomVariable:taille}</code>, la taille étant un entier. Par exemple : <syntaxhighlight lang="python"> chiffre1 = 1 nom1 = "un" chiffre2 = 2 nom2 = "deux" chaine = f"{nom1:5} : {chiffre1:5d}\n{nom2:5} : {chiffre2:5d}" print(chaine) # un : 1 # deux : 2 </syntaxhighlight> Vous remarquez que l'on ajoute un « d » pour les entiers décimaux, et que les nombres sont alignés à droite. Si le nombre est un nombre réel à virgule flottante ''({{lang|en|float}})'', on peut indiquer le nombre de décimales sous la forme <code>.''n''f</code> : <syntaxhighlight lang="python"> chaine = f"{np.pi:.5f}" print(chaine) # 3.15169 </syntaxhighlight> Avec la syntaxe <code>''m''.''n''f</code>, on indique également que la totalité du nombre doit occuper ''m'' caractères. Pour un nombre en notation scientifique (exponentielle), on utilise <code>.''n''e</code>. Pour convertir un nombre en caractère Unicode correspondant, on utilise la lettre c : <syntaxhighlight lang="python"> nompi = 0x03c0 # Caractère Unicode π : U+03C0 chaine = f"{nompi:c} = {np.pi:.5f}" print(chaine) # π = 3.14159 </syntaxhighlight> Notez que dans le cas de nombres, la mise en forme marche aussi si l'on écrit directement le nombre dans l'accolade (au lieu d'une variable). Le tiret de soulignement « <code>_</code> » (''underscore'', tiret du 8) permet de séparer les chiffres avant le séparateur décimal par groupe de trois chiffres séparés du tiret ; la virgule « <code>,</code> » les sépare d'une virgule. <syntaxhighlight lang="python"> print(f"{1e6:_}, {1e6:,}") # 1_000_000.0, 1,000,000.0 </syntaxhighlight> La classe ''str'' dispose également de la méthode <code>.format()</code>. On indique un n-uplet de chaînes (ou de nombres) à la méthode et l'on met des accolades dans la chaîne principale ; les accolades sont remplacées dans l'ordre des chaînes de la méthode. On peut changer l'ordre en indiquant quelle valeur utiliser dans quelle accolade. Par exemple : <syntaxhighlight lang="python"> chaine1 = "On compte {} puis {}".format(1, 2) chaine2 = "On compte {0} puis {1}. Mais à rebours, on compte {1} puis {0}.".format("un", "deux") print(chaine1, "\n", chaine2) # On compte 1 puis 2 # On compte un puis deux. Mais à rebours, on compte deux puis un. </syntaxhighlight> L'utilisation du caractère pourcent « % » permet d'utiliser la mise en forme <code>sprintf()</code> du langage C : <syntaxhighlight lang="python"> chaine = "π = %.5f" % np.pi print(chaine) # π = 3.14159 </syntaxhighlight> ; Exemple <nowiki>:</nowikI> barre de progression : Voici une fonction affichant une barre de progression, pour la ''i''-ème étape d'un processus ayant ''n'' étapes (pour la notion de fonction, voir la section ci-après ''[[#Fonction|Fonction]]''). : NB : nous avons utilisé les codes Unicode pour l'exemple, mais on peut évidemment copier le caractère, par exemple depuis une table Unicode ou une page Web<ref>Pour le point médian : ''{{W|Table des caractères Unicode/U0080}}'' ou ''{{W|Point médian}}''. Pour le pavé : ''{{W|Table des caractères Unicode/U2580}}''.</ref>, et le coller dans le code, comme nous l'avons fait dans le commentaire. <syntaxhighlight lang="Python"> def barre_progression(i, n, largeur=40): """ Affiche une barre de progression Entrées : — i : étape en cours, entier ; — n : nombre d'étapes à réaliser, entier ; — largeur : nombre de caractères total de la barre, entier. Sortie : affichage de la barre de progression. """ taux = i/n fait = int(largeur * taux) barre = f"{0x2588:c}" * fait + f"{0x00b7:c}" * (largeur - fait) # U+2588 : pavé "█" ; U+00B7 : point médian "·" print(f"Progression | {barre} | {100*taux:3.1f} %", end="\r") barre_progression(25, 100) # Progression | ██████████······························ | 25.0 % </syntaxhighlight> ==== Méthodes des chaînes ==== Le type ''str'' dispose d'un certain nombre de méthodes. Nous avons déjà vu les méthodes <code>''str''.join()</code> et <code>''str''.format()</code>, en voici quelques autres : * <code>''str''.capitalize()</code> : met le premier caractère en capitale (majuscule) et les autres en minuscule ; * <code>''str''.lower()</code> : met tout en minuscules ''({{lang|en|lowercase}})'' ; * <code>''str''.upper()</code> : met tout en capitales ''({{lang|en|lowercase}})'' ; * <code>''str''.center(''n'')</code> : met la chaîne au centre d'une chaîne de longueur ''n'', en complétant avec des espaces ; on peut compléter avec d'autres caractères avec <code>''str''.center(''n'', ''c'')</code>, par exemple <code>"a".center(7, ".")</code> donne <code>"....a...."</code> ; * <code>''str''.ljust(''n'', ''c'')</code> et <code>''str''.rjust(''n'', ''c'')</code> : comme <code>.center()</code> mais la chaîne est respectivement alignée au fer à gauche ''({{lang|en|left}})'' et à droite ''({{lang|en|right}})'' ; * <code>''str''.isdigit()</code> : booléen vrai si tous les caractères sont des nombres ; * <code>''str''.find(''sous-chaine'')</code>, <code>''str''.rfind(''sous-chaine'')</code> : indique respectivement le premier emplacement et le dernier emplacement de la sous-chaîne dans la chaîne, ou bien <code>-1</code> si la sous-chaîne est absente ; * <code>''str''.partition(''séparateur'')</code> : retourne un triplet avec la portion de chaîne avant le séparateur, le séparateur puis la portion de chaîne après le séparateur ; * <code>''str''.replace(''ancien'', ''nouveau'')</code> : remplace la chaîne ''ancien'' par la chaîne ''nouveau'' dans la chaîne ; * <code>''str''.split(''séparateur'')</code> : découpe la chaîne au niveau des séparateurs et renvoie une liste. ==== Autres fonctions ==== La fonction <code>chr()</code> transforme un code Unicode en caractère. Par exemple, <code>chr(97)</code> donne <code>"a"</code> et <code>chr(0x03c0)</code> donne <code>"π"</code>. Si on veut créer une liste de caractères qui se suivent, on peut par exemple utiliser : <syntaxhighlight lang="python"> [chr(x) for x in range(97, 102)] # ['a', 'b', 'c', 'd', 'e'] </syntaxhighlight> Si on veut créer une liste de nombres sous la forme de chaînes de caractères, on peut utiliser la commande <code>str()</code> vue ci-dessus. Par exemple : <syntaxhighlight lang="python"> [str(x) for x in range(1, 6)] # ['1', '2', '3', '4', '5'] </syntaxhighlight> Pour la syntaxe, voir ci-dessous la section [[#Définition en compréhension|''Définition en compréhension'']]. Ainsi, dans l'exemple de la barre de progression ci-dessus, on peut utiliser la solution suivante pour constituer la barre : <syntaxhighlight lang="python"> barre = chr(0x2588) * fait + chr(0x00b7) * (largeur - fait) # U+2588 : bloc ; U+00B7 : point médian </syntaxhighlight> Rappel : le module <code>html</code> permet d'utiliser les entités HTML : <syntaxhighlight lang="python"> import html … print(html.entities.html5["alpha;"]+html.entities.html5["middot;"]) # α· </syntaxhighlight> L'entité HTML <code>&xxx;</code> s'obtient par <code>html.entities.html5["xxx;"]</code>, donc en enlevant la perluète ; mais cela ne fonctionne pas avec les codes Unicode. Pour cela, on peut utiliser la commande <code>html.unescape()</code>. Ainsi, dans l'exemple de la barre de progression ci-dessus, on peut utiliser la solution suivante pour constituer la barre : <syntaxhighlight lang="python"> barre = html.unescape("&#x2588;") * fait + html.entities.html5["middot;"] * (largeur - fait) # U+2588 : bloc ; middot : point médian </syntaxhighlight> ou bien <syntaxhighlight lang="python"> barre = barre = html.unescape("&#x2588;" * fait + "&middot;" * (largeur - fait)) # U+2588 : bloc ; middot : point médian </syntaxhighlight> La commande <code>html.unescape()</code> interprète donc une chaîne complète, par exemple <syntaxhighlight lang="python"> print(html.unescape("L'esperluette est le caractère &laquo;&nbsp;&amp;&nbsp;&raquo;.")) # L'esperluette est le caractère « & ». </syntaxhighlight> == Manipulation de listes == Les listes sont une structure de données fondamentale en Python. ; Ressources * {{lien web | url = https://docs.python.org/3/tutorial/datastructures.html | langue = en | titre = 5. Data structures | site = Python documentation | consulté le = 2019-03-16 }} === Copie d'une liste === Contrairement à d'autres types, lorsque vos écrivez <code>b = a</code> avec des listes, vous ne créez pas une copie de la variable <code>a</code>, vous créez un ''alias'' : l'objet <code>b</code> est un autre nom de l'objet <code>a</code>. En particulier, si vous modifiez <code>b</code>, vous modifiez en fait <code>a</code>. Par exemple : <syntaxhighlight lang="python"> a = [1, 2, 3, 4] b = a b[2] = 5 print(a, b) # [1, 2, 5, 4] [1, 2, 5, 4] </syntaxhighlight> Si l'on veut créer une copie de <code>a</code>, il faut utiliser <code>a[:]</code> ou bien <code>a.copy()</code> : <syntaxhighlight lang="python"> a = [1, 2, 3, 4] b = a[:] c = a.copy() b[2] = 5 c[2] = 6 print(a, b, c) # [1, 2, 3, 4] [1, 2, 5, 4] [1, 2, 6, 4] </syntaxhighlight> === Méthodes de listes === Pour modifier une liste, vous disposez des méthodes suivantes : * <code>a.append(x)</code> : ajoute l'élément <code>x</code> à la fin de la liste <code>a</code> ; * <code>a.extend(x)</code> : ajoute la liste <code>x</code> à la fin de la liste <code>a</code> ; * <code>a.append(i, x)</code> : aoute l'élément <code>x</code> ''avant'' l'interstice ''i'' de la liste <code>a</code> ; * <code> x = a.pop(i)</code> : enlève l'élément ''i'' de la liste <code>a</code> et le met dans la variable <code>x</code> ; <code> x = a.pop()</code> enlève le dernier élément de la liste ; * <code>a.clear()</code> : vide la liste <code>a</code> ; * <code>a.sort()</code> : trie la liste par ordre croissant ; * <code>a.sort(reverse = True)</code> : trie par ordre décroissant ; * <code>a.reverse()</code> : inverse l'ordre de <code>a</code>. Pour supprimer l'élément à l'indice ''i'', au lieu d'utiliser <code>a.pop(i)</code>, on peut aussi utiliser <syntaxhighlight lang="python"> del(a[i]) </syntaxhighlight> Pour trier une liste, on peut aussi utiliser la fonction <code>sorted()</code>, ce qui permet par exemple de conserver la liste originale, non triée : <code>b = sorted(a)</code>. La fonction <code>sorted()</code> fonctionne avec tous les objets « itérables » comme par exemple une chaîne de caractères : <syntaxhighlight lang="python"> a = "ahjbfk" print(sorted(a)) # ['a', 'b', 'f', 'h', 'j', 'k'] </syntaxhighlight> Pour mettre en évidence la performance de la méthode <code>''list''.sort()</code> par rapport à la fonction générique <code>sorted()</code> : <syntaxhighlight lang="python"> import numpy as np import time a = np.random.rand(int(1e7)) t1 = time.perf_counter() b = sorted(a) # Fonction générique t2 = time.perf_counter() a.sort() # Méthode spécifique t3 = time.perf_counter() print("Sorted :", t2-t1, " s ; .sort :", t3-t2, "s ; rapport :", (t2-t1)/(t3-t2)) # Sorted : 14.2... s ; .sort : 1.1... s ; rapport : 12.6... </syntaxhighlight> Par rapport à une valeur donnée : * <code>a.remove(x)</code> : retire la première occurrence de la valeur <code>x</code> de la liste <code>a</code> ; * <code>a.index(x)</code> : indique l'indice où se trouve la première occurrence de la valeur <code>x</code> ; * <code>a.count(x)</code> : indique le nombre de fois que l'on trouve la valeur <code>x</code> dans la liste <code>a</code>. === Définition en compréhension === La [[w:fr:Liste en compréhension|définition en compréhension]] ''({{lang|en|list comprehension}})'' est une méthode permettant de construire des listes en indiquant simplement des axiomes, des consignes de filtrage. Cette méthode est élégante car proche de la notation mathématique et compacte, mais c'est une méthode itérative donc lente par rapport à une méthode vectorisée fournie par le module NumPy. Par exemple, pour créer la liste des carrés des nombres entiers entre 0 et 9, il suffit d'écrire <syntaxhighlight lang="python"> carre = [x**2 for x in range(10)] </syntaxhighlight> ce qui se rapproche de la notation d'ensemble <math>\{x^2 | x \in [0 ; 9] \}</math>. Si l'on veut la liste des nombres strictement inférieurs à 20 dont le carré est supérieur à 10, on peut écrire : <syntaxhighlight lang="python"> X = [x for x in range(20) if x**2 > 10] </syntaxhighlight> ce qui se rapproche de la notation d'ensemble <math>\{x | x \in [0 ; 19], x^2 > 10 \}</math>. Pour mettre en évidence la performance du calcul vectorisé par rapport à la méthode itérative : <syntaxhighlight lang="python"> import time import numpy as np n = int(1e7) # taille de la liste t1 = time.perf_counter() carre = [x**2 for x in range(n)] # Définition en compréhension t2 = time.perf_counter() carre2 = np.arange(n)**2 # Calcul vectorisé t3 = time.perf_counter() print("En compréhension : ", t2-t1, "s ; vectorisé :", t3-t2, "s ; rapport :", (t2-t1)/(t3-t2)) # En compréhension : 4.515... s ; vectorisé : 0.156... s ; rapport : 28.982... </syntaxhighlight> == Structure d'un programme == Un programme est simplement une suite d'instructions. Dans les environnements Unix BSD, un programme Python peut être considéré comme un script c'est-à-dire qu'il suffit de taper son nom dans l'invite de commande ''({{lang|en|shell}})'' sans avoir à invoquer <code>python</code>. Le programme doit alors commencer par un en-tête normalisé surnommé ''{{lang|en|[[wikt:shebang|shebang]]}}'' : <syntaxhighlight lang="python"> #!/usr/bin/env python3 </syntaxhighlight> Ce ''{{lang|en|shebang}}'' est inutile avec Jupyter. L'en-tête peut également contenir la description de l'encodage du fichier texte, typiquement : <syntaxhighlight lang="python"> # coding: utf-8 </syntaxhighlight> Le codage UTF-8 est le codage par défaut pour Python 3, il est donc inutile de l'indiquer. Les commentaires sont introduits par le croisillon <code>#</code>. On peut grouper une suite d'instructions dans un bloc. Un bloc d'instructions commence par deux-points « <code>:</code> » et est identé, c'est-à-dire qu'il a une marge constituée de quatre espaces — on peut aussi utiliser une tabulation mais il ne faut pas mélanger les deux méthodes ; les tabulations sont déconseillées, il vaut mieux utiliser quatre espaces<ref>{{lien web | url = https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces | titre = Tabs or Spaces? | site = Python documentation | consulté le = 2019-03-14 }}</ref>. Pour terminer le bloc, il suffit simplement de revenir en début de ligne ; contrairement à d'autres langages, il n'y a pas de commende de fin ''({{lang|en|end}})'', c'est l'indentation qui définit le bloc. : # début du bloc ''instruction 1'' ''instruction 2'' … ''dernière instruction du bloc'' ''instruction hors bloc'' Par exemple, une exécution conditionnelle <code>if</code> ou une boucle <code>for</code> exécute un bloc d'instruction. Si l'on a besoin d'un bloc d'instruction qui « ne fait rien », on utilise l'instruction <code>pass</code>. == Structures de contrôle == '''Boucle itérative''' La boucle itérative s'écrit : <syntaxhighlight lang="python"> for <variable> in <itérable>: <bloc d’instructions> </syntaxhighlight> Si l'on veut que la variable prenne ''n'' valeurs de 0 à ''n'' – 1, on utilise l'instruction <code>range()</code> : <syntaxhighlight lang="python"> for i in range(5): print(i) print("Fin de la boucle") </syntaxhighlight> <code>[▶]</code> 0 1 2 3 4 Fin de la boucle En fait, la commande <code>range()</code> extrait des valeurs de l'ensemble des nombres entiers ; on peut ainsi utiliser le découpage en tranches, par exemple <code>range(2, 5)</code>pour avoir la « liste » <code>[2, 3, 4]</code>. Notez que <code>range()</code> ne crée pas à proprement parler une liste, cela crée un objet de type ''« {{lang|en|range}} »'' (plage, intervalle) ; pour avoir une liste, il faut écrire <code>list(range(n))</code>. Dans une boucle, la commande <code>continue()</code> saute la fin du bloc d'instruction et passe à la valeur suivante de la boucle. La commande <code>break()</code> interrompt la boucle et passe à la suite. '''Exécution conditionnelle''' L'exécution conditionnelle s'écrit : <syntaxhighlight lang="python"> if <booléen>: <bloc d’instructions> </syntaxhighlight> On peut utiliser les commandes <code>elif</code> ''(else if'') et <code>else</code> : <syntaxhighlight lang="python"> if <booléen>: <bloc d’instructions> elif <booléen>: <bloc d’instructions> else: <bloc d’instructions> </syntaxhighlight> Notez que le test d'une condition est gourmand en ressources. S'il s'agit de savoir si l'on effectue une opération mathématique simple ou pas, on peut remplacer le test par une multiplication par un booléen (<code>True</code> vaut 1, <code>False</code> vaut 0). Par exemple, plutôt que d'écrire <syntaxhighlight lang="python"> if a > 0: b = b - c </syntaxhighlight> mieux vaut écrire : <syntaxhighlight lang="python"> b = b - (a > 0)*c </syntaxhighlight> '''Boucle antéconditionnée''' La boucle antéconditionnée s'écrit : <syntaxhighlight lang="python"> while <booléen>: <bloc d’instructions> </syntaxhighlight> Cette boucle peut contenir des instructions <code>continue()</code> et <code>break()</code>. == Fonction == La déclaration d'une fonction utilise la commande <code>def</code>. La fonction est un bloc d'instructions. Si elle doit renvoyer des valeurs, on utilise la commande <code>return</code>. Par exemple <syntaxhighlight lang="python"> def nombres(n): """But : Entrer plusieurs nombres Entrée : n, entier : quantité de nombre à saisir. Sortie : foo : liste de n réels. """ # description de la fonction foo = [] # initialisation for i in range(n): foo = foo+[float(input("Entrez un nombre"))] return foo a = nombres(3) print(a) </syntaxhighlight> La fonction commence par une chaîne de caractères qui la décrit. Cette chaîne peut être récupérée automatiquement par certains logiciels pour faire une documentation automatique. Si la description prend plusieurs lignes, elle commence et finit par trois double-guillemets <code>"""…"""</code> ; en fait, par convention, même si cela n'est pas obligatoire, les descriptions sont toutes encadrées de trois double-guillemets. Cette description est appelée ''{{lang|en|docstring (documentation string)}}''. Pour récupérer les ''{{lang|en|docstrings}}'' : <syntaxhighlight lang="python"> def foo(): """Cette fonction ne fait rien""" pass print(foo.__doc__) # Cette fonction ne fait rien </syntaxhighlight> L'instruction <code>input()</code> permet à l'utilisateur de saisir une valeur. La valeur est retournée sous la forme d'une chaîne de caractères qui est ensuite convertie en nombre réel avec l'instruction <code>float()</code>. On peut définir une valeur par défaut en l'indiquant dans l'en-tête de la définition de la fonction, de la manière suivante : <syntaxhighlight lang="python"> def nombres(n=1): # valeur par défaut : 1 """But : Entrer plusieurs nombres Entrée : n, entier : quantité de nombre à saisir. Sortie : foo : liste de n réels. """ # description de la fonction foo = [] # initialisation for i in range(n): foo = foo+[float(input("Entrez un nombre"))] return foo </syntaxhighlight> Si le paramètre à initialiser est de type modifiable ''({{lang|en|mutable}})'', comme par exemple une liste, il faut procéder comme suit : <syntaxhighlight lang="python"> def fooFonction(fooListe=None): # valeur par défaut : n'existe pas """Description""" if fooListe = None: fooListe = [] # initialisation <suite des instructions> </syntaxhighlight> Par défaut, les variables sont locales. On peut rendre une variable globale avec l'instruction <code>global</code> ''à l'intérieur de la fonction'', avant l'utilisation de la variable. Par exemple : <syntaxhighlight lang="python"> a = 1 b = 1 def toto(): """Test de variable globale. Entrée : aucune. Sortie : aucune.""" global a a = 2 b = 2 toto() print("a =", a, "; b =", b) # a = 2 ; b = 1 </syntaxhighlight> Pour être plus précis : si une variable n'est pas assignée dans une fonction, alors Python va chercher une variable du même nom à l'extérieur de la fonction. Mais à partir du moment où la variable est assignée dans la fonction, elle devient locale ''sauf'' si l'on a utilisé l'instruction <code>global</code>. Si l'on s'attend à un nombre indéfini d'arguments, on utilise la notion d'empaquetage/dépaquetage ''({{lang|en|packing/unpacking}})''<ref>{{lien web | url = https://deusyss.developpez.com/tutoriels/Python/args_kwargs/ | titre = Introduction à *args et **kwargs | consulté le = 2019-03-09 | site = Developpez.com }}.</ref>. L'empaquetage consiste à mettre les arguments dans un n-uplet, le dépaquetage consiste à développer un n-uplet en plusieurs variables. Cela se fait en mettant un astérisque ''({{lang|en|splat}})'' « <code>*</code> » devant le nom de la variable. Par convention, on utilise le nom de variable <code>*args</code> mais cela n'est pas obligatoire. <syntaxhighlight lang="python"> def concatenation(*args): """Concatène des chaînes de caractères Entrée : *args, n-uplet de chaînes de caractères. Sortie : resultat, chaîne de caractères.""" resultat = "" for i in args: resultat = resultat + i return resultat concatenation("a", "foo", "toto") # 'afoototo' </syntaxhighlight> À l'inverse, si une fonction doit recevoir plusieurs paramètres, on peut à la place lui transmettre une liste à dépaqueter : <syntaxhighlight lang="python"> def addition(a, b): """Ajoute deux nombres Entrées : — a : réel ; — b : réel. Sortie : a+b, réel""" return a+b arg = (1, 2) addition(*arg) # 3 </syntaxhighlight> On peut aussi empaqueter/dépaqueter un dictionnaire, on utilise pour cela deux astérisques « <code>**</code> ». Par convention, on utilise le nom <code>**kwargs</code> sans que cela soit obligatoire. L'instruction <code>lambda</code> permet de créer de petites fonctions ne contenant pas de boucle ni de branchement conditionnel. Cependant, si la déclaration est courte et compacte, le code n'est pas toujours facilement lisible ; l'utilisation de cette instruction n'est pas recommandée. Par exemple l'expression <syntaxhighlight lang="python"> f = lambda x: 2*x </syntaxhighlight> est la même chose que <syntaxhighlight lang="python"> def f(x): """Calcule le double. Entrée : x, réel. Sortie : 2*x, réel.""" return 2*x </syntaxhighlight> {{note|L'instruction <code>eval()</code> exécute une chaîne de caractères, c'est-à-dire traite une chaîne de caractères comme si c'étaient des instructions données à Python. Cette instruction est à éviter pour deux raisons : # Un utilisateur malveillant pourrait entrer du code malveillant dans la chaîne de caractères. # L'exécution est lente puisque Python doit compiler la chaîne à la volée. Cette instruction peut en général être remplacée par une autre instruction. }} == Gestion des erreurs == Dans un bloc d'instructions, on peut utiliser la structure <code>try:… except:</code>. Le bloc après <code>try</code> est exécuté ; si une erreur se déclare dans ce bloc, alors le bloc <code>except</code> s'exécute. Par exemple <syntaxhighlight lang="python"> try: 1/0 # Génère une erreur except: print("Division par zéro") # Cette instruction est donc exécutée </syntaxhighlight> On peut compléter avec <code>else:</code> et <code>finally:</code> : <syntaxhighlight lang="python"> try: <code à exécuter> except: <s’exécute en cas d’erreur> else: <s’exécute s’il n’y a pas d’erreur> finally: <s’exécute dans tous les cas> </syntaxhighlight> On peut séparer les différents types d'erreur : <syntaxhighlight lang="python"> try: <code à exécuter> except ValueError: print("Valeur erronée") except TypeError: print("Type erroné") </syntaxhighlight> Les types d'erreur les plus courants sont : * <code>NameError</code> : le nom de variable n'existe pas ; * <code>TypeError</code> : la valeur n'est pas du bon type ; * <code>ValueError</code> : la valeur n'est pas compatible avec ce qui est attendu ; * <code>RuntimeError</code> : type d'erreur général. On peut aussi créer ses propres erreurs : si une situation erronée survient, on peut « lever » une exception avec <code>raise</code>. Par exemple <syntaxhighlight lang="python"> if a < 0: raise ValueError("La valeur doit être positive") </syntaxhighlight> ; Ressources * {{lien web | url = https://docs.python.org/3/tutorial/errors.html | titre = Errors and exceptions | lang = en | site = Python documentation | consulté le = 2019-03-12 }} * {{lien web | url = https://docs.python.org/3/library/exceptions.html | titre = Built-in Exceptions | lang = en | site = Python documentation | consulté le = 2019-03-12 }} == Exercices == === Calcul du PGCD et du PPCM par l'algorithme d'Euclide === {{loupe|w:Algorithme d'Euclide}} Écrire un programme Python qui demande deux nombres entiers et affiche leurs PGCD et PPCM. Le programme utilisera l'algorithme d'Euclide. {{boîte déroulante début|solution}} <syntaxhighlight lang="python"> """Programme : euclide.py Auteur : User:cdang date : 2019-02-19 dates de modification : ---------------------------------------------------------------------------- version de Python : 3 module requis : aucun ---------------------------------------------------------------------------- Objectif : calcule le PGCD et le PPCM de deux nombres entiers. Entrée ------ au clavier, saisie de deux nombres entiers. Sorties ------- à l'écran, affichage du PGCD et du PPCM. """ # *************** # *************** # ** Fonctions ** # *************** # *************** def euclide(): """Calcule le PGCD et le PPCM avec l'algorithme d'Elclide Entrée ------ Aucune, la saisie des paramètres fait partie de la fonction Sortie ------ affichage du PGCD et du PPCM """ print("***** Algorithme d'Euclide *****\n") a0 = int(input("Premier nombre entier : a = ")) b0 = int(input("Second nombre entier : b = ")) a = a0 b = b0 r = a%b # initialisation while (r != 0) : # algorithme d'Euclide a = b b = r r = a%b # affichage des résultats print("PGCD(", a0, ", ", b0, ") = ", b) print("PPCM(", a0, ", ", b0, ") = ", a0*b0//b) # ************************* # ************************* # ** Programme principal ** # ************************* # ************************* euclide() </syntaxhighlight> On peut simplifier la boucle centrale : <syntaxhighlight lang="python"> while b: # s'exécute tant que b n'est pas 0 a, b = b, a % b # affectation de liste à liste return a </syntaxhighlight> {{boîte déroulante fin}} Notez que le module NumPy propose l'instruction <code>gcd()</code> : <syntaxhighlight lang="python"> import numpy … print(numpy.gcd(a, b)) </syntaxhighlight> === Tours de Hanoï === {{loupe|w:Tours de Hanoï}} Écrire un programme Python qui demande le nombre ''n'' de plateaux et affiche les manipulations nécessaires pour déplacer la pile d'un emplacement à un autre. Le programme utilisera l'algorithme récursif. {{boîte déroulante début|solution}} <syntaxhighlight lang="python"> """nom : hanoi.py auteur : User:cdang date de création : 2019-02-19 dates de modification : ---------------------------------------------------------------------------- version de Python : 3 module requis : aucun ---------------------------------------------------------------------------- Objectif : résout le problème des tours de Hanoï Entrées ------- trois chaînes de caractères (nom des piliers) Sorties ------- une chaîne de caractères (liste des opérations) """ # *************** # *************** # ** Fonctions ** # *************** # *************** def hanoi(a, b, c, n): """Résout le problème des tours de Hanoï de manière récursive But : déplace la pile de n disques du piler a au pilier b Entrées ------- a, b c : chaînes de 1 caractère, référence des emplacements ; n : entier, nombre de disques sur l'emplacement a Sorties ------- operations : chaînes de caractères décrivant les opérations """" if n>1: operations = hanoi(a, c, b, n-1) operations = operations+a+"→"+b+" ; " operations = operations+hanoi(c, b, a, n-1) else: operations = a+"→"+b+" ; " return operations # ************************* # ************************* # ** Programme principal ** # ************************* # ************************* resultat = hanoi("1", "2", "3", 3) print(resultat) </syntaxhighlight> {{boîte déroulante fin}} === Lancer de rayons === [[Fichier:Lentille hemispherique perspective.svg|vignette|Lentille hémisphérique.]] Considérons une lentille hémisphérique de rayon R faite d’un verre d’indice de réfraction ''n''. Nous plaçons une source ponctuelle à une distance ''d'' du dioptre plan, sur l’axe optique. Tracer des rayons partant de la source et traversant la lentille. {{clear}} {{Boîte déroulante/début |titre=Analyse d’optique géométrique}} [[Fichier:Lentille hemispherique analyse geometrique.svg|vignette|Analyse géométrique du problème.]] Il s’agit d’un problème ayant une symétrie de révolution par rapport à l’axe optique. Nous pouvons nous réduire à un problème plan en nous plaçant dans un plan contenant l’axe optique ; l’axe optique est encore un axe de symétrie orthogonale, nous pouvons donc nous contenter d'étudier un demi-plan. Pour simplifier, nous plaçons le centre du dioptre sphérique à l’origine O du repère. L’axe optique est l’axe ''x'' et l'axe perpendiculaire, vertical sur la figure, c’est l’axe ''y''. Les coordonnées de la source sont donc (-''d'' ; 0). Le rayon issu de la source et faisant un angle θ avec l’axe ''x'' frappe le dioptre plan à l’altitude ''h''. Nous avons : : ''h'' = ''d'' ⋅ tan θ. L’angle d’incidence vaut θ. D’après la loi de Snell-Descartes, l'angle de réfraction θ<sub>2</sub> vaut : : θ<sub>2</sub> = arcsin((sin θ) / ''n''). Le rayon réfracté passe par le points de coordonnées (0, ''h''). L’équation de la droite est donc : : ''y'' = a ⋅ ''x'' + ''h'' avec : ''a'' = tan θ<sub>2</sub>. L’équation du cercle de centre O et de rayon R est : : ''x''<sup>2</sup> + ''y''<sup>2</sup> = R<sup>2</sup>. Les coordonnées (''x''<sub>M</sub>, ''y''<sub>M</sub>) de l’intersection M du rayon avec le dioptre sphérique vérifient les deux équations. Par substitution, nous obtenons une équation du second degré en ''x'' que nous savons résoudre : : ''x''<sub>M</sub><sup>2</sup> + (''a'' ⋅ ''x''<sub>M</sub> + ''h'')<sup>2</sup> = R<sup>2</sup> : ⇔ (1 + ''a''<sup>2</sup>) ⋅ ''x''<sub>M</sub><sup>2</sup> + 2 ⋅ ''a'' ⋅ ''h'' ⋅ ''x''<sub>M</sub> + ''h''<sup>2</sup> – R<sup>2</sup> = 0. D’après les propriétés du cercle, le rayon est perpendiculaire à la tangente. Le rayon [OM] est donc normal au dioptre en M. Nous pouvons déterminer l’angle d’incidence θ<sub>i</sub> par le produit scalaire : : <math>\begin{pmatrix} 1 \\ a \end{pmatrix} \cdot \begin{pmatrix} x_\mathrm{M} \\ y_\mathrm{M} \end{pmatrix} = \sqrt{1^2 + a^2} \cdot \mathrm{R} \cdot \cos(\theta_\mathrm{i})</math> ce qui nous permet de calculer cet angle : : <math>\theta_\mathrm{i} = \operatorname{arcos} \left ( \frac{x_\mathrm{M} + a \cdot y_\mathrm{M}}{\mathrm{R} \cdot \sqrt{1^2 + a^2} } \right )</math> Comme nous passons vers un milieu d’indice plus faible, il y a un risque de réflexion totale. L’angle limite est : : θ<sub>max</sub> = arcsin(1/''n''). Si l’on a θ<sub>i</sub> &gt; θ<sub>max</sub>, le rayon repart vers l’intérieur. Nous ne traçons pas le rayon car cela nous emmènerait trop loin dans l’analyse. En revanche, si θ<sub>i</sub> ≤ θ<sub>max</sub>, alors nous pouvons appliquer la loi de Snell-Descartes pour avoir l’angle de réfraction θ<sub>e</sub> : : θ<sub>e</sub> = arcsin(''n'' ⋅ sin θ<sub>i</sub>). Pour tracer le rayon sortant, il nous faut l’angle θ<sub>3</sub> par rapport à l’horizontale. L’angle du rayon [OM] par rapport à l’horizontal vaut arctan(''y''<sub>M</sub> / ''x''<sub>M</sub>), nous avons donc : θ<sub>3</sub> = arctan(''y''<sub>M</sub> / ''x''<sub>M</sub>) + θ<sub>e</sub>. {{Boîte déroulante/fin}} {{Boîte déroulante/début |titre=Analyse algorithmique}} '''Structure des données''' Le problème est décrit par trois paramètres : # Le rayon <code>R1</code> de la lentille, en milliètres (réel en virgule flottante). # L’indice du verre, <code>n</code> sans dimension (réel en virgule flottante). L’indice de l’air vaut 1. # La distance de la source au dioptre d’entrée plan, <code>d</code> en millimètres (réel en virgule flottante). Un rayon est caractérisé par quatre paramètres : # L’angle d’émission <code>theta1</code> en radians (réel en virgule flottante). # L’angle de réfraction dans la lentille <code>theta2</code> en radians (réel en virgule flottante). # Les cordonnées <code>M</code> en millimètre (vecteur de dimension 2 <code>([x, y])</code> de réels en virgule flottante) du point d’intersection du rayon avec le dioptre sphérique. # L’angle de réfraction dans l’air après la lentille <code>theta3</code> en radians (réel en virgule flottante). Pour le calcul et le tracé, nous avons besoin des paramètres intermédiaires suivants : * l’altitude ''y'' = <code>h</code> en millimètres (réel en virgule flottante) à laquelle le rayon frappe le dioptre plan d’entrée ; * l’angle d’incidence du rayon avec le dioptre sphérique <code>thetaint</code> en radians (réel en virgule flottante). Les angles sont stockés en radians car c’est l’unité naturelle pour le calcul mais nous affichons les valeurs en degrés. Comme le calcul de conversion est récurrent, nous conservons les facteurs <code>degversrad</code> (conversion des degrés vers les radians, facteur valant π/180, réel en virgule flottante) et <code>radversdeg</code> (conversion des radians vers les degrés, facteur valant 180/π, réel en virgule flottante). '''Fonctions''' Nous avons besoin d’une fonction qui calcule les trois paramètres du rayon <code>(theta2, M, theta3)</code> à partir de l’angle d’émission <code>theta1</code>. Nous appelons cette fonction <code>lanceRayon()</code>. Cette fonction fait appelle à une fonction qui calcule l’angle du rayon réfracté à partir de l’angle du rayon incident <code>theta1</code>, les deux angles étant par rapport à la normale au dioptre au point considéré. Nous appelons cette fonction <code>refrac()</code>. La recherche de l’intersection <code>M</code> du rayon avec le dioptre sphérique nécessite de résoudre une équation du second degré. Nous utilisons pour cela la recherche des racines du polynôme en <code>x</code> avec la fonction <code lang="python">numpy.polynomial.polynomial.polyroots()</code>. D’après la configuration du problème géométrique, si l’on s’assure que le rayon frappe bien la lentille (0 ≤ <code>h</code> ≤ <code>R1</code>) alors nous sommes sûrs que le problème a deux solutions réelles (une positive et une négative) ou, dans le cas dégénéré où <code>h == R1</code>, une valeur unique <code>x == 0</code>. Comme nous recherchons la valeur positive, nous sélectionons la plus grande des deux racines. Pour la gestion de la réflexion interne : dans la fonction <code>refrac()</code>, nous vérifions les conditions de réflexion totale et si elles sont remplies, alors nous générons une erreur (commandes <code lang="python">try… except</code> et <code lang="python">raise ValueError</code>). Cette erreur est propagée à la fonction <code>lanceRayon()</code> : <code>lanceRayon()</code> appelle la fonction <code>refrac()</code> et si cette fonction renvoie une erreur, alors <code>lanceRayon()</code> renvoie également une erreur. Pour trouver l’angle d’émission <code>thetaLimite</code> provoquant la réflexion totale (en radians, réel en virgule flottante), nous effectuons une recherche par dichotomie : * nous partons de l’angle maximum possible, lorsque le rayon frappe le sommet de la lentille, et nous appelons la fonction <code>lanceRayon()</code> ; si cela ne génère pas d’erreur, alors nous pouvons aller jusqu’à cette valeur, la recherche est terminée ; si cela génère une erreur, alors nous divisons la valeur par deux ; * à une étape de la recherche donnée, si <code>lanceRayon()</code> ne génère pas d’erreur avec l’angle testé, alors nous savons que l’angle limite est supérieur à cette valeur ; cette valeur minore donc la valeur recherchée ; si au contraire <code>lanceRayon()</code> génère une erreur, alors c’est que l’angle est trop important, cette valeur majore donc la valeur recherchée ; nous pouvons ainsi resserer l’intervalle de recherche ; * nous nous arrêtons lorsque les valeurs haute et basse sont suffisamment proche. Concrètement : # Nous définissons une variable <code>angleHaut</code> angle en radians, réel en virgule flottante) qui est l’angle d’émission le plus bas connu provoquant la réflexion totale. # Nous définissons une variable <code>angleBas</code> angle en radians, réel en virgule flottante) qui est l’angle d’émission le plus haut connu ne provoquant pas de réflexion totale. Sa valeur initiale est 0. L’angle limite recherché est donc entre <code>angleBas</code> et <code>angleHaut</code>. # Nous définissons l’angle <code>angleTest</code> comme étant la moyenne entre <code>angleBas</code> et <code>angleHaut</code>. Si <code>lanceRayon(angleTest)</code> génère une erreur, alors <code>angleTest</code> est la nouvelle valeur d’<code>angleHaut</code> (puisque c’est une valeur provoquant la réflexion totale et qu’elle est plus basse que la valeur actuelle d’<code>angleHaut</code>). À l’inverse, si <code>lanceRayon(angleTest)</code> ne génère pas d’erreur, alors <code>angleTest</code> est la nouvelle valeur d’<code>angleBas</code> (puisque c’est une valeur ne provoquant pas la réflexion totale et qu’elle est plus haute que la valeur actuelle d’<code>angleBas</code>). # Nous arrêtons la procédure lorsque l’écart entre <code>angleBas</code> et <code>angleHaut</code> est inférieur à {{unité|10|échelle=<sup>–3</sup>|rad}} (valeur arbitraire). La valeur retenue est la valeur finale d’<code>angleBas</code> (puisque l’on veut être sûr qu’il n’y ait pas de réflexion totale). La valeur affichée est la valeur en degrés arrondie au dixième. {{Boîte déroulante/fin}} {{Boîte déroulante/début |titre=Solution}} Nous demandons à l’utilisateur ou à l’utilisatrice les valeurs des paramètres du problème : rayon de la lentille, distance de la source, indice de réfraction du verre. Nous vérifions que les valeurs entrées sont bien des nombres ; si c’est une chaîne vide, alors nous utilisons une valeur par défaut. Nous créons une fonction <code>refrac()</code> qui permet de calculer l’angle réfracté à partir de l’angle d’incidence et des indices de réfraction. S’il y a rélexion totale, alors nous générons une erreur. La fonction <code>lanceRayon()</code> calcule les différents points de passage du rayon. Elle appelle pour cela la fonction <code>refrac()</code>. Si un appel de la commande <code>refrac()</code> génère une erreur, alors nous générons également une erreur. Nous déterminons l’angle d’émision du rayon <code>thetaLimite</code> qui provoque une réflecxion totale. Pour cela, nous créons une fonction <code>rechercheLimite()</code> qui cherche par dichotomie. Nous traçons un rayon tous les 5° jusqu’à la valeur limite. <syntaxhighlight lang="python"> #!/usr/bin/env python3 # coding: utf-8 """nom : lancerRayons.py auteur : User:cdang date de création : 2022-05-06 dates de modification : ---------------------------------------------------------------------------- version de Python : 3 module requis : NumPy, matplotlib ---------------------------------------------------------------------------- Objectif : trace des trajets optique avec une lentille hémisphérique Entrées ------- Le rayon de la lentille, la distance de la source, l’indice de réfraction du verre, trois chaînes de caractères saisies par l’utilisateur·rice et qui sont converties en réels. Sorties ------- La valeur limite de l’angle (réel) et le tracé de plusieurs rayons. """ # ****************************************************** # ****************************************************** # ** Lancer de rayons pour une lentille hémisphérique ** # ****************************************************** # ****************************************************** import numpy as np import matplotlib.pyplot as plt import numpy.polynomial.polynomial as nppol # ************** # * Constantes * # ************** # Pour la conversion degrés ↔ radians radversdeg = 180/np.pi degversrad = 1/radversdeg # ************* # * Fonctions * # ************* def boucleEntreeNombre(messageSaisie, valeurDefaut): """Permet de s’assurer que l’utilisateur·rice a bien entré un nombre. Entrée : — message à afficher (chaîne de caractères) ; — valeur par défaut (réel à virgule flottante). Sortie : nombre (réel à virgule flottante).""" messageErreur = "Veuillez entrer une valeur numérique (ou vide pour accepter la valeur par défaut).\n" execute = True while execute: strNombre = input(messageSaisie+f" (valeur par défaut {valeurDefaut}) : ") if strNombre == "": nombre = valeurDefaut execute = False else: try: nombre = float(strNombre) except: print(messageErreur) else: execute = False return nombre def initialisation(): """L’utilisateur·rice entre les variables du problème. Entrées : aucune. Sorties : — R1 (mm) : rayon de la lentille ; — d (mm) : distance de la source au dioptre plan ; — n (sans dimension) : indice de réfraction du verre.""" R1 = boucleEntreeNombre("Rayon de la lentille en mm", 20.0) d = boucleEntreeNombre("Distance de la source au dioptre plan en mm", 20.0) n = boucleEntreeNombre("Indice de réfraction (sans dimension)", 1.5) return (R1, d, n) def refrac(n1, n2, theta1): """Calcule l’angle de réfraction theta2 (radians) en fonction — de l’angle d’incidence theta1 (radians); — de l’indice de réfraction n1 du premier milieu ; — de l’indice de réfraction n2 du second milieu.""" reflexionTotale=False rapport=n2/n1 rapportinv=np.reciprocal(rapport) if n1 > n2: thetal = np.arcsin(rapport) # angle limite pour la réflexion totale if theta1 >= thetal: reflexionTotale=True if reflexionTotale: print("Réflexion totale") raise ValueError else: return np.arcsin(rapportinv*np.sin(theta1)) def lanceRayon(n1, n2, d, R, theta1): """Détermine le rayon issu de la source située à une distance d (mm) du bareau et avec une élévation de theta1 (radians), en fonction des indices de réfraction n1 et n2. Les éléments retournés sont : — la hauteur h (mm) à laquelle le rayon frappe le barreau ; — l’angle de réfraction theta2 (radians)) dans le barreau ; — l’angle de réfraction theta3 (radians) à la sortie du barreau — le point M(x, y) (mm) auquel le rayon sort du barreau.""" h = d*np.tan(theta1) if h >= R: print("Le rayon est au-dessus du barreau") raise ValueError else: theta2 = refrac(n1, n2, theta1) a = np.tan(theta2) x = max(nppol.polyroots([h*h - R*R, 2*a*h, 1+a*a])) # recherche de l’intersection du rayon avec le cercle y = a*x + h M = np.array([x, y]) thetaint = np.arccos((x + a*y)/(R*np.sqrt(1 + a*a))) theta3 = np.arctan(y/x) - refrac(n2, n1, thetaint) return (h, theta2, theta3, M) def rechercheLimite(n1, n2, d, R): """Recherche l’angle limite pour la réflexion totale. Entrée : — indice de réfraction des milieux 1 et 2, n1 et n2 ; — distance au barreau, d(mm). Sortie : angle limite theta (radians)""" angleHaut = np.arctan(R/d) angleBas = 0 angleTest = angleHaut try: lanceRayon(n1, n2, d, angleTest, R) except: condition = True # il y a réflexion total en haut de la lentille else: condition = False # il n’y a jamais réflexion totale dans la lentille while condition: #dichotomie angleTest = np.mean([angleHaut, angleBas]) # on ajuste la valeur de test try: lanceRayon(n1, n2, d, R, angleTest) except: angleHaut = angleTest # réflexion totale : on abaisse la valeur maximale else: angleBas = angleTest # pas de réflexion totale : on monte la valeur minimale condition = ((angleHaut - angleBas) >= 0.001) # on a cerné la limite à 0,001 rad près if not condition: angleTest = angleBas return angleTest # *********************** # * Programme principal * # *********************** (R1, d, n) = initialisation() xmax = round(R1 + d) thetaLimite = rechercheLimite(1, n, d, R1) thetaLimiteDeg = thetaLimite*radversdeg print(f"Angle limite pour la réflexion totale : {thetaLimiteDeg:.1f}°.\n") anglesDeg = np.arange(0, thetaLimiteDeg, 5)[1:] # trace un rayon tous les 5° anglesRad = anglesDeg*degversrad nb = len(anglesDeg) h = np.zeros(nb) # initialisation des vecteurs de valeurs theta2 = np.zeros(nb) theta3 = np.zeros(nb) M = np.zeros((nb, 2)) for i in range(nb): (h[i], theta2[i], theta3[i], M[i, :]) = lanceRayon(1, n, d, R1, anglesRad[i]) (h_lim, theta2_lim, theta3_lim, M_lim) = lanceRayon(1, n, d, R1, thetaLimite) # tracé anglesCercle = 0.5*np.pi*(np.linspace(1, 0, 20)) x_cercle = R1*np.cos(anglesCercle) # coordonnées des pints du cercle y_cercle = R1*np.sin(anglesCercle) fig = plt.plot([-d,xmax], [0, 0], "k-.", linewidth="0.5") # tracé de l’axe optique for i in range(nb): plt.plot([-d, 0, M[i, 0], xmax], [0, h[i], M[i, 1], M[i, 1] + (xmax - M[i, 0])*np.tan(theta3[i])], label=f"{anglesDeg[i]:.0f}°") plt.plot([-d, 0, M_lim[0], xmax], [0, h_lim, M_lim[1], M_lim[1] + (xmax - M_lim[0])*np.tan(theta3_lim)], label=f"{0.1*int(np.trunc(10*thetaLimite*radversdeg)):.1f}°") plt.plot(x_cercle, y_cercle, "k", linewidth="0.5") # tracé du cercle plt.plot([0,0], [0, R1], "k", linewidth="0.5") # tracé du premier dioptre #plt.axis("square") plt.gca().set_aspect("equal", adjustable="box") plt.xlabel("x (mm)") plt.ylabel("y (mm)") plt.title("Lentille hémisphérique, lancer de rayons") plt.legend() plt.savefig("lentille_hemispherique_lancer_rayon.svg", format="svg") plt.show() </syntaxhighlight> {{Boîte déroulante/fin}} == Mesurer le temps == Le module <code>time</code> fournit les fonctions suivantes : * <code>time.gmtime()</code> : renvoie la date et l'heure du méridien de Greenwich (''{{lang|en|Greenwich mean time}}'', GMT), sous la forme d'un dictionnaire (année, mois, jour du mois, heure, minute, seconde, jour de la semaine, jour de l'année, heure d'été/hiver), ** jour de la semaine est un entier entre 0 (lundi) et 6 (dimanche), ** jour du mois est un entier entre 1 et 366 ; * <code>time.localtime()</code> : comme le précédent, mais l'heure est l'heure locale ; * <code>time.time()</code> : donne le nombre de seconde qui se sont écoulées depuis le 1er janvier 1970 ; * <code>time.gmtime(n)</code> et <code>time.localtime(n)</code> transforment un nombre de secondes (écoulées depuis le 1er janvier 1970) en une date au format (année, mois, jour, etc.), n-uplet de neuf valeurs ; <code>time.mktime()</code> fait le contraire, il transforme un n-uplet de neuf valeurs (années, mois, jour, etc.) en un nombre de secondes (écoulées depuis le 1er janvier 1970) ; * <code>time.sleep(n)</code> : provoque une pause dans le déroulement du programme de ''n'' secondes ; * <code>time.perf_counter()</code> : indique une date en seconde ; s'utilise pour mesurer la durée d'exécution d'une partie du code, en faisant la différence entre deux relevés. Concernant la date et l'heure sous la forme d'un n-uplet, on peut extraire l'heure de la manière suivante : <syntaxhighlight lang="python"> import time a = time.localtime() print("Il est ", a[3], "h", a[4]) # ou bien print("Il est ", a.tm_hour, "h", a.tm_min) </syntaxhighlight> Pour mesurer la performance d'une portion de code : <syntaxhighlight lang="python"> import time t1 = time.perf_counter() <suite d’instructions> t2 = time.perf_counter() print("Durée d'exécution :", t2-t1 </syntaxhighlight> == Programmation orientée objet == Nous n'allons pas ici faire un cours de programmation orientée objet (POO), nous allons aborder le sujet de manière pragmatique. De manière schématique, un « objet » est une « super-variable ». Cette super-variable peut contenir plusieurs variables, appelées « attributs » ; elle contient en fait un dictionnaire (paires « nom d'attribut : valeur d'attribut »). Elle peut aussi contenir des fonctions spécifiques appelées « méthodes ». De même qu'une variable a un type, un objet fait partie d'une « classe ». La classe est le modèle de l'objet ; en franglais informatique, on dit que l'objet est une instance de la classe. La POO est donc un formalisme : lorsque l'on définit des variables et des fonctions concernant un même type d'objet (au sens commun du terme), on les empaquette dans une classe. Il faut donc d'abord définir la classe, puis attribuer cette classe à un objet (« instancier » la classe). Considérons par exemple que nous voulons travailler sur des [[w:Engrenage|engrenages]] ; pour simplifier, nous nous contentons d'engrenages à dentures droites. Une roue dentée, un pignon, est essentiellement définie par son nombre de dents Z et par son module ''m'' qui correspond à la largeur de dents<ref>ainsi que par son épaisseur ''e'' et le matériau dont elle est faite mais nous allons négliger ces paramètres pour la simplicité de l'étude.</ref>. Nous allons définir trois méthodes : la méthode <code>.diametrePrimitif()</code> qui calcule le diamètre primitif de la roue dentée, <code>.pas()</code> qui calcule la largeur des dents au niveau du cercle primitif et <code>.rapport()</code> qui calcule le rapport de transmission de deux roues engrenées Z<sub>1</sub>/Z<sub>2</sub>. La méthode <code>.rapport()</code> vérifie par ailleurs que les roues ont le même module, condition indispensable pour former un engrenage. Nous définissons la classe ainsi : <syntaxhighlight lang="python"> class pignon: """roue dentée""" # explication de la classe pi = 3.141592653589793 # pour calculer le pas def __init__(self, Z=13, m=0.06): # instructions lancées lors de la déclaration """Valeurs des attributs""" self.Z = Z # nombre de dents self.m = m # module def diametrePrimitif(self): """Calcule le diamètre primitif""" return self.m*self.Z def pas(self): """Calcule le pas""" return self.pi*self.m def rapport(roueDentee, self): """Calcule le rapport de transmission""" if roueDentee.m != self.m: # gestion de l'erreur raise ValueError("Les pignons doivent avoir le même module") else: return roueDentee.Z/self.Z </syntaxhighlight> Nous remarquons que lorsque nous déclarons les méthodes, le paramètre <code>self</code> correspond à l'objet lui-même. Ainsi, dans la méthode <code>.rapport()</code>, la variable <code>self.Z</code> est le nombre de dents de la roue elle-même et <code>roueDentee.Z</code> est le nombre de dents de la roue passée en paramètre. Pour déclarer les roues, nous écrivons : <syntaxhighlight lang="python"> roue1 = pignon() # attribution de la classe, « instanciation » roue1.Z = 13 # définition des caractéristiques du pignon « roue1 » roue1.m = 2 roue2 = pignon(16, 2) # manière alternative </syntaxhighlight> Nous pouvons alors utiliser les objets de la manière suivante : <syntaxhighlight lang="python"> print(roue1.Z) # 13 print(roue1.diametrePrimitif()) # 26 R = roue1.rapport(roue2) # 0.8125 </syntaxhighlight> La commande <code>dir(a)</code> affiche tous les attributs et méthodes de l'objet <code>a</code>. ; Ressources : {{lien web | url = https://docs.python.org/3/tutorial/classes.html | titre = Classes | site = Python documentation | consulté le = 2019-03-08 }} == Interface graphique avec Tk == === Généralités === Une interface graphique utilisateur (GUI, ''{{lang|en|graphic user interface}}'') est un ensemble de boîtes permettant d'interagir avec l'utilisateur, c'est-à-dire qui permettent la saisie d'informations, l'exécution d'actions et l'affichage d'informations. L'interface se compose d'éléments appelés ''{{lang|en|widgets}}''. Les éléments ''({{lang|en|widgets}})'' classiques sont : * boîte de dialogue ''({{lang|en|dialog box}})'' : fenêtre contenant d'autres éléments ; * étiquette ''({{lang|en|label}})'' : texte affiché ; * liste déroulante ''({{lang|en|drop-down list}})'' : zone permettant le choix d'une option, la liste se déployant lorsque l'on clique sur la zone ; * zone de texte, champ de saisie ''({{lang|en|text box}})'' : zone permettant de taper du texte ; * boîte combinée ''({{lang|en|combo box}})'' : zone de saisie de texte contenant une liste déroulante qui permet de choisir des éléments prédéfinis ; * bouton ''({{lang|en|button}})'' : objet effectuant une action lorsque l'on clique dessus ; * case à cocher ''({{lang|en|checkbox, tickbox}})'' : objet permettant d'activer ou de désactiver une option lorsque l'on clique dessus ; * bouton radio, case d'option ''({{lang|en|radio button}})'' : objet permettant d'activer une option en désactivant les autres options ; une seule option peut être activée à la fois. === Avec Tk === Plusieurs modules permettent de gérer les interfaces graphiques. Nous choisissons ici le module développé sur la bibliothèque Tk qui est une bibliothèque multiplateforme. Pour cela, nous importons le module <code>tkinter</code> ainsi que le module <code>ttk</code>, ce dernier proposant des options plus « modernes » : <syntaxhighlight lang="python"> import tkinter as tk from tkinter import ttk </syntaxhighlight> Voici un programme permettant comme précédemment de calculer le rapport de transmission d'un engrenage. Nous détaillons sa construction ci-après. <syntaxhighlight lang="python"> # référence : https://tkdocs.com/tutorial/firstexample.html import tkinter as tk from tkinter import ttk # *************** # *************** # ** Fonctions ** # *************** # *************** def calcule(*args): """Calcule le rapport de transmission d'un engrenage""" try: valeurZ1 = float(IUz1.get()) valeurM1 = float(IUm1.get()) valeurZ2 = float(IUz2.get()) valeurM2 = float(IUm2.get()) if valeurM1 != valeurM2: IUrapport.set("Erreur de module") else: IUrapport.set(valeurZ2/valeurZ1) except: IUrapport.set("erreur") # ************************* # ************************* # ** Interface graphique ** # ************************* # ************************* # fenetre principale fenetre = tk.Tk() fenetre.title("Rapport de réduction") # élément (widget) cadre contenant tout le reste cadre = ttk.Frame(fenetre, padding="3 3 12 12") cadre.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S)) # le cadre s'étire si l'on étire la fenêtre fenetre.columnconfigure(0, weight=1) fenetre.rowconfigure(0, weight=1) # Paramètres du système (variables) IUz1 = tk.StringVar() IUm1 = tk.StringVar() IUz2 = tk.StringVar() IUm2 = tk.StringVar() IUrapport = tk.StringVar() # Création des zones de saisie z1_entry = ttk.Entry(cadre, width=7, textvariable=IUz1) m1_entry = ttk.Entry(cadre, width=7, textvariable=IUm1) z2_entry = ttk.Entry(cadre, width=7, textvariable=IUz2) m2_entry = ttk.Entry(cadre, width=7, textvariable=IUm2) # Création des étiquettes statiques z1_label = ttk.Label(cadre, text="z1") m1_label = ttk.Label(cadre, text="m1") z2_label = ttk.Label(cadre, text="z2") m2_label = ttk.Label(cadre, text="m2") rapport_statique = ttk.Label(cadre, text="Rapport de transmission : ") # Création de l'étiquette dynamique rapport_dynamique = ttk.Label(cadre, textvariable=IUrapport) # Création du bouton bouton = ttk.Button(cadre, text="Calcul", command=calcule) # Placement des éléments (widgets) z1_label.grid(column=1, row=1, sticky=tk.W) z1_entry.grid(column=2, row=1, sticky=(tk.W, tk.E)) m1_label.grid(column=1, row=2, sticky=tk.W) m1_entry.grid(column=2, row=2, sticky=(tk.W, tk.E)) z2_label.grid(column=1, row=3, sticky=tk.W) z2_entry.grid(column=2, row=3, sticky=(tk.W, tk.E)) m2_label.grid(column=1, row=4, sticky=tk.W) m2_entry.grid(column=2, row=4, sticky=(tk.W, tk.E)) rapport_statique.grid(column=1, row=5, sticky=tk.W) rapport_dynamique.grid(column=2, row=5, sticky=(tk.W, tk.E)) bouton.grid(column=2, row=6, sticky=tk.W) # ajoute une gouttière entre les éléments for enfant in cadre.winfo_children(): enfant.grid_configure(padx=5, pady=5) # Emplacement initial du curseur z1_entry.focus() # effet de la touche [entrée] fenetre.bind("<Return>", calcule) # ************************* # ************************* # ** Programme principal ** # ************************* # ************************* # Affichage et activation de la fenêtre fenetre.mainloop() </syntaxhighlight> [[Fichier:Organisation interface Tk Python.svg|vignette|upright=2|Organisation des ''widgets''.]] '''Explications''' Nous commençons par définir la boîte de dialogue que nous appelons <code>fenetre</code> ; c'est un objet <code>Tk</code> et nous lui donnons un titre « » : <syntaxhighlight lang="python"> fenetre = tk.Tk() fenetre.title("Rapport de réduction") </syntaxhighlight> Puis, nous définissons un cadre attaché à cette fenêtre et qui va nous permettre « d'accrocher » les autres éléments, ce qui permet de garder une apparence satisfaisante lorsque l'on retaille la fenêtre : <syntaxhighlight lang="python"> cadre = ttk.Frame(fenetre) </syntaxhighlight> Le cadre va comporter six lignes ''({{lang|en|row}})'' et deux colonnes ''({{lang|en|column}})''. Nous allons placer une étiquette ''({{lang|en|label}})'' « z1 » : <code>text="z1"</code>. Cette étiquette se trouve dans une case du cadre, celle de la première colonne et la première ligne : <code>grid(column=1, row=1)</code>. Par rapport à cette case, elle est collée à « l'ouest » (W, ''{{lang|en|west}}'', gauche) de la case : <code>sticky=tk.W</code>. <syntaxhighlight lang="python"> z1_label = ttk.Label(cadre, text="z1") # Création de l'étiquette z1_label.grid(column=1, row=1, sticky=tk.W) # Placement de l'étiquette </syntaxhighlight> Notez que l'on aurait pu écrire directement : <syntaxhighlight lang="python"> ttk.Label(cadre, text="z1").grid(column=1, row=1, sticky=tk.W) </syntaxhighlight> mais le fait de séparer la création de l'élément et son placement facilite la maintenance (recherche d'erreur, évolution du code). Pour tout ce qui est dynamique, c'est-à-dire les zone de saisie des valeurs et l'affichage du résultat, il faut définir des « chaînes variables » ''({{lang|variable strings}})'' : <syntaxhighlight lang="python"> IUz1 = tk.StringVar() </syntaxhighlight> Cette variable est une variable globale à la création. Nous pouvons alors placer la zone de saisie ''({{lang|en|entry}})'' à côté de l'étiquette lui correspondant. Nous nommons la zone de saisie <code>z1_entry</code> : <syntaxhighlight lang="python"> z1_entry = ttk.Entry(cadre, width=7, textvariable=IUz1) </syntaxhighlight> Nous faisons de même pour les trois autres paramètres de l'engrenage, ''m''<sub>1</sub>, ''z''<sub>2</sub> et ''m''<sub>2</sub>. Le résultat est également une chaîne variable globale. Par rapport à notre mise en page, elle se situe dans la case colonne 2 ligne 5, centrée sur cette case (collé à l'est et à l'ouest) : <syntaxhighlight lang="python"> rapport = tk.StringVar() rapport_dynamique = ttk.Label(cadre, textvariable=rapport) rapport_dynamique.grid(column=2, row=5, sticky=(tk.W, tk.E)) </syntaxhighlight> Il nous faut encore définir une fonction de manière classique, nous l'appelons « calcule ». Les variables étant globales, on les utilise directement. On récupère les valeurs avec la méthode <code>get()</code> et nous modifions la valeur avec la méthode <code>set()</code> : <syntaxhighlight lang="python"> def calcule(): valeurZ1 = float(IUz1.get()) valeurZ2 = float(IUz2.get()) IUrapport.set(valeurZ2/valeurZ1) </syntaxhighlight> Cette fonction est déclenchée lorsque l'on clique sur le bouton « Calcul » situé dans la case du cadre ligne 6 colonne 2 : <syntaxhighlight lang="python"> bouton = ttk.Button(cadre, text="Calcul", command=calcule) bouton.grid(column=2, row=6, sticky=tk.W) </syntaxhighlight> ou bien si l'on appuie sur la touche <code>[entrée]</code> du clavier : <syntaxhighlight lang="python"> fenetre.bind("<Return>", calcule) </syntaxhighlight> À tout ceci, nous ajoutons des « gouttières » (marges, ''{{lang|en|paddings}}'') afin d'espacer les éléments. Il faut ensuite « activer » la fenêtre pour qu'elle s'affiche. La méthode est <code>mainloop()</code> (boucle principale) : « boucle » (elle est active en permanence et attend des actions sur ses éléments), <syntaxhighlight lang="python"> fenetre.mainloop() </syntaxhighlight> Nous avons ci-dessus mis la plupart du code en programme principal. Nous pouvons aussi programmer de manière fonctionnelle, en mettant la plupart du code dans des fonctions ; cependant, pour que la fenêtre et les variables dynamiques soient globales à tout le programme, elles doivent être déclarées dans le programme principal. Nous pouvons aussi mêler la programmation orientée objet. {{boîte déroulante début|Calcul du rapport de transmission en programmation fonctionnelle et orientée objet}} <syntaxhighlight lang="python"> # référence : https://tkdocs.com/tutorial/firstexample.html import tkinter as tk from tkinter import ttk # ************* # ************* # ** Classes ** # ************* # ************* class pignon: """roue dentée""" # explication de la classe pi = 3.141592653589793 # pour calculer le pas def __init__(self, Z=13, m=0.06): """Valeurs des attributs""" # instructions lancées lors de la déclaration self.Z = Z # nombre de dents self.m = m # module def diametrePrimitif(self): """Calcule le diamètre primitif""" return self.m*self.Z def pas(self): """Calcule le pas""" return self.pi*self.m def rapport(roueDentee, self): """Calcule le rapport de transmission""" if roueDentee.m != self.m: # gestion de l'erreur raise ValueError("Les pignons doivent avoir le même module") else: return roueDentee.Z/self.Z # ************************ # ************************ # ** Variables globales ** # ************************ # ************************ # fenetre principale fenetre = tk.Tk() # Paramètres du système (variables) IUz1 = tk.StringVar() IUm1 = tk.StringVar() IUz2 = tk.StringVar() IUm2 = tk.StringVar() IUrapport = tk.StringVar() # *************** # *************** # ** Fonctions ** # *************** # *************** def calcule(*args): """Calcule le rapport de transmission d'un engrenage""" try: valeurZ1 = float(IUz1.get()) valeurM1 = float(IUm1.get()) valeurZ2 = float(IUz2.get()) valeurM2 = float(IUm2.get()) if valeurM1 != valeurM2: IUrapport.set("Erreur de module") else: roue1 = pignon(valeurZ1, valeurM1) roue2 = pignon(valeurZ2, valeurM2) IUrapport.set(roue1.rapport(roue2)) except: IUrapport.set("Erreur") # *********************** # * Interface graphique * # *********************** def configureFenetre(): """Configuration de la fenêtre principale""" fenetre.title("Rapport de réduction") # élément (widget) cadre contenant tout le reste cadre = ttk.Frame(fenetre, padding="3 3 12 12") cadre.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S)) # le cadre s'étire si l'on étire la fenêtre fenetre.columnconfigure(0, weight=1) fenetre.rowconfigure(0, weight=1) # Création des zones de saisie z1_entry = ttk.Entry(cadre, width=7, textvariable=IUz1) m1_entry = ttk.Entry(cadre, width=7, textvariable=IUm1) z2_entry = ttk.Entry(cadre, width=7, textvariable=IUz2) m2_entry = ttk.Entry(cadre, width=7, textvariable=IUm2) # Création des étiquettes statiques z1_label = ttk.Label(cadre, text="z1") m1_label = ttk.Label(cadre, text="m1") z2_label = ttk.Label(cadre, text="z2") m2_label = ttk.Label(cadre, text="m2") rapport_statique = ttk.Label(cadre, text="Rapport de transmission : ") # Création de l'étiquette dynamique rapport_dynamique = ttk.Label(cadre, textvariable=IUrapport) # Création du bouton bouton = ttk.Button(cadre, text="Calcul", command=calcule) # Placement des éléments (widgets) z1_label.grid(column=1, row=1, sticky=tk.W) z1_entry.grid(column=2, row=1, sticky=(tk.W, tk.E)) m1_label.grid(column=1, row=2, sticky=tk.W) m1_entry.grid(column=2, row=2, sticky=(tk.W, tk.E)) z2_label.grid(column=1, row=3, sticky=tk.W) z2_entry.grid(column=2, row=3, sticky=(tk.W, tk.E)) m2_label.grid(column=1, row=4, sticky=tk.W) m2_entry.grid(column=2, row=4, sticky=(tk.W, tk.E)) rapport_statique.grid(column=1, row=5, sticky=tk.W) rapport_dynamique.grid(column=2, row=5, sticky=(tk.W, tk.E)) bouton.grid(column=2, row=6, sticky=tk.W) # ajoute une gouttière entre les éléments for enfant in cadre.winfo_children(): enfant.grid_configure(padx=5, pady=5) # Emplacement initial du curseur z1_entry.focus() # effet de la touche [entrée] fenetre.bind("<Return>", calcule) # ************************* # ************************* # ** Programme principal ** # ************************* # ************************* configureFenetre() # Affichage et activation de la fenêtre fenetre.mainloop() </syntaxhighlight> {{boîte déroulante fin}} {{voir |{{lien web |url=https://docs.python.org/3/library/tkinter.ttk.html |titre=tkinter.ttk — Tk themed widgets |site=docs.python.org |consulté le=2026-06-11}} }} {{voir |{{lien web |url=https://matplotlib.org/stable/gallery/user_interfaces/embedding_in_tk_sgskip.html |titre=How to embed Matplotlib charts in Tkinter GUI? |site=Matplotlib.org |date=2025-07-15 |consulté le=2026-06-11}} }} === Avec PyQt === Le module PyQt (prononcer \ˈpaɪ.kjut\) permet d'utiliser la bibliothèque Qt dévelopée par Riverbank Computing. Il permet notamment de créer des interfaces graphiques. La communication entre objets Qt se fait par une mécanismes de « signal/emplacement » ''({{lang|en|signal/slot}})''. Un emplacement ''({{lang|en|slot}})'' est une fonction ''({{lang|en|callable}})'' ; un signal est un attribut d'un objet. Si l'attribut signal est défini pour l'emplacement, alors on dit que l'emplacement est relié à un signal. Par exemple, un objet <code>QPushButton</code> dispose du signal <code>clicked</code> qui est émis lorsque l'on clique dessus ; on peut ainsi faire exécuter un emplacement (fonction appelable) <code>action()</code> lorsque l'on clique sur le bouton par le biais du signal <code>clicked</code> : <syntaxhighlight lang="python"> from PyQt5.QtWidgets import QPushButton bouton = QPushButton("Appuies-moi dessus") button.clicked.connect(action()) </syntaxhighlight> {{voir|{{lien web |url=https://www.riverbankcomputing.com/static/Docs/PyQt6/ |titre=Reference guide PyQt6 |site=Riverbank Computing|consulté le=2026-0604}} }} {{...}} == Annotations == Une annotation est un commentaire qui sert à expliciter un type de variable. La syntaxe est différente des commentaires « classiques » : cela permet d'avoir un affichage différent avec les éditeurs de texte ayant une coloration syntaxique, et ces informations peuvent être récupérées par des logiciels extérieurs pour effectuer une documentation automatique ou bien des vérifications de type. Cependant : * comme les commentaires normaux, ils n'ont aucune influence lors de l'exécution du texte ; en particulier : * rien n'oblige à annoter les variables ; * il est possible d'avoir une variable ayant un type différent de son annotation ; le fait de pouvoir définir et changer le type de variable à la volée est une fonctionnalité fondamentale de Python. La syntaxe pour une annotation est : : nom_de_variable + deux-points + espace + type par exemple : <syntaxhighlight lang="python"> a: int </syntaxhighlight> Notez qu'ici, la variable n'est ''pas'' créée. Pour la créer, il faut lui affecter une valeur. Il est possible de l'affecter après ou bien sur la même ligne avec la syntaxe : : nom_de_variable + deux-points + espace + type + espace + égal + espace + valeur par exemple : <syntaxhighlight lang="python"> a: int a = 5 # est équivalent à a: int = 5 </syntaxhighlight> Même si l'annotation n'a pas d'impact sur l'exécution, le type doit être un type existant sinon cela génère une erreur de syntaxe. Les types classiques sont : : <code>int</code> — <code>float</code> — <code>str</code> — <code>bool</code> — <code>list</code> — <code>tuple</code> — <code>dict</code> Il est également possible de mettre une chaîne de caractères : <syntaxhighlight lang="python"> a: "ce que je veux" = 3.1516 </syntaxhighlight> On peut annoter une fonction. Il est possible d'annoter les variables déclarées au sein de la fonction, mais pas les variables globales (puisqu'elle ne sont pas définie au sein de la fonction). On peut aussi annoter : * les variables passées en paramètre, avec la même syntaxe dans les parenthèses ; * annoter le type de la variable de sortie (retournée) en la faisant précéder de <code>-&gt;</code> : <syntaxhighlight lang="python"> def plusCinq(a: float = 0) -> float: return a + 5 </syntaxhighlight> ; Ressources * {{lien web | url = https://www.python.org/dev/peps/pep-0526/ | titre = PEP 526 -- Syntax for Variable Annotations | site = Python.org | consulté le = 2019-04-05 | lang = en }} * {{lien web | url = https://www.python.org/dev/peps/pep-3107/ | titre = PEP 3107 -- Function Annotations | site = Python.org | consulté le = 2019-04-05 | lang = en }} == Décorateur == Un décorateur est une fonction qui s'applique à une fonction, à la manière de la composition mathématique ''g'' ∘ ƒ = ''g''(ƒ). Mais cette composition affecte la fonction elle-même ; l'utilisateur appelle la fonction ƒ mais c'est la fonction ''g'' ∘ ƒ qui s'exécute. Cette fonction ''g'' est appelée le décorateur. L'intérêt est de pouvoir modifier une fonction sans modifier le code de la fonction elle-même. Pour appliquer une décoration, il faut : # Déclarer le décorateur : une fonction qui s'applique à une autre fonction. # Affecter le décorateur à la fonction visée : en mettant <code>@''décoration''</code> juste avant la définition de la fonction. Par exemple : <syntaxhighlight lang="python"> def decorateur(f): print("Avant la fonction") f() print("après la fonction") @decorateur def afficheFoo(): print("Foo.") afficheFoo # Avant la fonction # Foo. # Après la fonction </syntaxhighlight> Lorsque l'on appelle <code>afficheFoo</code>, on appelle en fait <code>decorateur(afficheFoo)</code>. Si la fonction à modifier admet des paramètres, il faut définir une fonction enveloppante dans le décorateur. Par exemple, nous définissons ci-dessous un décorateur <code>deuxFois()</code> qui fait s'exécuter deux fois de suite la fonction : <syntaxhighlight lang="python"> def deuxFois(f): def conteneurFonction(*args, **kwargs): f(*args, **kwargs) f(*args, **kwargs) return conteneurFonction @deuxFois def plusCinq(a: int = 0): print(a + 5) plusCinq(2) # 7 # 7 print(plusCinq.__name__) # conteneurFonction </syntaxhighlight> Nous voyons que l'application du décorateur a modifié le nom de la fonction — pas le nom de la variable qui contient la fonction mais bien son nom « intime ». Pour éviter cela, on utilise la méthode <code>wraps()</code> du module <code>functools</code> : <syntaxhighlight lang="python"> import functools def deuxFois(f): @functools.wraps(f) def conteneurFonction(*args, **kwargs): f(*args, **kwargs) f(*args, **kwargs) return conteneurFonction @deuxFois def plusCinq(a: int = 0): print(a + 5) plusCinq(2) # 7 # 7 print(plusCinq.__name__) # plusCinq </syntaxhighlight> On peut par exemple utiliser un décorateur pour la mémoïsation. La mémoïsation est une méthode consistant à mémoriser les valeurs d'une fonction au fur et à mesure de son utilisation ; ainsi, si l'on veut évaluer la fonction avec les mêmes entrées, on se contente d'aller chercher la valeur enregistrée ce qui est plus rapide. On sacrifie donc la place mémoire au profit de la rapidité. On peut trouver des décorateurs de mémoïsation aux adresses suivantes : * https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize * https://gist.github.com/robcowie/1357800 ; Ressources : {{lien web | url = https://www.python.org/dev/peps/pep-0318/ | titre = PEP 318 -- Decorators for Functions and Methods | site = Python.org | lang = en | consulté le = 2019-04-05 }} == Manipulation de fichiers == === Importer le contenu d'un fichier === Python possède la fonction <code lang="python">open()</code> qui permet d'ouvrir un fichier. Ouvrir signifie qu'il crée un objet de type <code>file</code> qui possède notamment les méthodes <code lang="python">.read()</code> et <code lang="python">.write()</code>. Il peut s'agir d'un objet de type « fichier binaire » ''({{lang|en|binary file}})'' ou « fichier texte » ''({{lang|en|text file}})''. Si par exemple on veut utiliser (et donc lire) le contenu du fichier texte <code>monfichier.txt</code>, on écrit : <syntaxhighlight lang="python"> fichier = open("monfichier.txt", "rt") … fichier.close() </syntaxhighlight> Le paramètre <code>"rt"</code> signifie que nous ouvrons le fichier en lecture ''({{lang|en|read}})'' et qu'il s'agit d'un objet de type fichier texte. Notons deux choses : * en faisant cela, nous ne faisons qu'associer le fichier à un objet Python, nous n'avons pas encore importé les données ; * si nous ouvrons le fichier, il faut le fermer par la suite ; c'est pourquoi nous utilisons la méthode <code lang="python">.close()</code>. Pour éviter d'avoir à fermer le fichier, nous pouvons l'ouvrir au sein d'un contexte : <syntaxhighlight lang="python"> with open("monfichier.txt", "rt") as fichier: … </syntaxhighlight> Notons aussi que la chaîne de caractères indiquant le nom du fichier peut contenir le chemin d'accès au répertoire (dossier), mais sous Microsoft Windows, il faut utiliser des barres de fractions <code>/</code> pour séparer les sous-répertoires au lieu de la barre inversée habituelle, par exemple : <syntaxhighlight lang="python"> chemin = "C:/Temp/monfichier.txt" with open(chemin, "rt") as fichier: … </syntaxhighlight> Pour mettre les données du fichier dans la variable <code>contenu</code>, nous écrivons donc : <syntaxhighlight lang="python"> with open("monfichier.txt", "rt") as fichier: contenu = fichier.read() print(contenu) </syntaxhighlight> et si nous ne voulons lire que les <code>n</code> premiers caractères (<code>n</code> étant un entier), nous utilisons <code lang="python">contenu = fichier.read(n)</code>. Cette lecture est séquentielle, c'est-à-dire que si nous appliquons la méthode plusieurs fois, nous reprenons la lecture là où nous l'avons laissée. Si nous voulons lire une ligne, nous utilisons la méthode <code lang="python">.readline()</code>. La lecture ligne par ligne est également séquentielle. Nous pouvons aussi créer une liste dont chaque élément est une ligne du fichier ; nous utilisons alors la méthode <code lang="python">.readlines()</code> (notez le pluriel). Chaque élément de la liste se termine par le caractère de fin de ligne <code lang="python">\n</code>. Pour l'enlever, nous pouvons utiliser la méthode <code lang="python">.rstrip()</code> pour chaque élément de la liste, par exemple. L'exemple complet est alors : <syntaxhighlight lang="python"> with open("monfichier.txt", "rt") as fichier: contenu = fichier.readlines() contenu = [item.rstrip() for item in contenu] print(contenu) </syntaxhighlight> === Exporter du contenu vers un fichier === Si nous voulons créer un fichier texte <code>monfichier.txt</code> pour y mettre le contenu de la variable <code>texte</code>, alors nous utilisons : <syntaxhighlight lang="python"> with open("monfichier.txt", "wt") as fichier: fichier.write(texte) </syntaxhighlight> Le module principal important pour la manipulation de fichiers est est <code lang="python">os</code>. === Exploiter le contenu d'un fichier texte === Avec un fichier texte, la méthode <code lang="python">.read()</code> crée une variable de type texte. Nous pouvons séparer cette variable en différentes lignes avec la méthode <code lang="python">.splitlines()</code>. Cela crée une liste de chaînes de caractères, chaque chaîne étant une ligne. Si maintenant une ligne contient plusieurs données séparées par un séparateur commun, par exemple un espace, nous pouvons séparer les données par la méthode <code lang="python">.split(''séparateur'')</code>. Cela crée une liste de chaînes de caractères, chaque chaîne étant une donnée. Si par exemple le fichier est du type CSV ''({{lang|en|comma separated values}}'', valeurs séparées par une virgule), l'exploitation du fichier est : <syntaxhighlight lang="python"> with open("monfichier.txt", "rt") as fichier: contenu = fichier.read() contenu = contenu.splitlines() contenu = [item.split(",") for item in contenu] </syntaxhighlight> La variable <code>contenu</code> est une liste de listes. Pour avoir la ''n''<sup>e</sup> valeurs de la ''m''<sup>e</sup> ligne, on utilise : <syntaxhighlight lang="python"> contenu[m-1][n-1] </syntaxhighlight> Si l'on veut extraire la ligne ''m'' il suffit d'écrire : <syntaxhighlight lang="python"> contenu[m-1] </syntaxhighlight> mais si l'on veut la colonne ''n'', le plus simple est d'utiliser une définition en compréhension : <syntaxhighlight lang="python"> [ligne[n-1] for ligne in contenu] </syntaxhighlight> Dans certains fichiers CSV, les séparateurs de valeurs ne sont pas des virgules, on peut donc utiliser un autre caractère pour le séparateur. Concernant les séparateurs particuliers : * si le séparateur est une tabulation, on utilise <code lang="python">\t</code> : <code lang="python">contenu = [item.split("\t") for item in contenu]</code> ; * si le séparateur est un nombre arbitraire d'espaces et/ou de tabulation, on ne définit aucun séparateur : <code lang="python">contenu = [item.split() for item in contenu]</code>. Si la première ligne contient les en-têtes des colonnes, on peut l'enlever avec la fonction <code lang="python">del()</code> : <syntaxhighlight lang="python"> with open("monfichier.txt", "rt") as fichier: contenu = fichier.read() contenu = contenu.splitlines() del(contenu[0]) contenu = [item.split(",") for item in contenu] </syntaxhighlight> Certains logiciels créent des fichiers en utilisant le séparateur décimal régional, qui en France est la virgule. Pour remplacer les virgules par des points, on peut utiliser la méthode <code lang="python">.replace()</code>, de préférence ''avant'' de séparer les valeurs : <syntaxhighlight lang="python"> contenu = contenu.splitlines() contenu = [item.replace(",", ".") for item in contenu] # remplace les virgules par des points contenu = [item.split(";") for item in contenu] # si le séparateur est un point-virgule </syntaxhighlight> en effet, lorsque l'on a séparé les valeurs, on a une liste de liste, il faut alors balayer les sous-listes ce qui prend plus de temps : <syntaxhighlight lang="python"> contenu = contenu.splitlines() contenu = [item.split(";") for item in contenu] # si le séparateur est un point-virgule contenu = [[subitem.replace(",", ".") for subitem in item] for item in contenu] # remplace les virgules par des points </syntaxhighlight> '''Exemple complet''' Supposons que l'on ait un fichier texte de la forme : <syntaxhighlight lang="text"> x y z V 0.0 1.5 3.2 8.657 0.4 1.5 3.2 8.392 0.2 1.5 3.2 8.485 ... </syntaxhighlight> C'est un fichier valeurs V associées à des points de coordonnées ''(x, y, z)'' (un champ V sur l'espace, donc). Nous remarquons que seule la coordonnée ''x'' change : les données concernent la droite (''y'' = 1,5 ; ''z'' = 3,2). Nous remarquons aussi que les valeurs de ''x'' ne sont pas classées par ordre croissant ni décroissant. Nous voulons au final avoir une matrice [[''x''], [V]] triée par ''x'' croissant. Pour cela, nous pouvons faire : <syntaxhighlight lang="python"> with open(nomdefichier, "rt") ad fichier: contenu = fichier.read() contenu = contenu.splitlines() contenu = [item.split(" ") for item in contenu contenu = contenu[1:] # élimine la première ligne x = np.array([float(ligne[0]) for ligne in contenu]) V = np.array([float(ligne[3]) for ligne in contenu]) donnees = np.concatenate((x.reshape(-1, 1), V.reshape(-1, 1)), axis=1) # matrice [[x], [V]] ind = np.argsort(donnees[:, 0]) donnees = donnees[ind, :] # matrice triée plt.plot(donnees[:, 0], donnees[:, 1]) </syntaxhighlight> {{note|Pour le tri, voir [[../Manipulation_de_matrices#Fonctions_et_méthodes_de_base|''Manipulation de matrices'' &gt; ''Fonctions et méthodes de base'']].}} === Cas d'un fichier CSV === Si le fichier CSV ne contient que des valeurs numériques, on peut utiliser : <syntaxhighlight lang="python"> valeurs = np.loadtxt(chemin+nomfic, delimiter=",") # si le séparateur est une virgule </syntaxhighlight> Il existe un module <code lang="python">csv</code> dédié aux fichiers CSV. La manipulation du fichier se fait comme suit : <syntaxhighlight lang="python"> import csv with open(chemin+nomfic, "rt") as fichier: lecteur = csv.reader(fichier, delimiter=",") contenu = [ligne for ligne in lecteur] print(contenu) </syntaxhighlight> === Utilisation de Pandas === Pandas<ref>https://pandas.pydata.org/</ref> est un module gérant les tableaux de données, appelés <em lang="en">data frames</em>. Voici quelques commandes utiles : <syntaxhighlight lang="python"> import numpy as np import pandas as pd M = np.random.rand(10, 10) # crée une matrice NumPy aléatoire de dimension 10 × 10 tableau = pd.DataFrame(M) # transforme la matrice en tableau DataFrame tableau.to_csv("tableau.csv") # enregistre le tableau dans un fichier CSV donnees = pd.read_csv("tableau.csv").to_numpy() # lit le fichier et transforme le tableau DataFrame en matrice NumPy </syntaxhighlight> Si on ne veut pas d'entête lorsque l'on écrit le fichier CSV, on ajoute l'attribut <code>header = False</code> : <syntaxhighlight lang="python"> tableau.to_csv("tableau.csv", header = False) # enregistre le tableau dans un fichier CSV sans entête donnees = pd.read_csv("tableau.csv").to_numpy() # lit le fichier et transforme le tableau DataFrame en matrice NumPy </syntaxhighlight> Par défaut, la fonction <code>pd.read_csv()</code> considère que le séparateur est une virgule, et la commande <code>pd.read_table()</code> que c'est une tabulation. On peut définir le séparateur avec le paramètre <code>sep</code> : <syntaxhighlight lang="python"> donnees = pd.read_csv("tableau.csv", sep=";") </syntaxhighlight> On peut utiliser les séparateurs spéciaux : * <code>\t</code> : tabulation ; * <code>\s+</code> : nombre arbitraire d'espaces. On peut par ailleurs utiliser les paramètres suivants : * <code>dialect</code> : syntaxe du fichier, par exemple <code>dialect = "excel"</code> ; * <code>nrows</code> (entier) : nombre de lignes lues ; * <code>skiprows</code> (entier) : nombre de lignes sautées (non lues) en début de fichier ; * <code>header</code> (entier) : numéro de ligne utilisé pour l'en-tête, par exemple <code>header = 0</code> pour la première ligne ; * <code>skip_blank_lines</code> (booléen) : si la valeur est vraie (<code>True</code>), ne lit pas les lignes vide ; sinon, met une valeur <code>nan</code>. Par exemple : <syntaxhighlight lang="python"> donnees1 = pd.read_csv("tableau.csv", nrows=1, sep="\s+").to_numpy() donnees2 = pd.read_csv("tableau.csv", skiprows=3, sep="\s+").to_numpy() </syntaxhighlight> {{voir|{{lien web |url=https://pandas.pydata.org/docs/user_guide/io.html |titre=IO tools (text, CSV, HDF5, …) |site=Pandas |consulté le=2026-05-06}} }} == Exporter un programme Python == Vous pouvez créer un fichier « Python pur » <code>.py</code>. Pour cela, dans le menu <code>fichier/file</code> de Jupyter, choisir <code>télécharger/download</code> au format <code>.py</code> ; le fichier se trouve alors dans le répertoire de téléchargement du navigateur. == Recommandations == Les recommandations de programmation sont générales et ne sont en grande partie pas spécifiques à Python. {{voir|[[Découvrir_Scilab/Programmation#Recommandations]]}} == Ressources == * {{lien web | url = https://www.python.org/dev/peps/pep-0008/ | titre = PEP 8 -- Style Guide for Python Code | site = Python documentation | consulté le = 2019-03-14 }} == Notes et références == {{références}} ---- [[../Fonctions mathématiques générales|Fonctions mathématiques générales]] &lt; [[../|↑]] &gt; [[../Graphiques|Graphiques]] {{DEFAULTSORT:Elements de programmation}} [[Catégorie:Python pour le calcul scientifique (livre)]] 1mbznnnnbjie46smx42k8n5x0ib2pks Fonctionnement d'un ordinateur/Les unités arithmétiques et logiques entières (simples) 0 80707 768716 767947 2026-06-26T12:26:55Z Mewtow 31375 /* Le bit-slicing */ 768716 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachée de l'époque étaient assez simples et géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Mais il était possible d'assembler plusieurs ALU pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante, qui doit elle accepter celui-ci sur une entrée. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Le 74181 était conçu pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> 7shtcck4dzcnoaq1n0930ksdo0qw69e 768717 768716 2026-06-26T12:27:36Z Mewtow 31375 /* L'unité de calcul 74181 */ 768717 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachée de l'époque étaient assez simples et géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Mais il était possible d'assembler plusieurs ALU pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante, qui doit elle accepter celui-ci sur une entrée. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Le 74181 était conçu pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> 14h0m2fl1nvao0wto5gtdd9j41mk8oq 768718 768717 2026-06-26T12:27:48Z Mewtow 31375 /* L'unité de calcul 74181 */ 768718 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachée de l'époque étaient assez simples et géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Mais il était possible d'assembler plusieurs ALU pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante, qui doit elle accepter celui-ci sur une entrée. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Le 74181 était conçu pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> io999fle2s4cebfj7y32g0i7ks3unyy 768719 768718 2026-06-26T12:30:17Z Mewtow 31375 /* Le bit-slicing */ 768719 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Elle était conçue pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> 8u1j87gkohznm1h43qcsixncin6l78t 768720 768719 2026-06-26T12:30:35Z Mewtow 31375 /* Le bit-slicing */ 768720 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Elle était conçue pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> j9ssoaktr1a8aa5p0a55svxyvx9g800 768721 768720 2026-06-26T12:30:56Z Mewtow 31375 /* L'interface d'une unité de calcul et sa conception */ 768721 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Comme nous l'avons vu dans le chapitre dédié aux circuits de calculs, ajouter une entrée de retenue ne coute rien et est très simple à implémenter en à peine quelques portes logiques. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Elle était conçue pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> csknyhij1tifd1avcn6adg5nchokgji 768722 768721 2026-06-26T12:31:50Z Mewtow 31375 /* Le bit-slicing */ 768722 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Elle était conçue pour le ''bit-slicing'', grâce à son entrée de retenue et sa sortie de retenue. Mais il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> i0zmoz2hte3ogv4m50yxyxfme3omyqh 768723 768722 2026-06-26T12:32:16Z Mewtow 31375 /* Le bit-slicing */ 768723 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Il était possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=2|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=2|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=2|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=2|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> fxtvlfrs46hckqwk807a5zb9xt1tgak 768724 768723 2026-06-26T12:32:54Z Mewtow 31375 /* L'ALU du processeur 8086 d'Intel */ 768724 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Il était possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1.5|Additionneur complet basé sur un MUX]] Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=1.5|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=1.5|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=1.5|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> dpfb441thszb9wxs57r6o3bdrgr4n20 768725 768724 2026-06-26T12:33:29Z Mewtow 31375 /* L'ALU du processeur 8086 d'Intel */ 768725 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Il était possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1.5|Additionneur complet basé sur un MUX]] Le demi-additionneur est composé de deux portes logiques : une porte ET et une porte XOR. Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=1.5|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=1.5|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=1.5|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:TTL chip 24pin.svg|vignette|upright=0.5|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> pgddanjs80wsytah3ramcydsvga60hl 768726 768725 2026-06-26T15:15:21Z Mewtow 31375 /* L'unité de calcul 74181 */ 768726 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu les circuits pour l'addition, la soustraction et les comparaisons. Nous avons aussi vu qu'il est très facile d'implémenter la soustraction en rajoutant quelques portes logiques à un additionneur. Et de même, une fois qu'on sait faire la soustraction, implémenter les comparaisons demande juste d'ajouter quelques portes logiques. Mais il est possible d'aller plus loin ! Dans ce chapitre, nous allons voir un circuit appelé une '''unité de calcul arithmétique et logique''', abrévié ALU (''Arithmetic and Logical Unit''). Comme son nom l'indique, elle effectue des additions, des soustractions, des comparaisons et des opérations bit à bit. La plupart des ALUs ne gèrent pas les multiplications/divisions et vous comprendrez pourquoi dans ce qui suit. Tous les processeurs contiennent au moins une ALU. En fait, créer un processeur demande une unité de calcul, des registres, un circuit de communication avec la mémoire et d'interconnecter le tout. Il faut aussi ajouter des circuits pour commander le tout, qui sont regroupés dans l'unité de contrôle. L'unité de contrôle lit les instructions en mémoire, puis commande l'unité de calcul, les registres et la mémoire pour que l'instruction soit exécutée correctement. L'unité de contrôle est assez complexe et aura droit à plusieurs chapitres dédiés, nous avons déjà vu les registres, il est temps de voir l'unité de calcul. [[File:Microarchitecture d'un processeur.png|centre|vignette|upright=2|Microarchitecture d'un processeur]] ==L'interface d'une unité de calcul et sa conception== L'interface d'une ALU est assez simple. Il y a évidemment les entrées pour les opérandes et la sortie pour le résultat, mais aussi une entrée de commande qui permet de choisir l'instruction à effectuer. Sur cette entrée, on place une suite de bits qui précise l'instruction à effectuer, qui varie d'une ALU à l'autre. La suite de bit peut être vu est aussi appelée l''''''opcode''''', ce qui est un diminution de ''code opération''. L'ALU a aussi une '''entrée de retenue entrante''', sur le même modèle que les additionneurs. Pour rappel, les additionneurs sont conçus avec des additionneurs complets, qui prennent trois bits en entrée : deux bits d'opérande et un bit de retenue. Pour la colonne des bits de poids faible, il y a aussi un additionneur complet qui prend en opérande les deux bits de poids faible, mais aussi une retenue entrante. Les unité de calcul entières contiennent un additionneur entier, ce qui fait qu'elles aussi disposent de cette entrée de retenue. Elles fournissent aussi la retenue en sortie, avec d'autres informations, ce qui nous amène à parler des sorties de l'ALU. En plus de la sortie pour le résultat, l'ALU a des sorties de 1 bit appelées des '''''flags''''', ou indicateurs. Les plus fréquents sont les fameux bits intermédiaires vu dans le chapitre sur les comparaisons : un bit qui est à 1 si un débordement d'entier a eu lieu (la retenue de sortie), un bit qui est à 1 si un débordement d'entier en complètement à deux a eu lieu, un bit qui indique si le résultat est zéro, le bit de signe du résultat en complément à deux. Si c'est le cas, les bits intermédiaires alimentent souvent un circuit qui calcule le résultat d'une comparaison, qui est considéré comme séparé de l'ALU. Mais une ALU peut fournir d'autres ''flags'' en plus de ces 4 bits intermédiaires, voire ne pas fournir les 4 bits précédents, tout dépend de l'ALU. Par exemple, certains processeurs avaient un ''flag'' qui donnait le bit de parité du résultat. Autre exemple, les processeurs avec un support du BCD avaient des ''flags'' dédiés à la gestion du BCD. Le processeur Z80 fournissait les deux ''flags'' des exemples précédents, à savoir un ''flag'' pour le bit de parité du résultat, un autre pour la gestion du BCD, et un autre pour indiquer que le résultat valait zéro. [[File:Interface d'une ALU.jpg|centre|vignette|upright=2|Interface d'une ALU]] ===L'intérieur d'une unité de calcul=== Les unités de calcul les plus simples contiennent un circuit différent pour chaque opération possible. L’entrée de sélection commande des multiplexeurs pour sélectionner le bon circuit. [[File:Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.png|centre|vignette|upright=2.0|Unité de calcul conçue avec des sous-ALU reliées par des multiplexeurs.]] Mais les ALU que nous allons voir fonctionnent autrement. Elles sont construites sur le même modèle que l'additionneur-soustracteur, qui est un circuit configurable. On lui envoie un bit de commande qui décide entre addition ou soustraction, ce bit de commande configure un inverseur commandable et la retenue entrante. Les ALU qui vont suivre disposent de plusieurs circuits semblables à l'inverseur commandable. Ils possèdent une entrée de commande, dont la valeur est déduite par un circuit combinatoire à partir du code opération (généralement un décodeur). [[File:ALU composée de sous-ALU configurables.png|centre|vignette|upright=2.0|ALU composée de sous-ALU configurables.]] ===Le ''bit-slicing''=== Avant l'invention des premiers microprocesseurs, les processeurs étaient fournis en pièces détachées qu'il fallait relier entre elles. Le processeur était composé de plusieurs circuits intégrés, placés sur la même carte mère et connectés ensemble par des fils métalliques. Et l'ALU était un de ces circuits intégrés. Les ALUs en pièces détachées de l'époque géraient des opérandes de 2, 4, 8 bits, rarement 16 bits. Il était possible d'assembler plusieurs ALU de 4/8 bits pour créer des ALU plus grandes. Par exemple, on pouvait combiner plusieurs ALU 4 bits pour créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Par exemple, l'ALU des processeurs AMD Am2900 est une ALU de 16 bits composée de plusieurs sous-ALU de 4 bits. Un autre exemple classique est celui de l'ALU 74181, une ALU de 4 bits, qu'on pouvait combiner pour créer des ALUs de 16 bits ou plus. Cette technique qui consiste à créer des unités de calcul plus grosses à partir d’unités de calcul plus élémentaires s'appelle le '''''bit slicing'''''. Le ''bit slicing'' est utilisé pour des ALU capables de gérer les opérations bit à bit, l'addition, la soustraction, mais guère plus. Il n'y a pas, à ma connaissance, d'ALU en bit-slicing capable d'effectuer une multiplication ou une division. L'implémentation des opérations bit à bit avec une ALU bit-slice est triviale, la seule complication mineure est l'addition. Si on combine deux ALU de 4 bits, la première calcule l'addition des 4 bits de poids faible, la seconde calcule l'addition des 4 bits de poids fort. Mais il faut propager la retenue de l'addition entre les deux ALUs. Pour cela, il y a deux solutions. Avec la première solution, la première ALU doit transmettre un '''bit de retenue''' sortant à l'ALU suivante. Il faut que l'ALU ait une interface compatible : il faut qu'elle ait une entrée de retenue, et une sortie pour la retenue sortante. La retenue passée en entrée est automatiquement prise en compte lors d'une addition par l'ALU. Une autre solution utilisait un circuit d'anticipation de retenue, séparé de l'ALU. Les retenues étaient alors calculées par ce circuit, qui envoyait les retenues calculées sur les entrées de retenue des ALUs. Un exemple classique est celui de l'ALU 74181, mentionnée plus haut. Il était possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. ==Les ALU entières basées sur un additionneur-soustracteur== Pour rappel, un additionneur soustracteur est fait en combinant un additionneur avec un inverseur commandable. L'entrée de retenue et l'entrée de commande de l'inverseur sont partagée, c'est le même bit qui est envoyé sur les deux. Mais dans ce qui suit, on va supposer qu'elles sont découplées, qu'on peut envoyer des bits différents sur les deux. Le circuit est donc celui-ci : [[File:Additionneur soustracteur.png|centre|vignette|upright=2|Additionneur soustracteur]] De plus, nous allons ajouter un circuit commandable de mise à zéro pour la seconde entrée d'opérande. [[File:ALU basée sur un additionneur soustracteur modifié.png|centre|vignette|upright=2|ALU basée sur un additionneur soustracteur modifié]] L'ALU obtenue ainsi supporte 8 opérations distinctes, résumées dans le tableau ci-dessous. Les principales sont l'addition, la soustraction, l'opération NOT, l'incrémentation, le calcul du complément à deux, et l'identité (une entrée est recopiée sur la sortie). {|class="wikitable" |- ! Reset !! Invert !! Retenue entrante !! !! Sortie de l'ALU |- | 0 || 0 || 0 || || A + B |- | 0 || 0 || 1 || || A + B + 1 |- | 0 || 1 || 0 || || A + <math>NOT(B)</math> = A - B - 1 |- | 0 || 1 || 1 || || A - B |- | 1 || 0 || 0 || || B |- | 1 || 0 || 1 || || B + 1 |- | 1 || 1 || 0 || || <math>NOT(B)</math> |- | 1 || 1 || 1 || || <math>NOT(B)</math> + 1 (complément à deux) |} Pour les autres opérations bit à bit, l'idéal est d'ajouter des circuits pour les opérations ET/OU/XOR en parallèle de l'additionneur-soustracteur et d'utiliser un multiplexeur pour choisir quel circuit donne le résultat. Une amélioration relie l'inverseur commandable non seulement à l'additionneur, mais aussi aux portes ET/OU/XOR. Il est aussi possible de faire pareil avec le circuit pour mettre à zéro l'opérande non inversée. Le tout permet d'ajouter quelques opérations logiques gratuitement, juste en changeant le câblage du circuit [[File:Simplified-ALU.svg|centre|vignette|upright=2|ALU simplifiée.]] ==Les ALU qui manipulent les retenues== L'ALU précédente implémente pas les opérations bit à bit en ajoutant des circuits autour de l'additionneur. Cependant, il existe une alternative qui modifie l'additionneur pour qu'il devienne capable de faire des opérations ET/OU/XOR. Pour comprendre comment faire, il faut rappeler qu'un additionneur est composé de deux parties : une couche d'additionneurs complets, et le reste qui s'occupe du calcul ou de la propagation des retenues. Et il se trouve qu'en manipulant les retenues, on peut émuler d'autres opérations à partir de l'addition. Par exemple, nous avons déjà vu que l'opération XOR est une addition dans laquelle les retenues seraient ignorées. En conséquence, on peut émuler un XOR à partir d'une addition, en rajoutant un circuit pour mettre les retenues à 0, simplement composé de portes ET. Le choix de l'opération est le fait d'une entrée de commande : mise à 0 pour un XOR et à 1 pour l'addition. [[File:Circuit qui fait ADD et XOR.png|centre|vignette|upright=2|Circuit qui fait ADD et XOR.]] Mais on peut aller encore plus loin... ===Un additionneur complet est une petite ALU de 1 bit=== Mine de rien, un additionneur complet seul est capable d'exécuter de nombreuses opérations bit à bit, ce qui permet d'implémenter une unité de calcul logique avec des additionneurs complets. Pour rappel, une unité de calcul logique ne gère que les opérations bit à bit, pas l'addition ni la soustraction. Les opérations supportées sont les opérations NOT, OU, ET, XOR, parfois d'autres comme NXOR. Et un additionneur complet gère ces opérations nativement. Pour rappel, un additionneur complet additionne trois bits, en faisant deux XOR : : <math>\text{Somme} = (A \oplus B) \oplus \text{Retenue entrante}</math> : <math>\text{Retenue sortante} = (A \oplus B) . \text{Retenue entrante} + (A . B)</math> Il est alors intéressant de voir ce qui se passe si on force la retenue entrante à 0 ou 1. Si on force la retenue entrante à 0, le tout se simplifie grandement. On rappelle à toute fin utile que <math>X \oplus 0 = X</math>. Les équations précédentes deviennent : : <math>\text{Somme} = (A \oplus B)</math> : <math>\text{Retenue sortante} = A . B</math> A l'opposé, si on force les retenues à 1, les équations deviennent totalement différentes. Sachant que <math>X \oplus 1 = \overline{X}</math>, on obtient : : <math>\text{Somme} = \overline{A \oplus B}</math> : <math>\text{Retenue sortante} = (A \oplus B) + (A . B) = A + B</math> Pour résumer : * Si la retenue d'entrée est à 0, la retenue de sortie est un ET entre les deux bits d'opérandes, le bit de somme en est le XOR. * Si on met la retenue entrante à 1, alors la retenue sortante sera un OU entre les deux bits d'opérandes, le bit de somme en est le NXOR. ===Les ALU à manipulation de retenue=== Pour manipuler des retenues, il faut ajouter un circuit de masquage dans l'additionneur-soustracteur, pour mettre les retenues à 0/1. Le circuit de masquage : soit recopie le bit d'entrée (pour l'addition), soit force les entrées de retenue à 0, soit les force à 1. Le circuit de masquage est composé de portes universelles 1 bit, un circuit qu'on a abordé dans le chapitre sur les opérations bit à bit, avec une porte universelle par retenue. [[File:Additionneur modifiée en ALU entière capable de faire des XOR et NXOR.png|centre|vignette|upright=2|Additionneur modifiée en ALU entière capable de faire des XOR et NXOR]] Pour finaliser le circuit, il faut connecter la sortie soit aux bits de résultat, soit aux entrées de retenue, ce qui demande un simple multiplexeur. [[File:Implémentation d'une ALU entière simple.png|centre|vignette|upright=2|Implémentation d'une ALU entière simple]] ===La manipulation de la retenue dans l'additionneur complet=== L'ALU précédent utilise un multiplexeur en sortie des additionneurs complets, pour implémenter le OU et le ET bit à bit. Mais il existe une alternative qui modifie l'additionneur complet. Pour rappel, il est possible de créer un additionneur complet comme illustré ci-dessous. L'idée est que le bit de somme est égal à l'inverse de la retenue sortante, sauf dans deux cas : celui où les trois bits d'opérande valent 0, celui où ils valent tous 1. L'additionneur complet comprend donc un circuit qui calcule la retenue sortante, et deux circuits pour gérer les deux cas particuliers. Il se trouve que les deux circuits en question sont des portes ET et OU/NOR, qu'on peut donc réutiliser pour faire un ET/OU logique. Les deux portes en fin de chaine déterminent le résultat final en fonction de ce que disent les trois circuits précédents. L'une force le bit de somme à 0, l'autre le force à 1. [[File:Full adder basé sur une modification de la retenue interne, au complet.png|centre|vignette|upright=2|Full adder basé sur une modification de la retenue interne, au complet]] Dans ce qui suit, on suppose que le circuit utilise une porte ET et une porte OU, pour se simplifier la tâche. Ces deux portes prennent trois opérandes : les deux bits d'opérandes et le bit de retenue entrante. En manipulant la retenue entrante, on peut activer ou désactiver ces deux portes. * En mettant la retenue entrante à 0, la porte ET sera désactivée et la porte OU fournira le OU entre les deux bits d'opérande. * En mettant la retenue entrante à 1, la porte OU sortira systématiquement un 1 et n'aura aucun impact sur le bit de somme, la porte ET calculera le ET entre les deux bits d'opérande. Maintenant, cela ne suffit pas pour avoir un ET/OU en sortie de l'additionneur. Pour cela, il faut aussi neutraliser l'effet de la retenue sortante. Pour distinguer la retenue sortante de celle utilisée dans l'additionneur complet, on appellera cette dernière la '''retenue interne'''. Notez bien que cette retenue est l'inverse de la retenue sortante, il y a une porte NON pour l'inverser avant utilisation. Neutraliser l'effet de la retenue interne demande soit de forcer celle-ci à 0, soit de la forcer à 1. Pour cela, on remplace la porte NON par un circuit qui est capable : d'inverser la retenue, de la mettre à 0, de la mettre à 1. Nous avions vu un tel circuit dans le chapitre sur les opérations de masquage, il s'appelle une ''porte universelle 1 bit''. Dans le détail, on retrouve les possibilités classiques : * Si on ne force ni la retenue entrante, ni la retenue sortante, on a une addition. * Si on force la retenue entrante à 0, sans forcer la retenue interne, on a un XOR. * Si on force la retenue entrante à 1, sans forcer la retenue interne, on a un NXOR. Mais à cela, il faut ajouter les cas obtenus en modifiant la retenue interne : * Si on force la retenue entrante à 0 et la retenue interne à 1, on a un OU logique. * Si on force la retenue entrante à 1, et la retenue interne à 0, on a un ET logique. : Le cas où on force les deux retenues à 0 n'a pas d'intérêt : le bit de somme sera mis à zéro. Idem si on met les deux à 1 : le bit de somme sera forcé à 1. Les autres cas n'ont pas d'interprétation évidente. Une ALU de ce type a été utilisée sur les processeurs Intel x86 8008, ainsi que dans les processeurs Z80. L'ALU du processeur Intel x86 8008 est une ALU 8 bits, qui utilise un circuit d'anticipation de retenue, chose assez rare sur les processeurs de l'époque en raison de leur faible budget en transistors. L'implémentation exacte sur le 8008 était légèrement plus complexe, car il utilisait des portes logiques TTL AND-OR-NAND, qui regroupent une porte ET, une porte OU et une porte NAND en une seule. Pour ceux qui veulent en savoir plus, voici quelques liens : * [https://www.righto.com/2017/02/reverse-engineering-surprisingly.html Reverse-engineering the surprisingly advanced ALU of the 8008 microprocessor] * [https://www.righto.com/2013/09/the-z-80-has-4-bit-alu-heres-how-it.html The Z-80 has a 4-bit ALU. Here's how it works.] ==Les ALU basées sur des portes logiques universelles== Les ALU que nous allons voir dans cette section sont des additionneurs à propagation de retenue, dans lesquels les additionneurs complets sont remplacés par des unité de calcul de 1 bits, plus complexes que prévues. Les unités de calcul en question peuvent manipuler la retenue sortante, pour la mettre à 1 ou 0, comme indiqué plus haut. Cependant, ce n'est pas de cette manière que sont implémentées les opérations logiques. A la place, elles sont implémentées en utilisant des '''portes logiques universelles'''. ===Les portes logiques universelles à deux entrées=== Dans cette section, nous allons voir comment créer un circuit capable d'effectuer plusieurs opérations logiques, le choix de l'opération étant le fait d'une entrée de commande. Par exemple, imaginons un circuit capable de faire à la fois un ET, un OU, un XOR et un NXOR. Le circuit contiendra une entrée de commande de 2 bits, et la valeur sur cette entrée permet de sélectionner quelle opération faire : 00 pour un ET, 01 pour un OU, 11 pour un XOR, 01 pour le NXOR. Nous allons créer un tel circuit, sauf qu'il est capable de faire toutes les opérations entre deux bits et regroupe donc les 16 portes logiques existantes. Sachez qu'avec un simple multiplexeur, on peut créer un circuit qui effectue toutes les opérations bit à bit possible avec deux bits. Et cela a déjà été utilisé sur de vrais ordinateurs. Pour deux bits, divers théorèmes de l’algèbre de Boole nous disent que ces opérations sont au nombre de 16, ce qui inclus les traditionnels ET, OU, XOR, NAND, NOR et NXOR. Voici la liste complète de ces opérations, avec leur table de vérité ci-dessous (le nom des opérations n'est pas indiqué) : * Les opérateurs nommés 0 et 1, qui renvoient systématiquement 0 ou 1 quel que soit l'entrée ; * L'opérateur OUI qui recopie l'entrée a ou b, et l'opérateur NON qui l'inverse : <math>a</math>, <math>b</math>, <math>\overline{a}</math>, <math>\overline{b}</math> ; * L’opérateur ET, avec éventuellement une négation des opérandes : <math>a . b</math>, <math>\overline{a} . b</math>, <math>a . \overline{b}</math>, <math>\overline{a . b}</math> ; * La même chose avec l’opérateur OU : <math>a + b</math>, <math>\overline{a} + b</math>, <math>a + \overline{b}</math>, <math>\overline{a + b}</math> ; * Et enfin les opérateurs XOR et NXOR : <math>a \oplus b</math>, <math>\overline{a \oplus b}</math>. {|class="wikitable" |- !a !b ! !<math>0</math> !<math>a . b</math> !<math>a . \overline{b}</math> !<math>a</math> !<math>\overline{a} . b</math> !<math>b</math> !<math>a \oplus b</math> !<math>a + b</math> !<math>\overline{a . b}</math> !<math>\overline{a \oplus b}</math> !<math>\overline{b}</math> !<math>a + \overline{b}</math> !<math>\overline{a}</math> !<math>\overline{a} + b</math> !<math>\overline{a + b}</math> !<math>1</math> |- |0 || 0 || - ||0 || 0 ||0 ||0 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||1 ||1 ||1 ||1 |- |0 ||1 || - ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 ||0 ||0 ||0 ||0 ||1 ||1 ||1 ||1 |- |1 ||0 || - ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 ||0 ||0 ||1 ||1 |1 |- |1 ||1 || - ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 ||0 ||1 |} Le circuit à concevoir prend deux bits, que nous noterons a et b, et fournit sur sa sortie : soit a ET b, soit a OU b, soit a XOR b, etc. Pour sélectionner l'opération, une entrée du circuit indique quelle est l'opération à effectuer, chaque opération étant codée par un nombre. On pourrait penser que concevoir ce circuit serait assez complexe, mais il n'en est rien grâce à une astuce particulièrement intelligente. Regardez le tableau ci-dessus : vous voyez que chaque colonne forme une suite de bits, qui peut être interprétée comme un nombre. Il suffit d'attribuer ce nombre à l'opération de la colonne ! En faisant ainsi, le nombre attribué à chaque opération contient tous les résultats de celle-ci. Il suffit de sélectionner le bon bit parmi ce nombre pour obtenir le résultat. Et on peut faire cela avec un simple multiplexeur, comme indiqué dans le schéma ci-dessous ! [[File:Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|Unité de calcul bit à bit de 2 bits, capable d'effectuer toute opération bit à bit.]] Il faut noter que le raisonnement peut se généraliser avec 3, 4, 5 bits, voire plus ! Par exemple, il est possible d'implémenter toutes les opérations bit à bit possibles entre trois bits en utilisant un multiplexeur 8 vers 3. Maintenant que nous sommes armés des portes logiques universelles, nous pouvons implémenter un circuit généraliste, qui peut effectuer la même opération logique sur tous les bits. Ce circuit est appelé une '''unité de calcul logique'''. Elle prend en entrée deux opérandes, ainsi qu'une entrée de commande sur laquelle on précise quelle opération il faut faire. Elle est simplement composée d'autant de portes universelles 2 bits qu'il n'y a de bits dans les deux opérandes. Par exemple, si on veut un circuit qui manipule des opérandes 8 bits, il faut prendre 8 portes universelles deux bits. Toutes les entrées de commande des portes sont reliées à la même entrée de commande. [[File:Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit.png|centre|vignette|upright=2|Unité de calcul bit à bit de 4 bits, capable d'effectuer toute opération bit à bit]] ===L'ALU du processeur 8086 d'Intel=== Voyons maintenant l'ALU du processeur 8086 d'Intel, un des tout premier de la marque. Elle est basée sur un additionneur complet qui calcule la retenue sortante avec un multiplexeur 2 vers 1, illustré ci-dessous. [[File:Additionneur complet basé sur un MUX.png|centre|vignette|upright=1.5|Additionneur complet basé sur un MUX]] Le demi-additionneur est composé de deux portes logiques : une porte ET et une porte XOR. Sur le 8086, la porte XOR et la porte ET sont remplacées par une porte logique universelle commandable 2 bit, à savoir un circuit qui peut remplacer toutes les portes logiques 2 bit existantes. Pour configurer les deux portes, l'ALU contient un petit circuit combinatoire qui traduit l'''opcode'' en signaux envoyés aux portes universelles. [[File:ALU du 8086 (bloc de 1 bit).png|centre|vignette|upright=1.5|ALU du 8086 (bloc de 1 bit)]] Pour l'addition et la soustraction, les deux portes sont configurées pour reformer sur un additionneur complet. Pour les opérations bit à bit, la porte qui remplace le XOR est alors configurée pour donner la porte voulue : soit un ET, soit un OU, soit un XOR, soit.... En parallèle, l'autre porte logique a un 0 sur sa sortie, afin de mettre les retenues à 0. [[File:ALU du 8086 lors d'une opération logique.png|centre|vignette|upright=1.5|ALU du 8086 lors d'une opération logique]] L'ALU du 8086 supporte aussi les décalages d'un rang vers la gauche, qui sont équivalents à une multiplication par deux. L'opérande à décaler est envoyé sur les entrées A de chaque additionneur complet. Les deux portes logiques universelles sont alors configurées comme suit : la porte de propagation se comporte comme une porte FALSE, l'autre comme une porte OUI qui recopie l'entrée A. [[File:ALU du 8086 lors d'un décalage à gauche d'un rang.png|centre|vignette|upright=1.5|ALU du 8086 lors d'un décalage à gauche d'un rang]] Pour ceux qui veulent en savoir plus sur les circuits de calcul de l'Intel 8086, voici un lien : * [https://www.righto.com/2020/08/reverse-engineering-8086s.html Reverse-engineering the 8086's Arithmetic/Logic Unit from die photos] ===L'unité de calcul 74181=== [[File:SN74S181N.JPG|vignette|upright=1.0|Circuit imprimé d'une 74181.]] L''''unité de calcul 74181''' est très souvent présentée dans les cours d'architecture des ordinateurs, pour son aspect pédagogique indéniable. Elle a été commercialisée dans les années 60, à une époque où processeurs étaient vendus en kit, en pièces détachées. Les pièces détachées en question étaient des boitiers qui contenaient des registres, l'unité de calcul, des compteurs, des PLA, qu'on assemblait sur une carte électronique pour faire le processeur. Le 74181 était une ALU de 4 bits, ce qui veut dire qu'elle prenait en entrée deux opérandes entiers de 4 bits et fournissait un résultat de 4 bits. Il était possible de faire du ''bit-slicing'', à savoir de combiner plusieurs 74181 afin de créer une unité de calcul 8 bits, 12 bits, 16 bits, etc. Le 74181 était spécifiquement conçu pour, car il gérait un bit de retenue en entrée et fournissait une sortie pour la retenue du résultat. Il était aussi possible de combiner plusieurs 74181 avec une unité d'anticipation de retenue séparée, l'unité 74182, spécialement conçue pour travailler avec des 74181. Elle prenait en entrées 4 signaux P et G pour la propagation et la génération de retenue, et fournissait en sortie 4 retenues. Cela permettait de combiner jusqu'à 4 ALUs 74181. Le 74181 fonctionne concrètement comme un additionneur-soustracteur, où les inverseurs commandables sont remplacés par une porte universelle 2 bits. En conséquence, le 74181 peut combiner l'addition et les 16 opérations bit à bit (donc toutes les opérations de ce type possibles entre deux bits). De plus, il y a un MUX en sortie de l'ALU qui choisit la sortie parmi : la sortie des portes universelles 2 bits, la sortie de l'additionneur. L'ALU 74181 peut fonctionner selon deux modes. Dans le premier mode, il effectue une opération bit à bit seule. Dans le second mode, il effectue une opération bit à bit et une addition. En clair, il effectue une opération bit à bit et une addition facultative. En tout, le 74181 était capable de réaliser 32 opérations différentes : les 16 opérations bit à bit seules, et 16 autres opérations obtenues en combinant une opération bit à bit avec une addition. L'entrée de sélection de l'instruction fait 5 bits : un groupe de 4 bits précise l'opération bit à bit, et un '''bit M''' qui indique s'il faut faire l'addition ou non. Dans le groupe de 4 bits, les bits sont notés s0, s1, s2 et s3. [[File:Schéma fonctionnel du 74181.png|centre|vignette|upright=2|Schéma fonctionnel du 74181.]] Le 74181 comprend 75 portes logiques, mais ce nombre est à relativiser car l’implémentation utilisait des optimisations qui fusionnaient plusieurs portes entre elles. Elle utilisait notamment des portes AND-OR-NOT, identique à une porte ET suivie d'une porte NOR. Autre optimisation : l'additionneur est fusionné avec les portes logiques universelles. L'idée part d'un additionneur PG, qui génère deux signaux de propagation et de génération de retenue. Le 8086 remplace les portes qui calculent ces signaux par des portes universelles 2 bits. Le 74181 n'utilise qu'une seule porte logique universelle, très modifiée. En clair, il est composé d'ALU 1 bit reliées à un circuit d’anticipation de retenue. La table de vérité de vérité des ALU 1 bit est la suivante. On part du principe que le circuit a deux entrées A et B, et calcule A + f(A,B), avec f(A,B) une opération bit à bit. {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || f(0,0) || 0 |- | 0 || 1 || || 0+f(0,1) || || f(0,1) || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || f(1,0) |- | 1 || 1 || || 1+f(1,1) || || 1 || f(1,1) |} Sur le 74181, il faut imaginer que le circuit qui calcule f(A,B) est une porte universelle commandable 2 bits, réalisée avec un multiplexeur. Les bits du résultat sont envoyés sur les 4 entrées du multiplexeur, et le multiplexeur choisit le bon bit à partir des entrées A et B (qui sont envoyés sur son entrée de commande. Les 4 entrées du multiplexeur sont notées S0, S1, S2 et S3. On a alors : {|class="wikitable" |- ! A || B || || A PLUS f(a,b) || || P || G |- | 0 || 0 || || 0+f(0,0) || || S1 || 0 |- | 0 || 1 || || 0+f(0,1) || || S0 || 0 |- | 1 || 0 || || 1+f(1,0) || || 1 || S2 |- | 1 || 1 || || 1+f(1,1) || || 1 || S3 |} Le circuit pour faire cela est le suivant : [[File:Circuit de base du 74181, avant l'additionneur.jpg|centre|vignette|upright=2|Circuit de base du 74181, avant l'additionneur]] Le schéma du circuit est reproduit ci-dessous. Un œil entrainé peut voir du premier coup d’œil que l'additionneur utilisé est un additionneur à anticipation de retenue modifié. La première couche dans le schéma ci-dessous correspond au circuit qui calcule les signaux P et G. La seconde couche est composée du reste de l'additionneur, à savoir du circuit qui combine les signaux de propagation et de génération des retenues finales. [[File:74181aluschematic.png|centre|vignette|upright=2|Schéma des portes logique de l'ALU 74181.]] Pour ceux qui veulent en savoir plus sur cette unité de calcul et n'ont pas peur de lire une analyse des transistors TTL de la puce, voici deux articles très intéressant sur cette ALU : * [https://www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html Inside the vintage 74181 ALU chip: how it works and why it's so strange ] * [https://www.righto.com/2017/01/die-photos-and-reverse-engineering.html Inside the 74181 ALU chip: die photos and reverse engineering] ==Les ALU sérielles== Les '''ALU sérielles''' effectuent leurs calculs 1 bit à la fois, bit par bit. Le circuit est alors très simple : il contient un circuit de calcul très simple, de 1 bit, couplé à trois registres à décalage : un par opérande, un pour le résultat. Le circuit de calcul prend trois bits en entrées et fournit un résultat d'un bit en sortie, avec éventuellement une retenue en sortie. Une bascule est ajoutée au circuit, pour propager les retenues des additions/soustractions, elle ne sert pas pour les opérations bit à bit. L'ALU sérielle est facile à concevoir à partir de sa table de vérité, aussi je ne va pas détailler sa conception, je laisse le tout en exercice au lecteur. Mais un moyen de la concevoir facilement est simplement d'utiliser un additionneur complet avec de quoi mettre la retenue à 0/1, idem pour une des deux entrées d'opérande. [[File:ALU sérielle.jpg|centre|vignette|upright=2|ALU sérielle]] Les ALU sérielles ne payent pas de mine, mais elles étaient très utilisées autrefois, sur les tout premiers processeurs. Les ordinateurs antérieurs aux années 50 utilisaient des ALU de ce genre. L'avantage de ces ALU est qu'elles peuvent gérer des opérandes de grande taille, avec plus d'une trentaine de bits, sans trop de problèmes. Il suffit de prévoir des registres à décalage suffisamment longs, ce qui est tout sauf un problème. Par contre, elles sont assez lentes pour faire leur calcul, vu que les calculs se font bit par bit. Elles sont d'autant plus lentes que les opérandes sont longs. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de comparaison | prevText=Les circuits de comparaison | next=Les circuits pour l'addition multiopérande | nextText=Les circuits pour l'addition multiopérande }} </noinclude> m0utgwukiya4x3pqd1j7nsevqlij47w Dictionnaire de philosophie/Ubuntu 0 83068 768754 753984 2026-06-27T05:31:56Z PandaMystique 119061 Bot : ajout du paramètre lecture=oui au modèle {{DicoPhilo}} 768754 wikitext text/x-wiki {{DicoPhilo|Ubuntu|lecture=oui}} Ubuntu désigne une philosophie morale et sociale africaine, issue principalement des cultures bantoues d'Afrique australe, qui met au centre de sa conception de l'existence humaine l'interdépendance, la communauté et la dignité partagée. Le terme, qui signifie littéralement « humanité » en langues nguni (zoulou, xhosa, ndébélé), s'est imposé dans le débat philosophique contemporain comme une alternative aux conceptions individualistes dominantes dans la pensée occidentale<ref>Metz, Thaddeus. « Ubuntu as a Moral Theory and Human Rights in South Africa », ''African Human Rights Law Journal'', vol. 11, n° 2, 2011, p. 532-559</ref><ref>Ramose, Mogobe B. ''African Philosophy Through Ubuntu'', Harare, Mond Books, 1999, p. 49-66</ref>. ==Origines et formulations== La philosophie ubuntu trouve ses racines dans les sociétés précoloniales d'Afrique subsaharienne, où elle structurait les relations sociales sans avoir été nécessairement codifiée par écrit. Des concepts similaires existent sous diverses appellations : ''botho'' en sotho, ''hunhu'' en shona, ''utu'' en swahili<ref>임biti, John S. ''African Religions and Philosophy'', Oxford, Heinemann, 1969, p. 106-113</ref>. Ces notions témoignent d'une conception ontologique commune selon laquelle la personne humaine ne peut se réaliser qu'au sein de la communauté. Le philosophe kényan John Mbiti a popularisé la formule « Je suis parce que nous sommes ; et puisque nous sommes, donc je suis »<ref>Mbiti, John S. ''African Religions and Philosophy'', op. cit., p. 106</ref>, qui synthétise cette vision relationnelle de l'existence. En langues nguni, le proverbe ''umuntu ngumuntu ngabantu'' — « une personne est une personne par d'autres personnes » — exprime la même idée<ref>Tutu, Desmond. ''No Future Without Forgiveness'', New York, Doubleday, 1999, p. 31</ref>. L'archevêque Desmond Tutu, figure majeure de la lutte contre l'apartheid, a contribué à diffuser ubuntu sur la scène internationale. Pour lui, ubuntu désigne « l'essence de ce qu'est être humain », affirmant que « ma propre humanité est inextricablement liée à la vôtre »<ref>Tutu, Desmond. ''No Future Without Forgiveness'', op. cit., p. 34-35</ref>. Nelson Mandela a également mobilisé cette notion dans sa pratique politique, notamment lors de la mise en place de la Commission Vérité et Réconciliation en Afrique du Sud post-apartheid<ref>Mandela, Nelson. ''Long Walk to Freedom'', Boston, Little Brown, 1994, p. 227</ref>. ==Dimensions philosophiques== ===Conception de la personne=== Ubuntu propose une théorie de la personne (''personhood'') qui s'écarte des conceptions cartésiennes et libérales. Alors que Descartes fonde l'identité sur la pensée individuelle (« je pense, donc je suis »), ubuntu affirme : « Je suis parce que nous sommes »<ref>Shutte, Augustine. ''Philosophy for Africa'', Rondebosch, UCT Press, 1993, p. 46-50</ref>. La personne ne préexiste pas à ses relations ; elle se constitue à travers elles. Cette conception relationnelle a suscité des débats intenses parmi les philosophes africains. Ifeanyi Menkiti défend une position que l'on peut qualifier de « communautarienne forte », selon laquelle la personnalité (''personhood'') s'acquiert progressivement par l'incorporation aux normes communautaires<ref>Menkiti, Ifeanyi A. « Person and Community in African Traditional Thought », dans Richard A. Wright (dir.), ''African Philosophy: An Introduction'', Lanham, University Press of America, 1984, p. 171-181</ref>. À l'opposé, Kwame Gyekye défend un « communautarisme modéré » qui reconnaît une autonomie individuelle irréductible<ref>Gyekye, Kwame. ''Tradition and Modernity: Philosophical Reflections on the African Experience'', Oxford, Oxford University Press, 1997, p. 35-76</ref>. Le philosophe sud-africain Thaddeus Metz a proposé une interprétation systématique d'ubuntu comme théorie morale. Selon lui, une action est moralement bonne dans la mesure où elle favorise des relations d'identification mutuelle et de solidarité entre les personnes<ref>Metz, Thaddeus. « Toward an African Moral Theory », ''The Journal of Political Philosophy'', vol. 15, n° 3, 2007, p. 321-341</ref>. Cette formulation cherche à éviter les écueils d'un collectivisme qui nierait les droits individuels tout en préservant la dimension essentiellement relationnelle d'ubuntu. ===Harmonie et solidarité=== Ubuntu valorise l'harmonie sociale (''social harmony'') comme bien suprême. Tutu affirme : « L'harmonie, l'amitié, la communauté sont de grands biens. L'harmonie sociale est pour nous le ''summum bonum'' — le bien suprême »<ref>Tutu, Desmond. ''No Future Without Forgiveness'', op. cit., p. 35</ref>. Cela ne signifie pas l'absence de conflits, mais la recherche permanente de leur résolution par le dialogue et la réconciliation plutôt que par la coercition ou l'exclusion. La solidarité constitue l'autre pilier d'ubuntu. Elle se manifeste dans des pratiques telles que le ''letsema'' (entraide agricole collective) chez les peuples sotho-tswana, ou l'hospitalité inconditionnelle envers l'étranger, largement attestée dans les sociétés africaines précoloniales<ref>Metz, Thaddeus et Joseph B.R. Gaie. « The African Ethic of Ubuntu/Botho: Implications for Research on Morality », ''Journal of Moral Education'', vol. 39, n° 3, 2010, p. 273-290</ref>. ==Critiques et limites== Si ubuntu a acquis une légitimité considérable, notamment dans les discours sur la justice transitionnelle et le développement, plusieurs critiques méritent attention. ===Tensions avec les droits individuels=== Certains auteurs soulignent les tensions potentielles entre l'éthique communautaire d'ubuntu et la protection des droits individuels. Dans quelle mesure une philosophie qui valorise la conformité aux normes du groupe peut-elle protéger les dissidents, les minorités ou ceux qui transgressent les conventions sociales ?<ref>Matolino, Bernard. ''Personhood in African Philosophy'', Pietermaritzburg, Cluster Publications, 2014, p. 115-148</ref> Le risque existe que ubuntu légitime des formes d'oppression au nom de l'harmonie communautaire — notamment à l'égard des femmes ou des personnes LGBTQ+<ref>Oyowe, Oritsegbubemi Anthony. « Can a Communitarian Concept of African Personhood Be Both Relational and Gender-Neutral? », ''South African Journal of Philosophy'', vol. 33, n° 1, 2014, p. 85-99</ref>. La question se pose avec acuité dans les débats sur le mariage, la sexualité ou l'héritage. Les tribunaux sud-africains ont dû arbitrer des conflits entre le droit coutumier (souvent justifié par référence à ubuntu) et les droits constitutionnels<ref>Mokgoro, Yvonne. « Ubuntu and the Law in South Africa », ''Potchefstroom Electronic Law Journal'', vol. 1, n° 1, 1998, p. 15-26</ref>. ===Romantisation et instrumentalisation=== Ubuntu fait parfois l'objet d'une romantisation qui en masque les ambiguïtés historiques. Comme l'observe le philosophe nigérian Polycarp Ikuenobe, les sociétés africaines précoloniales n'étaient pas exemptes de hiérarchies, d'inégalités et de violences<ref>Ikuenobe, Polycarp. ''Philosophical Perspectives on Communalism and Morality in African Traditions'', Lanham, Lexington Books, 2006, p. 67-89</ref>. Présenter ubuntu comme une éthique parfaitement égalitaire relève d'une idéalisation qui sert parfois des agendas politiques contemporains. L'invocation d'ubuntu par les élites politiques et économiques africaines soulève aussi des questions. Lorsque des dirigeants corrompus ou autoritaires mobilisent la rhétorique d'ubuntu pour légitimer leur pouvoir, le concept perd sa substance critique. Comme le note Achille Mbembe, les discours sur les « valeurs africaines » ont souvent servi à masquer l'exercice brutal du pouvoir dans l'Afrique postcoloniale<ref>Mbembe, Achille. ''De la postcolonie. Essai sur l'imagination politique dans l'Afrique contemporaine'', Paris, Karthala, 2000, p. 139-167</ref>. ===Universalité et contextualité=== Un débat persiste sur le caractère universel ou spécifiquement africain d'ubuntu. Pour certains, comme Mogobe Ramose, ubuntu exprime une ontologie proprement africaine, irréductible aux catégories occidentales<ref>Ramose, Mogobe B. ''African Philosophy Through Ubuntu'', op. cit., p. 49-66</ref>. D'autres, comme Kwasi Wiredu, considèrent que les valeurs d'ubuntu peuvent être reformulées en termes philosophiques universels<ref>Wiredu, Kwasi. ''Cultural Universals and Particulars: An African Perspective'', Bloomington, Indiana University Press, 1996, p. 157-171</ref>. Cette question n'est pas seulement théorique. Elle engage la possibilité d'un dialogue interculturel authentique et la légitimité d'ubuntu comme ressource pour penser des problèmes globaux — éthique environnementale, intelligence artificielle, justice économique internationale<ref>Metz, Thaddeus. « Ubuntu as a Moral Theory: Reply to Four Critics », ''South African Journal of Philosophy'', vol. 26, n° 4, 2007, p. 369-387</ref>. ==Applications contemporaines== ===Justice transitionnelle=== L'application la plus célèbre d'ubuntu concerne la Commission Vérité et Réconciliation (CVR) sud-africaine (1995-1998). Présidée par Desmond Tutu, cette instance visait à favoriser la réconciliation nationale après l'apartheid en offrant l'amnistie aux auteurs de crimes politiques qui confessaient publiquement leurs actes<ref>Tutu, Desmond. ''No Future Without Forgiveness'', op. cit., p. 54-83</ref>. La CVR s'inspirait explicitement d'ubuntu, privilégiant la restauration des relations sociales sur la punition rétributive. Cette approche a suscité des controverses : certains y ont vu une voie novatrice vers la paix sociale ; d'autres ont dénoncé une forme d'impunité pour les bourreaux et une violence symbolique envers les victimes<ref>Mamdani, Mahmood. « Amnesty or Impunity? A Preliminary Critique of the Report of the Truth and Reconciliation Commission of South Africa », ''Diacritics'', vol. 32, n° 3-4, 2002, p. 33-59</ref>. ===Éthique environnementale=== Certains philosophes africains mobilisent ubuntu pour penser les rapports entre humains et nature. Selon cette lecture, la communauté morale ne se limite pas aux êtres humains mais s'étend à l'ensemble du vivant, voire au cosmos dans son ensemble<ref>Ramose, Mogobe B. « The Philosophy of Ubuntu and Ubuntu as a Philosophy », dans P.H. Coetzee et A.P.J. Roux (dir.), ''Philosophy from Africa'', Le Cap, Oxford University Press, 2002, p. 230-237</ref><ref>Murove, Munyaradzi Felix (dir.). ''African Ethics: An Anthology of Comparative and Applied Ethics'', Pietermaritzburg, University of KwaZulu-Natal Press, 2009, p. 315-331</ref>. Cette extension soulève des questions philosophiques complexes. Si ubuntu repose sur la réciprocité et la reconnaissance mutuelle, peut-on véritablement l'appliquer aux relations avec les animaux ou les écosystèmes, qui ne participent pas au « dialogue » de la même manière que les humains ?<ref>Horsthemke, Kai. « Animals and African Ethics », ''Journal of Animal Ethics'', vol. 5, n° 1, 2015, p. 94-109</ref> ===Développement et économie=== Ubuntu inspire des réflexions sur les modèles de développement économique en Afrique. Face aux échecs des politiques d'ajustement structurel imposées par les institutions financières internationales, certains économistes et philosophes plaident pour un développement fondé sur les valeurs communautaires africaines<ref>Hountondji, Paulin J. (dir.). ''Endogenous Knowledge: Research Trails'', Dakar, CODESRIA, 1997, p. 1-35</ref>. Le concept d'« africapitalisme », promu notamment par l'homme d'affaires nigérian Tony Elumelu, tente de concilier entreprise capitaliste et responsabilité sociale inspirée d'ubuntu. Cependant, cette tentative de réconciliation suscite le scepticisme : peut-on réellement articuler la logique d'accumulation capitaliste avec l'éthique redistributive et communautaire d'ubuntu, ou s'agit-il d'une opération idéologique visant à légitimer l'exploitation néolibérale ?<ref>Crippen, Matthew et Jonathan Schulkin. « Africapitalism, Ubuntu, and Sustainability », ''Journal of Business Ethics'', vol. 175, n° 2, 2021, p. 387-407</ref> ==Perspectives critiques marxistes== D'un point de vue matérialiste, ubuntu pose la question de savoir dans quelle mesure cette philosophie morale reflète les conditions socio-économiques des sociétés africaines précoloniales et comment elle s'articule aux structures économiques actuelles. Les modes de production précoloniaux en Afrique subsaharienne se caractérisaient généralement par l'absence de propriété privée de la terre, la prédominance de l'agriculture de subsistance et des formes collectives d'organisation du travail. Ubuntu pourrait être compris comme l'expression idéologique de ces rapports de production communautaires, où la survie matérielle dépendait effectivement de la coopération et de la solidarité<ref>Rodney, Walter. ''How Europe Underdeveloped Africa'', Londres, Bogle-L'Ouverture Publications, 1972, p. 33-64</ref>. La colonisation et l'intégration subséquente de l'Afrique dans le système capitaliste mondial ont profondément transformé ces structures sociales. L'introduction du travail salarié, de la propriété privée et de l'accumulation marchande a créé de nouvelles formes d'individualisme et de compétition incompatibles avec l'éthique communautaire traditionnelle<ref>Amin, Samir. ''Le développement inégal. Essai sur les formations sociales du capitalisme périphérique'', Paris, Minuit, 1973, p. 21-49</ref>. Dans ce contexte, l'invocation d'ubuntu par les élites postcoloniales peut être analysée comme une forme de « fausse conscience » au sens marxiste : une idéologie qui masque les contradictions réelles entre un discours communautaire et des pratiques économiques fondamentalement extractives et inégalitaires. Lorsque des États africains néolibéraux célèbrent ubuntu tout en menant des politiques d'austérité et de privatisation, il y a là une contradiction manifeste qui révèle le caractère mystificateur du discours<ref>Mamdani, Mahmood. ''Citoyen et sujet. L'Afrique contemporaine et l'héritage du colonialisme tardif'', Paris, Karthala, 2004, p. 286-317</ref>. Cependant, ubuntu conserve aussi un potentiel critique et émancipateur. En tant qu'éthique de la solidarité et de la dignité partagée, elle peut servir de base philosophique pour critiquer les rapports de domination capitalistes et néocoloniaux. Plusieurs mouvements sociaux africains contemporains mobilisent ubuntu pour légitimer des luttes pour la justice sociale, l'accès aux ressources et la démocratie participative<ref>Mamdani, Mahmood. « Ubuntu in South Africa and Beyond: The Challenge of Political Relevance », dans James Ogude (dir.), ''Ubuntu and Personhood'', Trenton, Africa World Press, 2018, p. 95-112</ref>. La question centrale reste celle de la matérialisation institutionnelle d'ubuntu. Comment traduire cette éthique relationnelle dans des structures économiques et politiques concrètes ? Une véritable praxis d'ubuntu exigerait sans doute une transformation des rapports de production — vers des formes de propriété collective, de démocratie économique et de redistribution égalitaire — qui remettrait en cause les fondements du capitalisme néolibéral actuellement dominant en Afrique et ailleurs. == Notes et références == {{references}} ==Bibliographie== * Crippen, Matthew et Jonathan Schulkin. « Africapitalism, Ubuntu, and Sustainability », ''Journal of Business Ethics'', vol. 175, n° 2, 2021, p. 387-407 * Gyekye, Kwame. ''Tradition and Modernity: Philosophical Reflections on the African Experience'', Oxford, Oxford University Press, 1997 * Hountondji, Paulin J. (dir.). ''Endogenous Knowledge: Research Trails'', Dakar, CODESRIA, 1997 * Ikuenobe, Polycarp. ''Philosophical Perspectives on Communalism and Morality in African Traditions'', Lanham, Lexington Books, 2006 * Mamdani, Mahmood. ''Citoyen et sujet. L'Afrique contemporaine et l'héritage du colonialisme tardif'', Paris, Karthala, 2004 * Mamdani, Mahmood. « Amnesty or Impunity? A Preliminary Critique of the Report of the Truth and Reconciliation Commission of South Africa », ''Diacritics'', vol. 32, n° 3-4, 2002, p. 33-59 * Mandela, Nelson. ''Long Walk to Freedom'', Boston, Little Brown, 1994 * Matolino, Bernard. ''Personhood in African Philosophy'', Pietermaritzburg, Cluster Publications, 2014 * Mbembe, Achille. ''De la postcolonie. Essai sur l'imagination politique dans l'Afrique contemporaine'', Paris, Karthala, 2000 * Mbiti, John S. ''African Religions and Philosophy'', Oxford, Heinemann, 1969 * Menkiti, Ifeanyi A. « Person and Community in African Traditional Thought », dans Richard A. Wright (dir.), ''African Philosophy: An Introduction'', Lanham, University Press of America, 1984, p. 171-181 * Metz, Thaddeus. « Toward an African Moral Theory », ''The Journal of Political Philosophy'', vol. 15, n° 3, 2007, p. 321-341 * Metz, Thaddeus. « Ubuntu as a Moral Theory: Reply to Four Critics », ''South African Journal of Philosophy'', vol. 26, n° 4, 2007, p. 369-387 * Metz, Thaddeus. « Ubuntu as a Moral Theory and Human Rights in South Africa », ''African Human Rights Law Journal'', vol. 11, n° 2, 2011, p. 532-559 * Metz, Thaddeus et Joseph B.R. Gaie. « The African Ethic of Ubuntu/Botho: Implications for Research on Morality », ''Journal of Moral Education'', vol. 39, n° 3, 2010, p. 273-290 * Mokgoro, Yvonne. « Ubuntu and the Law in South Africa », ''Potchefstroom Electronic Law Journal'', vol. 1, n° 1, 1998, p. 15-26 * Murove, Munyaradzi Felix (dir.). ''African Ethics: An Anthology of Comparative and Applied Ethics'', Pietermaritzburg, University of KwaZulu-Natal Press, 2009 * Oyowe, Oritsegbubemi Anthony. « Can a Communitarian Concept of African Personhood Be Both Relational and Gender-Neutral? », ''South African Journal of Philosophy'', vol. 33, n° 1, 2014, p. 85-99 * Ramose, Mogobe B. ''African Philosophy Through Ubuntu'', Harare, Mond Books, 1999 * Ramose, Mogobe B. « The Philosophy of Ubuntu and Ubuntu as a Philosophy », dans P.H. Coetzee et A.P.J. Roux (dir.), ''Philosophy from Africa'', Le Cap, Oxford University Press, 2002, p. 230-237 * Rodney, Walter. ''How Europe Underdeveloped Africa'', Londres, Bogle-L'Ouverture Publications, 1972 * Shutte, Augustine. ''Philosophy for Africa'', Rondebosch, UCT Press, 1993 * Tutu, Desmond. ''No Future Without Forgiveness'', New York, Doubleday, 1999 * Wiredu, Kwasi. ''Cultural Universals and Particulars: An African Perspective'', Bloomington, Indiana University Press, 1996 ==Voir aussi== * [[Philosophie africaine]] * [[Communautarisme]] * [[Éthique des vertus]] * [[Justice restaurative]] ==Liens externes== * [https://plato.stanford.edu/entries/african-ethics/ African Ethics] sur Stanford Encyclopedia of Philosophy * [https://iep.utm.edu/hunhu-ubuntu-southern-african-thought/ Ubuntu] sur Internet Encyclopedia of Philosophy {{Autocat}} ola5s2u9f3v42w8pil3cyup8k4165fz Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La Morale en tant que manifestation contre nature 0 83423 768756 767419 2026-06-27T06:26:08Z PandaMystique 119061 768756 wikitext text/x-wiki {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" | | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"| |} === Introduction : contexte et enjeux === Cinquième des dix chapitres du ''[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles|Crépuscule des idoles]]'', le chapitre {{lang|de|« Moral als Widernatur »}} est traditionnellement rendu en français par « La morale en tant que manifestation contre nature », titre de la traduction d'Henri Albert ; on peut aussi le traduire, plus littéralement, « La morale comme contre-nature ». Il compte parmi les attaques les plus vigoureuses de Nietzsche contre la morale chrétienne. Composé de six aphorismes qui déploient une critique à la fois physiologique et psychologique, il porte le projet central des derniers écrits : la transmutation de toutes les valeurs ({{lang|de|Umwerthung aller Werthe}}). Dans l'économie du livre, il fait suite à [[Philosophie/Nietzsche/Crépuscule des idoles/Comment, pour finir, le « monde vrai » devint fable|« Comment le "monde vrai" devint fable »]] et précède [[Philosophie/Nietzsche/Crépuscule des idoles/Les quatre grandes erreurs|« Les quatre grandes erreurs »]]. {{wikisource|Le Crépuscule des Idoles/La Morale en tant que manifestation contre nature}} Plutôt qu'une critique logique ou strictement morale, Nietzsche y met en œuvre une méthode généalogique. Il ne demande pas si la morale chrétienne est vraie ou fausse, mais de quel type de vie elle est l'expression. Cette interrogation physiologique déplace le débat : Nietzsche n'évalue plus la morale comme vraie ou fausse, mais selon qu'elle sert ou contrarie les intérêts de la vie. Ce critère mobilise lui-même une norme, celle de la vie ascendante, et engage Nietzsche dans une difficulté que le chapitre travaille en sous-main et sur laquelle on reviendra. Le commentaire qui suit épouse l'ordre des six aphorismes du chapitre. Ses intitulés restent thématiques et ne se superposent pas terme à terme au texte : le troisième aphorisme, le plus riche, demande d'être abordé en deux temps, les triomphes de la spiritualisation d'abord, la mise en cause de la « paix de l'âme » ensuite. === Section 1. Passions : entre destruction et spiritualisation === ==== Le dilemme de la passion ==== Le premier aphorisme pose une distinction entre deux rapports aux passions. Nietzsche reconnaît que « toutes les passions ont un temps où elles ne sont que néfastes, où elles avilissent leurs victimes avec la lourdeur de la bêtise ». Mais il existe « une époque tardive, beaucoup plus tardive où elles se marient à l'esprit, où elles se "spiritualisent" ». La passion n'est donc pas mauvaise en elle-même ; elle possède une double temporalité. À l'état brut, elle peut nuire. Transformée, affinée, elle devient puissance créatrice. Face à cette dualité, deux stratégies s'opposent. La première, que Nietzsche rattache au moralisme ancien, veut anéantir la passion elle-même. Elle trouve sa formule emblématique dans le « il faut tuer les passions » que Nietzsche écrit en français et prête à « tous les vieux monstres de la morale ». Le mot d'ordre est ancien : la mortification des passions ({{lang|la|mortificatio passionum}}) plonge ses racines dans le stoïcisme et le néoplatonisme et se lit déjà dans l'''Imitation de Jésus-Christ''. On a parfois rattaché la formule au XVIIe siècle français, à la suite d'Émile Faguet ; mais Nietzsche ne la date pas ainsi, et la source exacte de sa tournure reste incertaine.<ref>Andreas Urs Sommer, ''Kommentar zu Nietzsches Der Fall Wagner, Götzen-Dämmerung'', Berlin / Boston, De Gruyter, 2012, commentaire ''ad'' KSA 6, 82, 9 sq. (p. 315 sq.) : Sommer rapproche la formule d'Émile Faguet (« Le mot d'ordre, au XVIIe siècle, était celui-ci : il faut tuer les passions », ''Faguet 1934'', p. 242), tout en notant qu'elle ne se laisse pas établir avec certitude comme emprunt de Nietzsche. Sur la ''{{lang|la|mortificatio passionum}}'' d'origine stoïcienne et néoplatonicienne, voir Thomas a Kempis, ''De imitatione Christi'', I, 17.</ref> [[Fichier:Bloch-SermonOnTheMount.jpg|vignette|gauche|Le ''Sermon sur la montagne'', par Carl Bloch (1877) : Nietzsche y lit la formule la plus célèbre de l'extirpation des passions.]] Le Sermon sur la montagne en fournit l'illustration la plus célèbre, à propos de la sexualité : « Si ton œil est pour toi une occasion de chute, arrache-le ». Nietzsche remarque avec ironie que « heureusement qu'aucun chrétien n'agit selon ce précepte ». La prescription devient absurde dans son application littérale, et cette absurdité dévoile celle du principe.<ref>Matthieu 5, 29. Le logion est rapporté selon Marc 9, 47 et glosé dans ''L'Antéchrist'', 45 (KSA 6, 221). Cf. Sommer, ''Kommentar''…, ''ad'' KSA 6, 82, 14.</ref> ==== L'image du dentiste ==== Nietzsche cristallise sa critique par une métaphore médicale : « Nous n'admirons plus les dentistes qui ''arrachent'' les dents pour qu'elles ne fassent plus mal ». L'image dévoile l'irrationalité d'une thérapeutique qui supprime l'organe au lieu de le soigner. Détruire les passions et les désirs « seulement à cause de leur bêtise, et pour prévenir les suites désagréables de leur bêtise » nous apparaît désormais comme « une forme aiguë de la bêtise ». Le remède tue le patient. ==== La spiritualisation alternative ==== [[Fichier:Jacob Burckhardt.jpg|vignette|L'historien Jacob Burckhardt, à qui Nietzsche emprunte la notion de spiritualisation de la passion.]] La seconde attitude est la ''{{lang|de|Vergeistigung der Passion}}'', la spiritualisation de la passion. Le terme ne désigne pas un évanouissement de la passion ni sa simple négation, mais la transformation qualitative de l'énergie affective, son intégration à une vie consciente et créatrice. Nietzsche emprunte ce concept à Jacob Burckhardt, dont ''Die Cultur der Renaissance in Italien'' (1860, « La Civilisation de la Renaissance en Italie ») décrit comment la poésie amoureuse de la Renaissance élève la sensualité en une forme spiritualisée, qui cherche son expression la plus haute dans l'idée néoplatonicienne d'une unité première des âmes dans l'essence divine.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 82, 20-23 (p. 317). La source est Jacob Burckhardt, ''Die Cultur der Renaissance in Italien'' (1860), cité par Sommer d'après l'édition Burckhardt 1930a, t. 5, p. 317 ; Burckhardt y évoque, chez les lyriques et les auteurs de dialogues de la Renaissance, « le plus noble approfondissement et la plus noble spiritualisation de la passion ».</ref> Nietzsche reconnaît toutefois une limite historique : « On avouera d'autre part, avec quelque raison, que, sur le terrain où s'est développé le christianisme, l'idée d'une "spiritualisation de la passion" ne pouvait pas du tout être conçue ». Pourquoi cette impossibilité ? Parce que l'Église primitive « luttait, comme on sait, contre les "intelligents", au bénéfice des "pauvres d'esprit" ». Comment attendre d'une institution qui combat l'intelligence qu'elle conduise une « guerre intelligente contre la passion » ? Ce trait relève du diagnostic polémique de Nietzsche, et non d'une description neutre du christianisme des origines. ==== Le castratisme : pratique et philosophie ==== L'Église a choisi une tout autre méthode : le castratisme. Nietzsche fait de ce terme une métaphore directrice, propre à ses derniers écrits, pour désigner l'extirpation de la sensualité érigée en thérapeutique. Le castratisme n'est pas qu'une pratique ou une image ; c'est une ''philosophie'' de la vie fondée sur l'amputation systématique.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 83, 2-4 : l'association du {{lang|de|Castratismus}} au christianisme et à la morale n'apparaît que dans les œuvres tardives ; cf. ''GD'', « Moral als Widernatur » 4 (KSA 6, 85) et ''L'Antéchrist'', 16.</ref> Nietzsche souligne : « Elle ne demande jamais : "Comment spiritualise, embellit et divinise-t-on un désir ?" — De tous temps elle a mis le poids de la discipline sur l'extermination — de la sensualité, de la fierté, du désir de dominer, de posséder et de se venger ». L'énumération révèle l'ampleur de cette répression : elle vise l'ensemble des passions vitales, sans exception. === Section 2. Le diagnostic de dégénérescence === ==== Qui recourt aux moyens radicaux ? ==== Le deuxième aphorisme demande qui recourt réellement au castratisme. Réponse : « Le même remède, la castration et l'extirpation, est employé instinctivement dans la lutte contre le désir par ceux qui sont trop faibles de volonté, trop dégénérés pour pouvoir imposer une mesure à ce désir ». [[Fichier:Portrait d'Armand-Jean Le Bouthillier de Rancé, abbé de la Trappe - Musée Condé.jpg|vignette|L'abbé de Rancé (1626-1700), réformateur de La Trappe et initiateur de l'observance trappiste.]] Nietzsche vise « ces natures qui ont besoin de la Trappe, pour parler en image (et sans image), d'une définitive déclaration de guerre, d'un abîme entre eux et la passion ». L'allusion à La Trappe renvoie à la stricte observance dont Armand Jean Le Bouthillier de Rancé (1626-1700) fut l'initiateur : non le fondateur de l'abbaye, antérieure de plusieurs siècles, mais le réformateur qui en fit le foyer de l'ordre trappiste, emblème de l'ascétisme le plus exigeant.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 83, 15 (p. 319). Nietzsche qualifie lui-même Rancé de « fondateur des couvents trappistes » dans ''Aurore'', 192 (KSA 3, 166) et évoque « le grand fondateur de la Trappe, Rancé » dans la troisième ''Considération inactuelle'' (''Schopenhauer éducateur'', 3, KSA 1, 358) ; ce raccourci vaut pour le mouvement de réforme, l'abbaye Notre-Dame de la Trappe ayant été fondée au XIIe siècle.</ref> Ces individus, incapables de modération, n'ont qu'une ressource : la rupture entière. Le mot allemand {{lang|de|Kluft}} (abîme) dit cette séparation mieux qu'une simple distance. ==== La dégénérescence comme incapacité ==== Voici la formule centrale : « Ce ne sont que les dégénérés qui trouvent les moyens radicaux indispensables ». Et plus précisément : « la faiblesse de volonté, pour parler plus exactement, l'incapacité de ne ''point'' réagir contre une séduction n'est elle-même qu'une autre forme de la dégénérescence ». La portée en est grande. Nietzsche renverse l'évaluation morale usuelle. N'être capable que de l'extrême, le tout ou rien, ne témoigne pas de la force mais de la faiblesse. La véritable puissance sait modérer, graduer, proportionner sa réaction à la séduction. Un corps fort résiste à l'excitation ; un organisme dégénéré y succombe et doit l'éliminer. Un mot de méthode s'impose. « Dégénérescence », comme « décadence », appartient au vocabulaire médico-moral en vogue au XIXe siècle, que Nietzsche détourne à des fins polémiques. Ces termes nomment sa catégorie d'évaluation, l'opposition de la vie ascendante et de la vie déclinante, et non un diagnostic clinique neutre ; on les lira ici en ce sens.<ref>Sur l'arrière-plan de la littérature de la décadence chez Nietzsche, en particulier Paul Bourget, voir Sommer, ''Kommentar''…, ''ad'' KSA 6, 116.</ref> ==== L'hostilité envers les sens comme symptôme ==== « L'inimitié radicale, la haine à mort contre la sensualité est un symptôme grave : on a le droit de faire des suppositions sur l'état général d'un être à tel point excessif ». L'intensité même de la haine envers les passions devient l'indice d'un mal profond. Nietzsche observe que « cette inimitié et cette haine atteignent d'ailleurs leur comble quand de pareilles natures ne possèdent plus assez de fermeté, même pour les cures radicales, même pour le renoncement au "démon" ». L'incapacité à tenir le vœu de castration rend la condamnation plus furieuse encore : c'est l'échec de l'ascétisme qui nourrit un ascétisme plus violent. ==== Qui prononce les paroles les plus venimeuses ? ==== Nietzsche conclut par une observation sur l'origine du discours anti-sensuel : « Que l'on parcoure toute l'histoire des prêtres et des philosophes, y compris celle des artistes : ce ne sont ''pas'' les impuissants, ''pas'' les ascètes qui dirigent leurs flèches empoisonnées contre les sens, ce sont les ascètes impossibles, ceux qui auraient eu besoin d'être des ascètes ». [[Fichier:Augustine of Hippo Sandro Botticelli.jpg|vignette|gauche|Saint Augustin, par Botticelli (1480) : dans le brouillon, Nietzsche désignait Augustin comme l'« ascète impossible » par excellence.]] La formule est subtile. Les véritables ascètes s'accommodent de leur condition ; ce qui produit le discours le plus violent, c'est le désir réprimé avec rage. Le pire ennemi des passions est celui qui les subit le plus intensément et les combat avec fureur. Dans la première rédaction, Nietzsche nommait cet « ascète impossible » : Augustin ; et il identifiait le type dégénéré à « Schopenhauer dans son rapport à la sexualité », le brouillon de ces pages portant le titre {{lang|de|« Schopenhauer und die Sinnlichkeit »}}. Ces deux noms ont disparu de la version imprimée.<ref>Voir l'apparat de KSA 14, 415-417, et Sommer, ''Kommentar''…, p. 313-315. La copie des sections 1 et 2 conservée dans le dossier Mp XVI 4 porte le titre {{lang|de|« Schopenhauer und die Sinnlichkeit »}}, et la rédaction du cahier W II 6 désigne expressément Augustin comme l'« ascète impossible ».</ref> === Section 3. Les triomphes du naturalisme : spiritualisation et agôn === ==== L'amour comme spiritualisation de la sensualité ==== Le troisième aphorisme présente les réalisations positives de la {{lang|de|Vergeistigung}}. Nietzsche énonce : « La spiritualisation de la sensualité s'appelle ''amour'' : elle est un grand triomphe sur le christianisme ». La perspective chrétienne s'en trouve inversée. Pour la tradition, l'amour reste suspect, entaché de sensualité. Pour Nietzsche, il est la transfiguration accomplie de la sensualité. Cet amour-spiritualisation ne nie pas le corps, ne le transcende pas vers une sphère abstraite : il l'intègre à la conscience, à la tendresse, à la beauté. C'est ce que Burckhardt observe chez les poètes de la Renaissance, où la spiritualisation la plus fine de la passion procède de la sensualité la plus raffinée. ==== L'inimitié spiritualisée : l'agôn ==== « L' ''inimitié'' est un autre triomphe de notre spiritualisation ». Celle-ci « consiste à comprendre profondément l'intérêt qu'il y a à avoir des ennemis : bref, à agir et à conclure inversement que l'on agissait et concluait autrefois ». Nietzsche renverse ici la logique chrétienne. L'Église voulait « de tous temps l'anéantissement de ses ennemis » ; « nous autres, immoralistes et anti-chrétiens, nous voyons notre avantage à ce que l'Église subsiste ». La position n'a rien de cynique. Elle repose sur la reconnaissance que la force se forme dans le conflit, que l'excellence naît de la concurrence, que l'ennemi est nécessaire. On peut rapprocher cette valorisation de l'adversaire du modèle grec de l'agôn ({{lang|grc|ἀγών}}, la compétition réglée), même si Nietzsche insiste ici moins sur la joute elle-même que sur la conservation de l'ennemi et la fécondité de l'opposition. ==== La politique et la grande politique ==== Cette spiritualisation s'étend au domaine politique : « Dans les choses politiques, l'inimitié est devenue maintenant aussi plus intellectuelle, plus sage, plus réfléchie, plus ''modérée'' ». Chaque parti voit « un intérêt de conservation de soi à ne pas laisser s'épuiser le parti adverse ». La destruction de l'adversaire entraînerait l'affaiblissement de soi-même. Il en va de même pour la « grande politique ». « Une nouvelle création, par exemple le nouvel Empire, a plus besoin d'ennemis que d'amis : ce n'est que par le contraste qu'elle commence à se sentir nécessaire, à ''devenir'' nécessaire ». L'ennemi n'est donc pas un obstacle externe, mais une condition de l'affirmation de soi. ==== L'ennemi intérieur et la fécondité ==== « Nous ne nous comportons pas autrement à l'égard de l'"ennemi intérieur" : là aussi nous avons spiritualisé l'inimitié, là aussi nous avons compris sa ''valeur'' ». On n'est « fécond qu'à ce prix-là qu'on est riche en opposition » ; on ne reste « jeune qu'à condition que l'âme ne se repose pas, que l'âme ne demande pas la paix ». Ces remarques contredisent l'idéal ascétique de tranquillité. La vraie jeunesse n'est pas l'ataraxie (absence de trouble), mais la vitalité conflictuelle. La fécondité naît de tensions internes maintenues dans un équilibre dynamique. === La paix de l'âme : fin du troisième aphorisme === ==== Le rejet de la quiétude morale ==== Toujours au sein du troisième aphorisme, Nietzsche en vient à l'idéal de la « paix de l'âme ». « Rien n'est devenu plus étranger pour nous que ce qui faisait autrefois l'objet des désirs, la "paix de l'âme" que souhaitaient les ''chrétiens'' ». Le jugement est tranché : cet idéal, autrefois valorisé, devient répugnant. « Rien n'est moins l'objet de notre envie que le bétail moral et le bonheur gras de la conscience tranquille ». L'image du « bétail moral » dit le mépris de Nietzsche pour une moralité bornée, ruminante, satisfaite d'elle-même. Cette paix n'est pas l'apaisement du guerrier après la victoire, mais la stupeur de la bête endormie. ==== Grande vie et guerre ==== « On a renoncé à la ''grande'' vie lorsqu'on renonce à la guerre ». La formule est provocante. Elle affirme que la grandeur vitale suppose un état de lutte, de tension créatrice. La paix définitive serait la mort, ou plutôt la vie diminuée. ==== Les masques de la paix de l'âme ==== Nietzsche énumère ensuite les réalités souvent masquées par l'expression « paix de l'âme » : * Le doux rayonnement d'une animalité riche dans le domaine moral ou religieux * Le commencement de la fatigue, la première ombre que jette le soir * Un signe que l'air est humide, que le vent du sud va souffler (métaphore climatique) * La reconnaissance involontaire pour une bonne digestion (l'apaisement physiologique travesti en état moral) * L'accalmie chez le convalescent qui recommence à prendre goût à toute chose et qui attend * L'état qui suit une forte satisfaction de notre passion dominante, le bien-être d'une rare satiété * La caducité de notre volonté, de nos désirs, de nos vices * La paresse que la vanité pousse à se parer de moralité * La venue d'une certitude, même d'une terrible certitude * L'expression de la maturité et de la maîtrise, au milieu de l'activité, du travail, de la production, du vouloir, la respiration tranquille quand la « liberté de la volonté » est ''atteinte'' Cette énumération minutieuse montre que « paix de l'âme » recouvre une multiplicité de réalités biologiques, psychologiques et morales qu'il convient de distinguer plutôt que de confondre sous une formule creuse. ==== L'auto-référence ==== L'aphorisme se clôt sur une remarque réflexive : « ''Crépuscule des idoles'' : qui sait ? peut-être est-ce là aussi une sorte de "paix de l'âme"… ». Nietzsche suggère avec ironie que son propre livre pourrait passer pour une forme de cette paix : celle qui suit un combat mené à son terme, satisfaction apaisée après l'exercice de la critique.<ref>Ce développement sur la « paix de l'âme », ainsi que l'autoréférence finale, appartiennent encore au troisième aphorisme (KSA 6, 84-85), et non à une section distincte ; voir l'apparat de KSA 14, 415 sq. et l'analyse d'Axel Pichler, ''Philosophie als Text. Zur Darstellungsform der Götzen-Dämmerung'', Berlin / Boston, De Gruyter, 2014, qui situe au seuil du quatrième aphorisme le statut problématique des fondements évaluatifs de la critique.</ref> === Section 4. Le naturalisme moral : formulation du principe === ==== La formulation centrale ==== Le quatrième aphorisme présente le « principe » nietzschéen sous forme de formule : « Tout naturalisme dans la morale, c'est-à-dire toute ''saine'' morale, est dominée par l'instinct de vie, — un commandement de la vie quelconque est rempli par un canon déterminé d'"ordres" et de "défenses", une entrave ou une inimitié quelconque, sur le domaine vital, est ainsi mise de côté ». Ce « naturalisme moral » ne signifie pas l'absence de normes, mais l'ancrage de celles-ci dans l'impératif vital. La morale saine n'est pas celle qui obéit à des principes abstraits, mais celle qui organise l'existence en fonction de l'amplification de la vie. Elle prescrit certaines actions parce qu'elles favorisent la vitalité ; elle en interdit d'autres parce qu'elles l'appauvrissent. ==== La morale antinaturelle ==== « La morale ''antinaturelle'', c'est-à-dire toute morale qui jusqu'à présent a été enseignée, vénérée et prêchée, se dirige, au contraire, précisément ''contre'' les instincts vitaux —, elle est une ''condamnation'', tantôt secrète, tantôt bruyante et effrontée, de ces instincts ». Cette morale s'oppose directement à ce qui constitue l'énergie vitale. C'est la morale contre-nature elle-même qui parle lorsqu'elle reprend la formule proverbiale {{lang|de|« Gott sieht das Herz an »}} (« Dieu regarde le cœur », écho de Luc 16, 15) : en la prononçant, elle dit non aux aspirations les plus basses comme les plus hautes de la vie et fait de Dieu l'« ennemi de la vie ». Sa cible n'est pas tel acte extérieur, mais la disposition intérieure, l'instinct lui-même, qu'elle condamne en son principe.<ref>Le sujet grammatical de la phrase est, chez Nietzsche, la morale contre-nature, non le Christ : {{lang|de|« Indem sie sagt 'Gott sieht das Herz an', sagt sie […] Nein »}} (''GD'', « Moral als Widernatur » 4, KSA 6, 85, 26). La formule, proverbiale et largement répandue, s'adosse à Luc 16, 15 (Sommer, ''Kommentar''…, ''ad'' KSA 6, 85, 26, p. 326). Une rédaction préparatoire met explicitement ces mots dans la bouche de « l'idéologue, le moraliste » (KGW IX 8, W II 5, 48 ; cf. KSA 14, 417 sq.).</ref> ==== Les figures du néant ==== Deux formules lapidaires synthétisent le diagnostic : : ''« Le saint qui plaît à Dieu, c'est le castrat idéal. »'' : ''« La vie prend fin là où commence le "Royaume de Dieu" ({{lang|de|Reich Gottes}}). »'' Ces deux énoncés dépeignent un renversement entier : ce que Dieu valorise, la sainteté, c'est l'émasculation de la vie ; et l'ordre divin commence là même où la vie terrestre s'achève. Le christianisme n'est donc pas seulement hostile à la vie ; il en est la négation systématique.<ref>Cf. Matthieu 12, 18 pour le « bon plaisir » divin. Sur l'idéal de sainteté entendu comme « négation de la volonté de vivre » ({{lang|de|Verneinung des Willens zum Leben}}), voir Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', t. I, livre IV, § 68.</ref> === Section 5. Morale et décadence : généalogie d'une maladie === ==== L'impossible jugement objectif sur la vie ==== Le cinquième aphorisme développe l'argument généalogique central. « En admettant que l'on ait compris ce qu'il y a de sacrilège dans un pareil soulèvement contre la vie, tel qu'il est devenu presque sacro-saint dans la morale chrétienne, on aura, par cela même et heureusement, compris autre chose encore : ce qu'il y a d'inutile, de factice, d'absurde, de ''mensonger'' dans un pareil soulèvement ». Nietzsche énonce alors son argument central : « Une condamnation de la vie de la part du vivant n'est finalement que le symptôme d'une espèce de vie déterminée ». Pour la poser véritablement, il faudrait « prendre position ''en dehors'' de la vie et la connaître d'autre part tout aussi bien que quelqu'un qui l'a traversée, que plusieurs et même tous ceux qui y ont passé, pour ne pouvoir que toucher au problème de la ''valeur'' de la vie ». Cet argument invalide le principe du jugement moral objectif. Tout jugement de valeur sur la vie provient de l'intérieur de la vie. Nous ne pouvons juger la vie que depuis la vie. ==== L'optique de la vie ==== « Si nous parlons de la valeur, nous parlons sous l'inspiration, sous l'optique de la vie : la vie elle-même nous force à déterminer des valeurs, la vie elle-même évalue par notre entremise lorsque nous déterminons des valeurs ». La formule est centrale : tout système de valeurs, même le plus critique, reflète une certaine configuration vitale. Nous jugeons toujours depuis un point de vue incarné, partial, intéressé. ==== La morale antinaturelle comme symptôme de décadence ==== « Il s'ensuit que toute ''morale contre nature'' qui considère Dieu comme l'idée contraire, comme la condamnation de la vie, n'est en réalité qu'une évaluation de la vie, — de ''quelle'' vie ? de ''quelle'' espèce de vie ? » La réponse surgit aussitôt : « de la vie descendante, affaiblie, fatiguée, condamnée ». On ne réfute pas la morale chrétienne en montrant qu'elle se contredit logiquement ; on l'explique en montrant qu'elle exprime une volonté de non-être, une aspiration de la vie dégénérée à sa propre négation. [[Fichier:Arthur Schopenhauer by J Schäfer, 1859b.jpg|vignette|Arthur Schopenhauer en 1859 : sa « négation de la volonté de vivre » est, pour Nietzsche, la forme la plus consciente de la morale de décadence.]] « La morale, telle qu'on l'a entendue jusqu'à maintenant — telle qu'elle a été formulée en dernier lieu par Schopenhauer, comme "négation de la volonté de vivre" — cette morale est ''l'instinct de décadence'' même, qui se transforme en impératif : elle dit : "''va à ta perte !''" — elle est le jugement de ceux qui sont déjà jugés ». Schopenhauer apparaît ici comme le dernier philosophe en qui la morale chrétienne devient pleinement transparente et consciente d'elle-même. === Section 6. Critique du prescriptivisme moral === ==== La naïveté du « tu dois » ==== Le sixième et dernier aphorisme étend la critique à toute forme de moralisme prescriptif. « Considérons enfin quelle naïveté il y a à dire : "L'homme devrait être fait de telle manière !" » Nietzsche oppose à cette prétention « la réalité : nous voyons une merveilleuse richesse de types, une exubérance dans la variété et dans la profusion des formes », et l'on entendrait « n'importe quel pitoyable moraliste des carrefours venir nous dire : "Non ! l'homme ''devrait'' être fait autrement" ? » ==== Le moraliste ridicule ==== Pire, « il sait même ''comment'' il devrait être, ce pauvre diable de cagot, il fait son propre portrait sur les murs et il dit : "''Ecce Homo !''" » L'allusion à Jean 19, 5, où Pilate montre Jésus flagellé, sera reprise par Nietzsche comme titre de son autobiographie ''{{lang|la|Ecce homo}}''. Ici, elle dénonce la prétention du moraliste à ériger son propre type dégénéré en norme universelle.<ref>Jean 19, 5 (« Voici l'homme »).</ref> ==== L'absurdité du changement prescrit ==== Même l'approche individualisée du moraliste reste ridicule : « Même lorsque le moraliste ne s'adresse qu'à l'individu pour lui dire : "C'est ainsi que tu dois être !" il ne cesse pas de se rendre ridicule ». Pourquoi ? Parce que « l'individu, quelle que soit la façon de le considérer, fait partie de la fatalité, il est une loi de plus, une nécessité de plus pour tout ce qui est à venir ». C'est une ''{{lang|la|reductio ad absurdum}}'' de la liberté morale. L'individu n'est pas une substance libre flottant au-dessus des lois naturelles ; il est une configuration de forces, un nœud de nécessités héréditaires et environnementales. Lui dire « change ta nature » revient à « souhaiter la transformation de tout, même une transformation en arrière ». ==== Les moralistes conséquents : négateurs du monde ==== « Et vraiment, il y a eu des moralistes conséquents qui voulaient que les hommes fussent autres, c'est-à-dire vertueux, ils voulaient les hommes à leur image, à l'image des cagots ; c'est pour cela qu'ils ont ''nié'' le monde. Point de petite folie ! Point de façon modeste d'immodestie ! » Ces moralistes ont tiré les conclusions dernières de leur position. Si l'homme doit être tout autre, c'est que le monde tel qu'il est doit être entièrement mauvais. La négation du monde découle du refus du réel au nom d'un idéal. ==== Verdict final ==== « La morale, pour peu qu'elle ''condamne'' est, par soi-même, et ''non'' pas par égard pour la vie, une erreur spécifique qu'il ne faut pas prendre en pitié, une ''idiosyncrasie de dégénérés'' qui a fait immensément de mal ! » Le verdict est sans réserve. La morale qui condamne par elle-même, sans égard pour la vie, n'est pas une sagesse, mais une « erreur spécifique », une manifestation pathologique. ==== L'affirmation immoraliste ==== « Nous autres immoralistes, au contraire, nous avons largement ouvert notre cœur à toute espèce de compréhension, d'intelligibilité et d'''approbation'' ». Cette affirmation finale inverse le jugement. L'« immoralisme » nietzschéen n'est ni amoralisme ni nihilisme, mais la capacité à voir, à comprendre, à inclure plutôt qu'à rejeter en bloc. « Nous ne nions pas facilement, nous mettons notre honneur à être ''affirmateurs'' ». L'affirmation n'est pas ici une nouvelle table de valeurs ni une morale plus haute, mais une disposition : non pas affirmer aveuglément, mais dire oui à la diversité, à la complexité, à la tragédie de l'existence. « Nos yeux se sont ouverts toujours davantage pour cette économie qui a besoin, et qui sait se servir de tout ce que la sainte déraison, la raison ''maladive'' du prêtre rejette, pour cette économie dans la loi vitale qui tire son avantage même des plus répugnants spécimens de cagots, de prêtres et de pères la Vertu ». Cette reconnaissance de la fonction économique du mal, de son utilité vitale, culmine dans la dernière phrase : « ''quels'' avantages ? — Mais nous-mêmes, nous autres immoralistes, nous sommes ici une réponse vivante ». === Conclusion : une critique généalogique et physiologique === ==== La méthode nietzschéenne ==== Cette section du ''Crépuscule des idoles'' déploie pleinement la méthode généalogique. Il ne s'agit pas de réfuter la morale chrétienne par l'argumentation logique, mais de l'expliquer génétiquement : d'en retrouver l'origine dans une physiologie dégénérée, dans une volonté de non-être. Le diagnostic repose sur l'idée que toute morale traduit un certain état vital ; sa portée n'est pas logique mais symptomatologique. ==== La spiritualisation contre la castration ==== L'opposition entre « spiritualisation » et « castration » structure toute l'argumentation. Là où le christianisme opère par suppression et négation, Nietzsche lui oppose une transformation qualitative qui préserve et élève l'énergie vitale. L'amour comme spiritualisation de la sensualité, l'inimitié spiritualisée comme agôn : voilà les contre-modèles qui réorientent la vie vers sa pleine expression. ==== Au-delà du moralisme ==== La conclusion « nous-mêmes, nous autres immoralistes, nous sommes ici une réponse vivante » ne signifie pas que Nietzsche rejette toute évaluation. Au contraire. Il fait porter la force sur l'affirmation de la multiplicité et sur la reconnaissance de l'économie par laquelle même les types dégénérés servent la vie. Cette position ne relève ni du moralisme ni de l'amoralisme. Ce que Nietzsche refuse, c'est une morale qui juge la vie du point de vue d'un au-delà imaginaire. Contre le « tu dois » abstrait et universel, il affirme la diversité des types, la richesse du devenir, la nécessité de chaque configuration vitale, y compris celles que le moralisme chrétien condamne. ==== Une difficulté assumée : juger la vie depuis la vie ==== Reste une tension que le chapitre ne dissimule pas. En dépréciant la morale ascétique parce qu'elle contrarie les intérêts de la vie, Nietzsche mobilise encore une norme, celle de la vie ascendante : il argumente moralement contre la morale. Sommer propose de lire ce geste comme une stratégie métamorale. Loin de livrer une nouvelle table de valeurs, Nietzsche exhibe la manière dont fonctionne toute évaluation, jusque dans sa prétention à se dépasser, et conduit ainsi la logique de la morale à se retourner contre elle-même.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 81-82 : l'argumentation morale contre la morale peut se lire comme une tentative de conduire performativement la logique interne de la morale à l'absurde, et l'arrière-plan du chapitre comme « métamoral ».</ref> Le vocabulaire de la « nature » connaît la même instabilité. Si tout est vie, force et interprétation, alors la morale « contre nature » est elle-même un phénomène naturel, le symptôme d'un certain type de vie. Nietzsche peut donc tenir la morale pour anti-naturelle et, ailleurs, pour un fragment de nature, fruit d'un sol vital déterminé.<ref>Karl Jaspers, ''Nietzsche. Einführung in das Verständnis seines Philosophierens'', Berlin, De Gruyter, 1936 (trad. fr. ''Nietzsche. Introduction à sa philosophie'', Paris, Gallimard, 1950), relève cette oscillation : la morale est dite « contre nature » sans cesser d'être « un morceau de nature ».</ref> Cette critique ne donne donc pas accès à des valeurs objectives. Comme Nietzsche le formulera deux chapitres plus loin, dans [[Philosophie/Nietzsche/Crépuscule des idoles/Ceux qui veulent rendre l’humanité « meilleure »|« Ceux qui veulent rendre l'humanité "meilleure" »]], « il n'y a point de faits moraux », seulement des interprétations morales de phénomènes. La morale relève d'une sémiotique, d'une symptomatologie : elle vaut comme signe d'un type de culture ou d'intériorité, non comme savoir.<ref>''GD'', « Ceux qui veulent rendre l'humanité "meilleure" » ({{lang|de|Die "Verbesserer" der Menschheit}}), 1 (KSA 6, 98) : « il n'y a point de faits moraux… la morale n'est qu'une interprétation de certains phénomènes, plus exactement une mésinterprétation ». Cf. Sommer, ''Kommentar''…, ''ad'' KSA 6, 98.</ref> ==== Portée du chapitre ==== Le texte demeure l'une des attaques les plus serrées jamais conduites contre le moralisme chrétien, non au nom du libertinage ou de l'amoralisme, mais d'un point de vue qui juge les morales à la mesure de la vie. La critique ne vise pas à libérer la chair contre l'esprit : elle montre comment une certaine spiritualité, celle de l'extirpation, appauvrit la vie au lieu de l'amplifier. Nietzsche oppose ainsi à la spiritualité chrétienne de l'extirpation une spiritualisation affirmative des passions : non pas l'amputation du désir, mais sa transformation. C'est cette opposition, et non un programme de réforme adressé aux chrétiens, qui porte le chapitre. == Notes et références == {{Références|colonnes=2}} {{AutoCat}} 0zbngv33814kh3z17ydpgcidgbh1fxp 768757 768756 2026-06-27T06:27:37Z PandaMystique 119061 768757 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" | | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"| |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} === Introduction : contexte et enjeux === Cinquième des dix chapitres du ''[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles|Crépuscule des idoles]]'', le chapitre {{lang|de|« Moral als Widernatur »}} est traditionnellement rendu en français par « La morale en tant que manifestation contre nature », titre de la traduction d'Henri Albert ; on peut aussi le traduire, plus littéralement, « La morale comme contre-nature ». Il compte parmi les attaques les plus vigoureuses de Nietzsche contre la morale chrétienne. Composé de six aphorismes qui déploient une critique à la fois physiologique et psychologique, il porte le projet central des derniers écrits : la transmutation de toutes les valeurs ({{lang|de|Umwerthung aller Werthe}}). Dans l'économie du livre, il fait suite à [[Philosophie/Nietzsche/Crépuscule des idoles/Comment, pour finir, le « monde vrai » devint fable|« Comment le "monde vrai" devint fable »]] et précède [[Philosophie/Nietzsche/Crépuscule des idoles/Les quatre grandes erreurs|« Les quatre grandes erreurs »]]. {{wikisource|Le Crépuscule des Idoles/La Morale en tant que manifestation contre nature}} Plutôt qu'une critique logique ou strictement morale, Nietzsche y met en œuvre une méthode généalogique. Il ne demande pas si la morale chrétienne est vraie ou fausse, mais de quel type de vie elle est l'expression. Cette interrogation physiologique déplace le débat : Nietzsche n'évalue plus la morale comme vraie ou fausse, mais selon qu'elle sert ou contrarie les intérêts de la vie. Ce critère mobilise lui-même une norme, celle de la vie ascendante, et engage Nietzsche dans une difficulté que le chapitre travaille en sous-main et sur laquelle on reviendra. Le commentaire qui suit épouse l'ordre des six aphorismes du chapitre. Ses intitulés restent thématiques et ne se superposent pas terme à terme au texte : le troisième aphorisme, le plus riche, demande d'être abordé en deux temps, les triomphes de la spiritualisation d'abord, la mise en cause de la « paix de l'âme » ensuite. === Section 1. Passions : entre destruction et spiritualisation === ==== Le dilemme de la passion ==== Le premier aphorisme pose une distinction entre deux rapports aux passions. Nietzsche reconnaît que « toutes les passions ont un temps où elles ne sont que néfastes, où elles avilissent leurs victimes avec la lourdeur de la bêtise ». Mais il existe « une époque tardive, beaucoup plus tardive où elles se marient à l'esprit, où elles se "spiritualisent" ». La passion n'est donc pas mauvaise en elle-même ; elle possède une double temporalité. À l'état brut, elle peut nuire. Transformée, affinée, elle devient puissance créatrice. Face à cette dualité, deux stratégies s'opposent. La première, que Nietzsche rattache au moralisme ancien, veut anéantir la passion elle-même. Elle trouve sa formule emblématique dans le « il faut tuer les passions » que Nietzsche écrit en français et prête à « tous les vieux monstres de la morale ». Le mot d'ordre est ancien : la mortification des passions ({{lang|la|mortificatio passionum}}) plonge ses racines dans le stoïcisme et le néoplatonisme et se lit déjà dans l'''Imitation de Jésus-Christ''. On a parfois rattaché la formule au XVIIe siècle français, à la suite d'Émile Faguet ; mais Nietzsche ne la date pas ainsi, et la source exacte de sa tournure reste incertaine.<ref>Andreas Urs Sommer, ''Kommentar zu Nietzsches Der Fall Wagner, Götzen-Dämmerung'', Berlin / Boston, De Gruyter, 2012, commentaire ''ad'' KSA 6, 82, 9 sq. (p. 315 sq.) : Sommer rapproche la formule d'Émile Faguet (« Le mot d'ordre, au XVIIe siècle, était celui-ci : il faut tuer les passions », ''Faguet 1934'', p. 242), tout en notant qu'elle ne se laisse pas établir avec certitude comme emprunt de Nietzsche. Sur la ''{{lang|la|mortificatio passionum}}'' d'origine stoïcienne et néoplatonicienne, voir Thomas a Kempis, ''De imitatione Christi'', I, 17.</ref> [[Fichier:Bloch-SermonOnTheMount.jpg|vignette|gauche|Le ''Sermon sur la montagne'', par Carl Bloch (1877) : Nietzsche y lit la formule la plus célèbre de l'extirpation des passions.]] Le Sermon sur la montagne en fournit l'illustration la plus célèbre, à propos de la sexualité : « Si ton œil est pour toi une occasion de chute, arrache-le ». Nietzsche remarque avec ironie que « heureusement qu'aucun chrétien n'agit selon ce précepte ». La prescription devient absurde dans son application littérale, et cette absurdité dévoile celle du principe.<ref>Matthieu 5, 29. Le logion est rapporté selon Marc 9, 47 et glosé dans ''L'Antéchrist'', 45 (KSA 6, 221). Cf. Sommer, ''Kommentar''…, ''ad'' KSA 6, 82, 14.</ref> ==== L'image du dentiste ==== Nietzsche cristallise sa critique par une métaphore médicale : « Nous n'admirons plus les dentistes qui ''arrachent'' les dents pour qu'elles ne fassent plus mal ». L'image dévoile l'irrationalité d'une thérapeutique qui supprime l'organe au lieu de le soigner. Détruire les passions et les désirs « seulement à cause de leur bêtise, et pour prévenir les suites désagréables de leur bêtise » nous apparaît désormais comme « une forme aiguë de la bêtise ». Le remède tue le patient. ==== La spiritualisation alternative ==== [[Fichier:Jacob Burckhardt.jpg|vignette|L'historien Jacob Burckhardt, à qui Nietzsche emprunte la notion de spiritualisation de la passion.]] La seconde attitude est la ''{{lang|de|Vergeistigung der Passion}}'', la spiritualisation de la passion. Le terme ne désigne pas un évanouissement de la passion ni sa simple négation, mais la transformation qualitative de l'énergie affective, son intégration à une vie consciente et créatrice. Nietzsche emprunte ce concept à Jacob Burckhardt, dont ''Die Cultur der Renaissance in Italien'' (1860, « La Civilisation de la Renaissance en Italie ») décrit comment la poésie amoureuse de la Renaissance élève la sensualité en une forme spiritualisée, qui cherche son expression la plus haute dans l'idée néoplatonicienne d'une unité première des âmes dans l'essence divine.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 82, 20-23 (p. 317). La source est Jacob Burckhardt, ''Die Cultur der Renaissance in Italien'' (1860), cité par Sommer d'après l'édition Burckhardt 1930a, t. 5, p. 317 ; Burckhardt y évoque, chez les lyriques et les auteurs de dialogues de la Renaissance, « le plus noble approfondissement et la plus noble spiritualisation de la passion ».</ref> Nietzsche reconnaît toutefois une limite historique : « On avouera d'autre part, avec quelque raison, que, sur le terrain où s'est développé le christianisme, l'idée d'une "spiritualisation de la passion" ne pouvait pas du tout être conçue ». Pourquoi cette impossibilité ? Parce que l'Église primitive « luttait, comme on sait, contre les "intelligents", au bénéfice des "pauvres d'esprit" ». Comment attendre d'une institution qui combat l'intelligence qu'elle conduise une « guerre intelligente contre la passion » ? Ce trait relève du diagnostic polémique de Nietzsche, et non d'une description neutre du christianisme des origines. ==== Le castratisme : pratique et philosophie ==== L'Église a choisi une tout autre méthode : le castratisme. Nietzsche fait de ce terme une métaphore directrice, propre à ses derniers écrits, pour désigner l'extirpation de la sensualité érigée en thérapeutique. Le castratisme n'est pas qu'une pratique ou une image ; c'est une ''philosophie'' de la vie fondée sur l'amputation systématique.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 83, 2-4 : l'association du {{lang|de|Castratismus}} au christianisme et à la morale n'apparaît que dans les œuvres tardives ; cf. ''GD'', « Moral als Widernatur » 4 (KSA 6, 85) et ''L'Antéchrist'', 16.</ref> Nietzsche souligne : « Elle ne demande jamais : "Comment spiritualise, embellit et divinise-t-on un désir ?" — De tous temps elle a mis le poids de la discipline sur l'extermination — de la sensualité, de la fierté, du désir de dominer, de posséder et de se venger ». L'énumération révèle l'ampleur de cette répression : elle vise l'ensemble des passions vitales, sans exception. === Section 2. Le diagnostic de dégénérescence === ==== Qui recourt aux moyens radicaux ? ==== Le deuxième aphorisme demande qui recourt réellement au castratisme. Réponse : « Le même remède, la castration et l'extirpation, est employé instinctivement dans la lutte contre le désir par ceux qui sont trop faibles de volonté, trop dégénérés pour pouvoir imposer une mesure à ce désir ». [[Fichier:Portrait d'Armand-Jean Le Bouthillier de Rancé, abbé de la Trappe - Musée Condé.jpg|vignette|L'abbé de Rancé (1626-1700), réformateur de La Trappe et initiateur de l'observance trappiste.]] Nietzsche vise « ces natures qui ont besoin de la Trappe, pour parler en image (et sans image), d'une définitive déclaration de guerre, d'un abîme entre eux et la passion ». L'allusion à La Trappe renvoie à la stricte observance dont Armand Jean Le Bouthillier de Rancé (1626-1700) fut l'initiateur : non le fondateur de l'abbaye, antérieure de plusieurs siècles, mais le réformateur qui en fit le foyer de l'ordre trappiste, emblème de l'ascétisme le plus exigeant.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 83, 15 (p. 319). Nietzsche qualifie lui-même Rancé de « fondateur des couvents trappistes » dans ''Aurore'', 192 (KSA 3, 166) et évoque « le grand fondateur de la Trappe, Rancé » dans la troisième ''Considération inactuelle'' (''Schopenhauer éducateur'', 3, KSA 1, 358) ; ce raccourci vaut pour le mouvement de réforme, l'abbaye Notre-Dame de la Trappe ayant été fondée au XIIe siècle.</ref> Ces individus, incapables de modération, n'ont qu'une ressource : la rupture entière. Le mot allemand {{lang|de|Kluft}} (abîme) dit cette séparation mieux qu'une simple distance. ==== La dégénérescence comme incapacité ==== Voici la formule centrale : « Ce ne sont que les dégénérés qui trouvent les moyens radicaux indispensables ». Et plus précisément : « la faiblesse de volonté, pour parler plus exactement, l'incapacité de ne ''point'' réagir contre une séduction n'est elle-même qu'une autre forme de la dégénérescence ». La portée en est grande. Nietzsche renverse l'évaluation morale usuelle. N'être capable que de l'extrême, le tout ou rien, ne témoigne pas de la force mais de la faiblesse. La véritable puissance sait modérer, graduer, proportionner sa réaction à la séduction. Un corps fort résiste à l'excitation ; un organisme dégénéré y succombe et doit l'éliminer. Un mot de méthode s'impose. « Dégénérescence », comme « décadence », appartient au vocabulaire médico-moral en vogue au XIXe siècle, que Nietzsche détourne à des fins polémiques. Ces termes nomment sa catégorie d'évaluation, l'opposition de la vie ascendante et de la vie déclinante, et non un diagnostic clinique neutre ; on les lira ici en ce sens.<ref>Sur l'arrière-plan de la littérature de la décadence chez Nietzsche, en particulier Paul Bourget, voir Sommer, ''Kommentar''…, ''ad'' KSA 6, 116.</ref> ==== L'hostilité envers les sens comme symptôme ==== « L'inimitié radicale, la haine à mort contre la sensualité est un symptôme grave : on a le droit de faire des suppositions sur l'état général d'un être à tel point excessif ». L'intensité même de la haine envers les passions devient l'indice d'un mal profond. Nietzsche observe que « cette inimitié et cette haine atteignent d'ailleurs leur comble quand de pareilles natures ne possèdent plus assez de fermeté, même pour les cures radicales, même pour le renoncement au "démon" ». L'incapacité à tenir le vœu de castration rend la condamnation plus furieuse encore : c'est l'échec de l'ascétisme qui nourrit un ascétisme plus violent. ==== Qui prononce les paroles les plus venimeuses ? ==== Nietzsche conclut par une observation sur l'origine du discours anti-sensuel : « Que l'on parcoure toute l'histoire des prêtres et des philosophes, y compris celle des artistes : ce ne sont ''pas'' les impuissants, ''pas'' les ascètes qui dirigent leurs flèches empoisonnées contre les sens, ce sont les ascètes impossibles, ceux qui auraient eu besoin d'être des ascètes ». [[Fichier:Augustine of Hippo Sandro Botticelli.jpg|vignette|gauche|Saint Augustin, par Botticelli (1480) : dans le brouillon, Nietzsche désignait Augustin comme l'« ascète impossible » par excellence.]] La formule est subtile. Les véritables ascètes s'accommodent de leur condition ; ce qui produit le discours le plus violent, c'est le désir réprimé avec rage. Le pire ennemi des passions est celui qui les subit le plus intensément et les combat avec fureur. Dans la première rédaction, Nietzsche nommait cet « ascète impossible » : Augustin ; et il identifiait le type dégénéré à « Schopenhauer dans son rapport à la sexualité », le brouillon de ces pages portant le titre {{lang|de|« Schopenhauer und die Sinnlichkeit »}}. Ces deux noms ont disparu de la version imprimée.<ref>Voir l'apparat de KSA 14, 415-417, et Sommer, ''Kommentar''…, p. 313-315. La copie des sections 1 et 2 conservée dans le dossier Mp XVI 4 porte le titre {{lang|de|« Schopenhauer und die Sinnlichkeit »}}, et la rédaction du cahier W II 6 désigne expressément Augustin comme l'« ascète impossible ».</ref> === Section 3. Les triomphes du naturalisme : spiritualisation et agôn === ==== L'amour comme spiritualisation de la sensualité ==== Le troisième aphorisme présente les réalisations positives de la {{lang|de|Vergeistigung}}. Nietzsche énonce : « La spiritualisation de la sensualité s'appelle ''amour'' : elle est un grand triomphe sur le christianisme ». La perspective chrétienne s'en trouve inversée. Pour la tradition, l'amour reste suspect, entaché de sensualité. Pour Nietzsche, il est la transfiguration accomplie de la sensualité. Cet amour-spiritualisation ne nie pas le corps, ne le transcende pas vers une sphère abstraite : il l'intègre à la conscience, à la tendresse, à la beauté. C'est ce que Burckhardt observe chez les poètes de la Renaissance, où la spiritualisation la plus fine de la passion procède de la sensualité la plus raffinée. ==== L'inimitié spiritualisée : l'agôn ==== « L' ''inimitié'' est un autre triomphe de notre spiritualisation ». Celle-ci « consiste à comprendre profondément l'intérêt qu'il y a à avoir des ennemis : bref, à agir et à conclure inversement que l'on agissait et concluait autrefois ». Nietzsche renverse ici la logique chrétienne. L'Église voulait « de tous temps l'anéantissement de ses ennemis » ; « nous autres, immoralistes et anti-chrétiens, nous voyons notre avantage à ce que l'Église subsiste ». La position n'a rien de cynique. Elle repose sur la reconnaissance que la force se forme dans le conflit, que l'excellence naît de la concurrence, que l'ennemi est nécessaire. On peut rapprocher cette valorisation de l'adversaire du modèle grec de l'agôn ({{lang|grc|ἀγών}}, la compétition réglée), même si Nietzsche insiste ici moins sur la joute elle-même que sur la conservation de l'ennemi et la fécondité de l'opposition. ==== La politique et la grande politique ==== Cette spiritualisation s'étend au domaine politique : « Dans les choses politiques, l'inimitié est devenue maintenant aussi plus intellectuelle, plus sage, plus réfléchie, plus ''modérée'' ». Chaque parti voit « un intérêt de conservation de soi à ne pas laisser s'épuiser le parti adverse ». La destruction de l'adversaire entraînerait l'affaiblissement de soi-même. Il en va de même pour la « grande politique ». « Une nouvelle création, par exemple le nouvel Empire, a plus besoin d'ennemis que d'amis : ce n'est que par le contraste qu'elle commence à se sentir nécessaire, à ''devenir'' nécessaire ». L'ennemi n'est donc pas un obstacle externe, mais une condition de l'affirmation de soi. ==== L'ennemi intérieur et la fécondité ==== « Nous ne nous comportons pas autrement à l'égard de l'"ennemi intérieur" : là aussi nous avons spiritualisé l'inimitié, là aussi nous avons compris sa ''valeur'' ». On n'est « fécond qu'à ce prix-là qu'on est riche en opposition » ; on ne reste « jeune qu'à condition que l'âme ne se repose pas, que l'âme ne demande pas la paix ». Ces remarques contredisent l'idéal ascétique de tranquillité. La vraie jeunesse n'est pas l'ataraxie (absence de trouble), mais la vitalité conflictuelle. La fécondité naît de tensions internes maintenues dans un équilibre dynamique. === La paix de l'âme : fin du troisième aphorisme === ==== Le rejet de la quiétude morale ==== Toujours au sein du troisième aphorisme, Nietzsche en vient à l'idéal de la « paix de l'âme ». « Rien n'est devenu plus étranger pour nous que ce qui faisait autrefois l'objet des désirs, la "paix de l'âme" que souhaitaient les ''chrétiens'' ». Le jugement est tranché : cet idéal, autrefois valorisé, devient répugnant. « Rien n'est moins l'objet de notre envie que le bétail moral et le bonheur gras de la conscience tranquille ». L'image du « bétail moral » dit le mépris de Nietzsche pour une moralité bornée, ruminante, satisfaite d'elle-même. Cette paix n'est pas l'apaisement du guerrier après la victoire, mais la stupeur de la bête endormie. ==== Grande vie et guerre ==== « On a renoncé à la ''grande'' vie lorsqu'on renonce à la guerre ». La formule est provocante. Elle affirme que la grandeur vitale suppose un état de lutte, de tension créatrice. La paix définitive serait la mort, ou plutôt la vie diminuée. ==== Les masques de la paix de l'âme ==== Nietzsche énumère ensuite les réalités souvent masquées par l'expression « paix de l'âme » : * Le doux rayonnement d'une animalité riche dans le domaine moral ou religieux * Le commencement de la fatigue, la première ombre que jette le soir * Un signe que l'air est humide, que le vent du sud va souffler (métaphore climatique) * La reconnaissance involontaire pour une bonne digestion (l'apaisement physiologique travesti en état moral) * L'accalmie chez le convalescent qui recommence à prendre goût à toute chose et qui attend * L'état qui suit une forte satisfaction de notre passion dominante, le bien-être d'une rare satiété * La caducité de notre volonté, de nos désirs, de nos vices * La paresse que la vanité pousse à se parer de moralité * La venue d'une certitude, même d'une terrible certitude * L'expression de la maturité et de la maîtrise, au milieu de l'activité, du travail, de la production, du vouloir, la respiration tranquille quand la « liberté de la volonté » est ''atteinte'' Cette énumération minutieuse montre que « paix de l'âme » recouvre une multiplicité de réalités biologiques, psychologiques et morales qu'il convient de distinguer plutôt que de confondre sous une formule creuse. ==== L'auto-référence ==== L'aphorisme se clôt sur une remarque réflexive : « ''Crépuscule des idoles'' : qui sait ? peut-être est-ce là aussi une sorte de "paix de l'âme"… ». Nietzsche suggère avec ironie que son propre livre pourrait passer pour une forme de cette paix : celle qui suit un combat mené à son terme, satisfaction apaisée après l'exercice de la critique.<ref>Ce développement sur la « paix de l'âme », ainsi que l'autoréférence finale, appartiennent encore au troisième aphorisme (KSA 6, 84-85), et non à une section distincte ; voir l'apparat de KSA 14, 415 sq. et l'analyse d'Axel Pichler, ''Philosophie als Text. Zur Darstellungsform der Götzen-Dämmerung'', Berlin / Boston, De Gruyter, 2014, qui situe au seuil du quatrième aphorisme le statut problématique des fondements évaluatifs de la critique.</ref> === Section 4. Le naturalisme moral : formulation du principe === ==== La formulation centrale ==== Le quatrième aphorisme présente le « principe » nietzschéen sous forme de formule : « Tout naturalisme dans la morale, c'est-à-dire toute ''saine'' morale, est dominée par l'instinct de vie, — un commandement de la vie quelconque est rempli par un canon déterminé d'"ordres" et de "défenses", une entrave ou une inimitié quelconque, sur le domaine vital, est ainsi mise de côté ». Ce « naturalisme moral » ne signifie pas l'absence de normes, mais l'ancrage de celles-ci dans l'impératif vital. La morale saine n'est pas celle qui obéit à des principes abstraits, mais celle qui organise l'existence en fonction de l'amplification de la vie. Elle prescrit certaines actions parce qu'elles favorisent la vitalité ; elle en interdit d'autres parce qu'elles l'appauvrissent. ==== La morale antinaturelle ==== « La morale ''antinaturelle'', c'est-à-dire toute morale qui jusqu'à présent a été enseignée, vénérée et prêchée, se dirige, au contraire, précisément ''contre'' les instincts vitaux —, elle est une ''condamnation'', tantôt secrète, tantôt bruyante et effrontée, de ces instincts ». Cette morale s'oppose directement à ce qui constitue l'énergie vitale. C'est la morale contre-nature elle-même qui parle lorsqu'elle reprend la formule proverbiale {{lang|de|« Gott sieht das Herz an »}} (« Dieu regarde le cœur », écho de Luc 16, 15) : en la prononçant, elle dit non aux aspirations les plus basses comme les plus hautes de la vie et fait de Dieu l'« ennemi de la vie ». Sa cible n'est pas tel acte extérieur, mais la disposition intérieure, l'instinct lui-même, qu'elle condamne en son principe.<ref>Le sujet grammatical de la phrase est, chez Nietzsche, la morale contre-nature, non le Christ : {{lang|de|« Indem sie sagt 'Gott sieht das Herz an', sagt sie […] Nein »}} (''GD'', « Moral als Widernatur » 4, KSA 6, 85, 26). La formule, proverbiale et largement répandue, s'adosse à Luc 16, 15 (Sommer, ''Kommentar''…, ''ad'' KSA 6, 85, 26, p. 326). Une rédaction préparatoire met explicitement ces mots dans la bouche de « l'idéologue, le moraliste » (KGW IX 8, W II 5, 48 ; cf. KSA 14, 417 sq.).</ref> ==== Les figures du néant ==== Deux formules lapidaires synthétisent le diagnostic : : ''« Le saint qui plaît à Dieu, c'est le castrat idéal. »'' : ''« La vie prend fin là où commence le "Royaume de Dieu" ({{lang|de|Reich Gottes}}). »'' Ces deux énoncés dépeignent un renversement entier : ce que Dieu valorise, la sainteté, c'est l'émasculation de la vie ; et l'ordre divin commence là même où la vie terrestre s'achève. Le christianisme n'est donc pas seulement hostile à la vie ; il en est la négation systématique.<ref>Cf. Matthieu 12, 18 pour le « bon plaisir » divin. Sur l'idéal de sainteté entendu comme « négation de la volonté de vivre » ({{lang|de|Verneinung des Willens zum Leben}}), voir Arthur Schopenhauer, ''Le Monde comme volonté et comme représentation'', t. I, livre IV, § 68.</ref> === Section 5. Morale et décadence : généalogie d'une maladie === ==== L'impossible jugement objectif sur la vie ==== Le cinquième aphorisme développe l'argument généalogique central. « En admettant que l'on ait compris ce qu'il y a de sacrilège dans un pareil soulèvement contre la vie, tel qu'il est devenu presque sacro-saint dans la morale chrétienne, on aura, par cela même et heureusement, compris autre chose encore : ce qu'il y a d'inutile, de factice, d'absurde, de ''mensonger'' dans un pareil soulèvement ». Nietzsche énonce alors son argument central : « Une condamnation de la vie de la part du vivant n'est finalement que le symptôme d'une espèce de vie déterminée ». Pour la poser véritablement, il faudrait « prendre position ''en dehors'' de la vie et la connaître d'autre part tout aussi bien que quelqu'un qui l'a traversée, que plusieurs et même tous ceux qui y ont passé, pour ne pouvoir que toucher au problème de la ''valeur'' de la vie ». Cet argument invalide le principe du jugement moral objectif. Tout jugement de valeur sur la vie provient de l'intérieur de la vie. Nous ne pouvons juger la vie que depuis la vie. ==== L'optique de la vie ==== « Si nous parlons de la valeur, nous parlons sous l'inspiration, sous l'optique de la vie : la vie elle-même nous force à déterminer des valeurs, la vie elle-même évalue par notre entremise lorsque nous déterminons des valeurs ». La formule est centrale : tout système de valeurs, même le plus critique, reflète une certaine configuration vitale. Nous jugeons toujours depuis un point de vue incarné, partial, intéressé. ==== La morale antinaturelle comme symptôme de décadence ==== « Il s'ensuit que toute ''morale contre nature'' qui considère Dieu comme l'idée contraire, comme la condamnation de la vie, n'est en réalité qu'une évaluation de la vie, — de ''quelle'' vie ? de ''quelle'' espèce de vie ? » La réponse surgit aussitôt : « de la vie descendante, affaiblie, fatiguée, condamnée ». On ne réfute pas la morale chrétienne en montrant qu'elle se contredit logiquement ; on l'explique en montrant qu'elle exprime une volonté de non-être, une aspiration de la vie dégénérée à sa propre négation. [[Fichier:Arthur Schopenhauer by J Schäfer, 1859b.jpg|vignette|Arthur Schopenhauer en 1859 : sa « négation de la volonté de vivre » est, pour Nietzsche, la forme la plus consciente de la morale de décadence.]] « La morale, telle qu'on l'a entendue jusqu'à maintenant — telle qu'elle a été formulée en dernier lieu par Schopenhauer, comme "négation de la volonté de vivre" — cette morale est ''l'instinct de décadence'' même, qui se transforme en impératif : elle dit : "''va à ta perte !''" — elle est le jugement de ceux qui sont déjà jugés ». Schopenhauer apparaît ici comme le dernier philosophe en qui la morale chrétienne devient pleinement transparente et consciente d'elle-même. === Section 6. Critique du prescriptivisme moral === ==== La naïveté du « tu dois » ==== Le sixième et dernier aphorisme étend la critique à toute forme de moralisme prescriptif. « Considérons enfin quelle naïveté il y a à dire : "L'homme devrait être fait de telle manière !" » Nietzsche oppose à cette prétention « la réalité : nous voyons une merveilleuse richesse de types, une exubérance dans la variété et dans la profusion des formes », et l'on entendrait « n'importe quel pitoyable moraliste des carrefours venir nous dire : "Non ! l'homme ''devrait'' être fait autrement" ? » ==== Le moraliste ridicule ==== Pire, « il sait même ''comment'' il devrait être, ce pauvre diable de cagot, il fait son propre portrait sur les murs et il dit : "''Ecce Homo !''" » L'allusion à Jean 19, 5, où Pilate montre Jésus flagellé, sera reprise par Nietzsche comme titre de son autobiographie ''{{lang|la|Ecce homo}}''. Ici, elle dénonce la prétention du moraliste à ériger son propre type dégénéré en norme universelle.<ref>Jean 19, 5 (« Voici l'homme »).</ref> ==== L'absurdité du changement prescrit ==== Même l'approche individualisée du moraliste reste ridicule : « Même lorsque le moraliste ne s'adresse qu'à l'individu pour lui dire : "C'est ainsi que tu dois être !" il ne cesse pas de se rendre ridicule ». Pourquoi ? Parce que « l'individu, quelle que soit la façon de le considérer, fait partie de la fatalité, il est une loi de plus, une nécessité de plus pour tout ce qui est à venir ». C'est une ''{{lang|la|reductio ad absurdum}}'' de la liberté morale. L'individu n'est pas une substance libre flottant au-dessus des lois naturelles ; il est une configuration de forces, un nœud de nécessités héréditaires et environnementales. Lui dire « change ta nature » revient à « souhaiter la transformation de tout, même une transformation en arrière ». ==== Les moralistes conséquents : négateurs du monde ==== « Et vraiment, il y a eu des moralistes conséquents qui voulaient que les hommes fussent autres, c'est-à-dire vertueux, ils voulaient les hommes à leur image, à l'image des cagots ; c'est pour cela qu'ils ont ''nié'' le monde. Point de petite folie ! Point de façon modeste d'immodestie ! » Ces moralistes ont tiré les conclusions dernières de leur position. Si l'homme doit être tout autre, c'est que le monde tel qu'il est doit être entièrement mauvais. La négation du monde découle du refus du réel au nom d'un idéal. ==== Verdict final ==== « La morale, pour peu qu'elle ''condamne'' est, par soi-même, et ''non'' pas par égard pour la vie, une erreur spécifique qu'il ne faut pas prendre en pitié, une ''idiosyncrasie de dégénérés'' qui a fait immensément de mal ! » Le verdict est sans réserve. La morale qui condamne par elle-même, sans égard pour la vie, n'est pas une sagesse, mais une « erreur spécifique », une manifestation pathologique. ==== L'affirmation immoraliste ==== « Nous autres immoralistes, au contraire, nous avons largement ouvert notre cœur à toute espèce de compréhension, d'intelligibilité et d'''approbation'' ». Cette affirmation finale inverse le jugement. L'« immoralisme » nietzschéen n'est ni amoralisme ni nihilisme, mais la capacité à voir, à comprendre, à inclure plutôt qu'à rejeter en bloc. « Nous ne nions pas facilement, nous mettons notre honneur à être ''affirmateurs'' ». L'affirmation n'est pas ici une nouvelle table de valeurs ni une morale plus haute, mais une disposition : non pas affirmer aveuglément, mais dire oui à la diversité, à la complexité, à la tragédie de l'existence. « Nos yeux se sont ouverts toujours davantage pour cette économie qui a besoin, et qui sait se servir de tout ce que la sainte déraison, la raison ''maladive'' du prêtre rejette, pour cette économie dans la loi vitale qui tire son avantage même des plus répugnants spécimens de cagots, de prêtres et de pères la Vertu ». Cette reconnaissance de la fonction économique du mal, de son utilité vitale, culmine dans la dernière phrase : « ''quels'' avantages ? — Mais nous-mêmes, nous autres immoralistes, nous sommes ici une réponse vivante ». === Conclusion : une critique généalogique et physiologique === ==== La méthode nietzschéenne ==== Cette section du ''Crépuscule des idoles'' déploie pleinement la méthode généalogique. Il ne s'agit pas de réfuter la morale chrétienne par l'argumentation logique, mais de l'expliquer génétiquement : d'en retrouver l'origine dans une physiologie dégénérée, dans une volonté de non-être. Le diagnostic repose sur l'idée que toute morale traduit un certain état vital ; sa portée n'est pas logique mais symptomatologique. ==== La spiritualisation contre la castration ==== L'opposition entre « spiritualisation » et « castration » structure toute l'argumentation. Là où le christianisme opère par suppression et négation, Nietzsche lui oppose une transformation qualitative qui préserve et élève l'énergie vitale. L'amour comme spiritualisation de la sensualité, l'inimitié spiritualisée comme agôn : voilà les contre-modèles qui réorientent la vie vers sa pleine expression. ==== Au-delà du moralisme ==== La conclusion « nous-mêmes, nous autres immoralistes, nous sommes ici une réponse vivante » ne signifie pas que Nietzsche rejette toute évaluation. Au contraire. Il fait porter la force sur l'affirmation de la multiplicité et sur la reconnaissance de l'économie par laquelle même les types dégénérés servent la vie. Cette position ne relève ni du moralisme ni de l'amoralisme. Ce que Nietzsche refuse, c'est une morale qui juge la vie du point de vue d'un au-delà imaginaire. Contre le « tu dois » abstrait et universel, il affirme la diversité des types, la richesse du devenir, la nécessité de chaque configuration vitale, y compris celles que le moralisme chrétien condamne. ==== Une difficulté assumée : juger la vie depuis la vie ==== Reste une tension que le chapitre ne dissimule pas. En dépréciant la morale ascétique parce qu'elle contrarie les intérêts de la vie, Nietzsche mobilise encore une norme, celle de la vie ascendante : il argumente moralement contre la morale. Sommer propose de lire ce geste comme une stratégie métamorale. Loin de livrer une nouvelle table de valeurs, Nietzsche exhibe la manière dont fonctionne toute évaluation, jusque dans sa prétention à se dépasser, et conduit ainsi la logique de la morale à se retourner contre elle-même.<ref>Sommer, ''Kommentar''…, ''ad'' KSA 6, 81-82 : l'argumentation morale contre la morale peut se lire comme une tentative de conduire performativement la logique interne de la morale à l'absurde, et l'arrière-plan du chapitre comme « métamoral ».</ref> Le vocabulaire de la « nature » connaît la même instabilité. Si tout est vie, force et interprétation, alors la morale « contre nature » est elle-même un phénomène naturel, le symptôme d'un certain type de vie. Nietzsche peut donc tenir la morale pour anti-naturelle et, ailleurs, pour un fragment de nature, fruit d'un sol vital déterminé.<ref>Karl Jaspers, ''Nietzsche. Einführung in das Verständnis seines Philosophierens'', Berlin, De Gruyter, 1936 (trad. fr. ''Nietzsche. Introduction à sa philosophie'', Paris, Gallimard, 1950), relève cette oscillation : la morale est dite « contre nature » sans cesser d'être « un morceau de nature ».</ref> Cette critique ne donne donc pas accès à des valeurs objectives. Comme Nietzsche le formulera deux chapitres plus loin, dans [[Philosophie/Nietzsche/Crépuscule des idoles/Ceux qui veulent rendre l’humanité « meilleure »|« Ceux qui veulent rendre l'humanité "meilleure" »]], « il n'y a point de faits moraux », seulement des interprétations morales de phénomènes. La morale relève d'une sémiotique, d'une symptomatologie : elle vaut comme signe d'un type de culture ou d'intériorité, non comme savoir.<ref>''GD'', « Ceux qui veulent rendre l'humanité "meilleure" » ({{lang|de|Die "Verbesserer" der Menschheit}}), 1 (KSA 6, 98) : « il n'y a point de faits moraux… la morale n'est qu'une interprétation de certains phénomènes, plus exactement une mésinterprétation ». Cf. Sommer, ''Kommentar''…, ''ad'' KSA 6, 98.</ref> ==== Portée du chapitre ==== Le texte demeure l'une des attaques les plus serrées jamais conduites contre le moralisme chrétien, non au nom du libertinage ou de l'amoralisme, mais d'un point de vue qui juge les morales à la mesure de la vie. La critique ne vise pas à libérer la chair contre l'esprit : elle montre comment une certaine spiritualité, celle de l'extirpation, appauvrit la vie au lieu de l'amplifier. Nietzsche oppose ainsi à la spiritualité chrétienne de l'extirpation une spiritualisation affirmative des passions : non pas l'amputation du désir, mais sa transformation. C'est cette opposition, et non un programme de réforme adressé aux chrétiens, qui porte le chapitre. == Notes et références == {{Références|colonnes=2}} {{AutoCat}} rf7jx10m80dgvq2m32hpnksjxawpf0x Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Le Problème de Socrate 0 83429 768748 767416 2026-06-27T03:05:56Z PandaMystique 119061 768748 wikitext text/x-wiki {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} == Introduction : que signifie mettre Socrate en procès ? == Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l’interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' (''Götzen-Dämmerung''), intitulé « Le problème de Socrate » (''Das Problem des Sokrates''). Nietzsche y soumet le fondateur présumé de la philosophie occidentale à un examen sans ménagement : loin d’incarner l’apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d’une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s’inscrit dans une stratégie plus vaste : en brisant l’idole Socrate, Nietzsche entend ébranler l’édifice entier de la philosophie morale occidentale. == Contexte : genèse et place du chapitre dans l'œuvre == === Circonstances de rédaction === Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d’abord le titre « Sokrates als Problem » (« Socrate comme problème »), puis fut intégré à un projet plus large sur « la philosophie comme décadence » (KSA 14, 413). Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92], où Socrate est qualifié de « moment de la plus profonde perversité dans l’histoire de l’humanité ». === Continuité et ruptures avec les œuvres antérieures === La critique de Socrate traverse l’œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l’« Urbild des theoretischen Optimisten » (« archétype de l’optimiste théorique », GT 15). Nietzsche y opposait l’esprit dionysien, tragique et affirmatif, au rationalisme socratique, qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique prend une inflexion physiologique nouvelle : sous l’influence de lectures médicales récentes — notamment Charles Féré (''Dégénérescence et Criminalité'', 1888) et les travaux d’anthropologie criminelle de Lombroso —, Nietzsche pathologise Socrate. Le philosophe n’est plus seulement un adversaire intellectuel : il est un décadent, un malade, dont la pensée exprime un organisme en voie de décomposition. === La thèse centrale === Nietzsche soutient que la philosophie socratique — avec son équation « raison = vertu = bonheur » — constitue, non pas une conquête de l’esprit, mais le symptôme d’une dégénérescence (''Degenerescenz''). Les « instincts en anarchie » de Socrate l’auraient contraint à ériger la raison en tyran pour se dominer lui-même. Cette solution individuelle, étendue à toute une civilisation en déclin (l’Athènes du V{{e}} siècle), aurait inauguré deux millénaires de philosophie hostile à la vie. La décadence — terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui donner une portée physiologique — désigne ici la désagrégation des instincts vitaux et l’incapacité à affirmer l’existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === ==== Structure argumentative du passage ==== Cette première section remplit une fonction d’ouverture programmatique. Elle se déploie en quatre mouvements : * Le constat (lignes 1-4) énonce l’unanimité des sages sur la non-valeur de la vie. * L’exemple paradigmatique (lignes 4-6) s’appuie sur les dernières paroles de Socrate. * Le renversement herméneutique (lignes 6-10) transforme un argument d’autorité en symptôme de maladie. * L’image conclusive (lignes 10-11) figure la sagesse comme un corbeau attiré par la charogne. Cette structure mime un syllogisme apparent pour le retourner aussitôt : là où la tradition concluait à la vérité d’un jugement unanime, Nietzsche conclut à la pathologie commune des juges. ==== Analyse détaillée ==== ===== 1. Le jugement unanime des sages sur la vie ===== « De tout temps, les plus sages ont porté le même jugement : elle ne vaut rien » L’ouverture est brusque. Nietzsche ne commence pas par une question prudente, mais par une affirmation qui se donne pour un fait acquis. Le syntagme « de tout temps » (''zu allen Zeiten'') confère à l’énoncé une portée transhistorique : il ne s’agit pas d’une école particulière, mais d’un trait que Nietzsche présente comme constant de la sagesse philosophique depuis ses origines. L’expression « elle ne vaut rien » (''es taugt nichts'') mérite attention. Le verbe allemand « taugen » signifie « être bon à », « convenir », « avoir de la valeur ». La formule est volontairement triviale, presque grossière : Nietzsche fait parler les « sages » comme s’ils prononçaient un verdict de comptoir. Cette trivialisation prépare la dégradation ultérieure de leur prestige. ====== Les quatre tonalités du discours des sages ====== Nietzsche caractérise ce jugement par quatre attributs coordonnés : * « plein de doute » (''voll Zweifel'') ; * « plein de mélancolie » (''voll Schwermuth'') ; * « plein de lassitude de la vie » (''voll Müdigkeit am Leben'') ; * « plein de résistance contre la vie » (''voll Widerstand gegen das Leben''). Cette énumération dessine une progression : du doute intellectuel à la mélancolie affective, de la fatigue existentielle à l’hostilité active. Le « contre la vie » (''gegen das Leben'') final annonce le thème central du chapitre : la philosophie comme entreprise de négation vitale. Le terme « Schwermuth » (mélancolie) appartient au vocabulaire médico-psychologique du XIX{{e}} siècle. Il désigne un état dépressif que la psychiatrie de l’époque — notamment chez Jean-Étienne Esquirol et Wilhelm Griesinger — tenait pour pathologique. En l’attribuant aux sages, Nietzsche prépare son diagnostic : leur jugement n’exprime pas une vérité objective, mais un état morbide. ===== 2. Les dernières paroles de Socrate ===== ====== La source platonicienne ====== Nietzsche fait référence au ''Phédon'' de Platon (118a), où Socrate, après avoir bu la ciguë, prononce ses dernières paroles : « Ô Criton, nous devons un coq à Asclépios ; acquittez cette dette, n’y manquez pas » (traduction Schleiermacher). Asclépios (Esculape en latin) est le dieu grec de la médecine. Le coq était l’offrande traditionnelle qu’on lui faisait après une guérison. La phrase de Socrate signifie donc, littéralement, qu’il remercie Asclépios de l’avoir guéri d’une maladie. ====== L’interprétation nietzschéenne ====== Nietzsche reformule ces paroles de manière significative : « vivre — cela signifie être longtemps malade ». Cette paraphrase n’est pas dans le texte platonicien. Elle constitue une interprétation des derniers mots, selon laquelle la « maladie » dont Socrate se dit guéri n’est autre que la vie elle-même. Cette lecture n’est pas une invention de Nietzsche. Elle s’inscrit dans une tradition interprétative ancienne, remontant aux scholies d’Olympiodore (VI{{e}} siècle). Karl Steinhart, le professeur de grec de Nietzsche à Schulpforta, avait explicitement défendu cette interprétation dans ses annotations à la traduction des dialogues de Platon : « Socrate aussi se sent, à l’instant de mourir, guéri de la maladie de la vie terrestre et libéré des liens entravants du corps » (Steinhart 1854, 577). Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi 1994) et l’avait utilisée pour ses cours. En 1864, Steinhart l’avait recommandé à Karl Schaarschmidt comme « une nature profonde et rêveuse, passionnément attachée à la philosophie, notamment platonicienne, dans laquelle il est déjà assez initié » (KGB I 4, 338). ====== La reprise du ''Gai Savoir'' ====== Cette interprétation des dernières paroles de Socrate apparaît déjà dans ''Le Gai Savoir'' (§ 340), dans un passage intitulé « Socrate mourant » : {{Citation bloc|J'admire la bravoure et la sagesse de Socrate dans tout ce qu'il fit, dit — et ne dit pas. […] J'aurais voulu qu'il se fût tu aussi au dernier instant de sa vie — peut-être appartiendrait-il alors à un ordre d'esprits encore plus élevé. Était-ce la mort ou le poison ou la piété ou la méchanceté — quelque chose lui délia la langue en cet instant et il dit : "Ô Criton, je dois un coq à Asclépios." Ce "dernier mot" ridicule et terrible signifie, pour qui a des oreilles : "Ô Criton, la vie est une maladie !" Est-ce possible ! Un homme comme lui, qui avait vécu gaiement et comme un soldat aux yeux de tous — était pessimiste ! | FW 340, KSA 3, 569}} La différence entre les deux textes est instructive. Dans ''Le Gai Savoir'', Nietzsche exprime encore de l’admiration pour Socrate et se dit déçu par ses dernières paroles. Dans le ''Crépuscule'', l’admiration a disparu : Socrate n’est plus qu’un « décadent » parmi d’autres. ====== L’évolution de l’image de Socrate chez Nietzsche ====== Cette évolution peut se résumer ainsi : * Dans ''La Naissance de la tragédie'' (1872), Socrate est l’« archétype de l’optimiste théorique » (GT 15), le destructeur de la culture tragique grecque. Mais Nietzsche, alors sous l’influence de Schopenhauer, demeure encore proche d’un pessimisme qui valorise la négation du vouloir-vivre. * Dans ''Le Gai Savoir'' (1882), Socrate apparaît comme un pessimiste secret, ce qui le rapproche paradoxalement de Schopenhauer ; mais Nietzsche commence, en même temps, à prendre ses distances avec le pessimisme. * Dans le ''Crépuscule'' (1888), Socrate est désormais un « décadent » et un nihiliste, c’est-à-dire un négateur de la vie, que Nietzsche, devenu partisan d’une affirmation de l’existence, attaque de front. ===== 3. Le renversement herméneutique : du ''consensus sapientium'' au diagnostic de maladie ===== ====== Le ''consensus sapientium'' comme argument traditionnel ====== L’expression latine « consensus sapientium » (« accord des sages ») désigne un argument classique : l’unanimité des autorités intellectuelles sur un point constituerait une preuve de sa vérité. Cette idée remonte à la ''Topique'' d’Aristote (I 1, 100b 20 sq.), selon laquelle les opinions généralement admises (''endoxa''), même si elles ne sont pas des preuves au sens strict, peuvent être utiles à la recherche. Nietzsche avait déjà discuté ce concept dans ''Humain, trop humain'' (I, § 110), mais dans un autre sens. Il y citait le poème de Goethe ''Kophtisches Lied'' (1827) : « Alle die Weisesten aller der Zeiten / lächeln und winken und stimmen mit ein » (« Tous les très sages de tous les temps / sourient, font signe et acquiescent »). Dans ce passage antérieur, Nietzsche se rangeait du côté des sages contre le « ''consensus gentium'' » (accord des peuples), qu’il tenait pour un indice de sottise. Ici, au contraire, il retourne le soupçon contre les sages eux-mêmes : leur accord ne prouve pas leur vérité, mais leur maladie commune. ====== « Nos pessimistes » ====== L’expression « nos pessimistes » (''unsre Pessimisten'') désigne d’abord Schopenhauer et ses disciples. Les manuscrits préparatoires (cahiers W II 5, 50 et 51) nommaient explicitement Schopenhauer, que la version publiée a rendu anonyme (KSA 14, 413). Cette « déconcrétisation » (''Entkonkretisierung''), selon le terme d’Andreas Urs Sommer, déplace la critique : elle quitte la polémique contemporaine pour prendre la forme d’une affirmation générale. Schopenhauer avait fait du pessimisme le cœur de sa philosophie. Dans ''Le Monde comme volonté et représentation'' (livre IV, § 53-71), il soutenait que la vie est essentiellement souffrance et que la sagesse consiste dans la « négation du vouloir-vivre » (''Verneinung des Willens zum Leben''). Les dernières paroles de Socrate semblaient confirmer cette thèse : même le plus sage des hommes reconnaissait que la vie est une maladie. ====== Le renversement nietzschéen ====== Nietzsche inverse entièrement l’argument : * Position traditionnelle : les sages s’accordent à déprécier la vie ; cet accord prouve la vérité de leur jugement. * Position nietzschéenne : les sages s’accordent à déprécier la vie ; cet accord prouve qu’ils partagent une pathologie commune. Le passage du « vrai » (wahr) au « malade » (krank) est le pivot du texte. Nietzsche ne discute pas le contenu du jugement des sages (la vie vaut-elle ou non quelque chose ?) : il déplace la question vers les conditions de production de ce jugement. La méthode est généalogique : comprendre d’où vient une évaluation, plutôt que décider abstraitement si elle est vraie. ====== Le « nous » et les « Hyperboréens » ====== Le texte oppose un « on » (man) passé à un « nous » (wir) présent. Ce « nous » désigne ceux qui ont surmonté le pessimisme et pratiquent la « grande santé » (''die große Gesundheit''). Dans les manuscrits, ce groupe était identifié aux « Hyperboréens » ou aux « immoralistes » — termes par lesquels Nietzsche désigne des esprits libres capables d’affirmer la vie sans réserve. Les Hyperboréens, dans la mythologie grecque, étaient un peuple légendaire vivant au-delà du vent du nord (Borée), dans une contrée de félicité permanente. Nietzsche reprend ce terme dans l’ouverture de ''L’Antéchrist'' : « Regardons-nous en face. Nous sommes des Hyperboréens » (« Avant-propos »). ===== 4. L’image du corbeau et de la charogne ===== ====== La symbolique du corbeau ====== La section se clôt sur une image saisissante : « La sagesse n’apparaîtrait-elle pas sur terre comme un corbeau qu’une légère odeur de charogne met en joie ? » Le corbeau (''Rabe'') est un charognard. En l’associant à la sagesse philosophique, Nietzsche suggère que celle-ci se nourrit de ce qui est mort ou mourant. La philosophie serait attirée par la décomposition vitale comme le corbeau par les cadavres. Cette image opère une substitution symbolique révélatrice. L’emblème traditionnel de la philosophie est la chouette de Minerve (Athéna), oiseau de sagesse et de clairvoyance nocturne. Hegel, dans la préface des ''Principes de la philosophie du droit'' (1820), avait formulé cette image : « La chouette de Minerve ne prend son vol qu’à la tombée de la nuit. » Nietzsche remplace la chouette — oiseau noble, associé à la réflexion — par le corbeau — charognard, associé à la mort et à la putréfaction. ====== Les sources mythologiques ====== Le corbeau possède toutefois une symbolique ambivalente. Dans la mythologie nordique, les deux corbeaux Hugin et Munin (« Pensée » et « Mémoire ») accompagnent Odin et lui rapportent ce qui se passe dans le monde. Dans la ''Götterdämmerung'' de Wagner — dont le titre allemand est proche de celui du ''Crépuscule des idoles'' (''Götzen-Dämmerung'') —, les corbeaux d’Odin apparaissent à plusieurs reprises, notamment au moment où Hagen assassine Siegfried (acte III, scène 2). Jakob Grimm, dans sa ''Deutsche Mythologie'', que Nietzsche connaissait, notait la parenté entre le corbeau et le loup comme animaux sacrés d’Apollon — dieu de la clarté rationnelle. Cette ambivalence — le corbeau comme figure de la sagesse et comme charognard — est précisément ce que Nietzsche exploite pour suggérer que la « sagesse » philosophique est, en réalité, une attirance morbide pour ce qui décline. ====== L’odeur de charogne (''Aas'') ====== Le mot allemand « ''Aas'' » (charogne) est violent. Il évoque non seulement la mort, mais la décomposition, la puanteur, le dégoût. La vie que les philosophes jugent « sans valeur » n’est pas simplement niée : elle est présentée comme un cadavre dont la philosophie se repaît. Cette image prépare le diagnostic du chapitre : les philosophes ne jugent pas la vie de l’extérieur, en observateurs neutres ; ils sont eux-mêmes des organismes qui déclinent, attirés par ce qui leur ressemble. === § 2 : La valeur de la vie est-elle évaluable ? === Nietzsche pousse plus loin sa position : la question même de la valeur de la vie est illégitime. « La valeur de la vie ne peut pas être évaluée » (''Der Werth des Lebens kann nicht abgeschätzt werden''). Pourquoi ? Parce que le vivant est juge et partie : il ne peut s’extraire de la vie pour la juger objectivement. L’expression « valeur de la vie » (''Werth des Lebens'') fait écho au titre de l’ouvrage d’Eugen Dühring (''Der Werth des Lebens'', 1865), que Nietzsche avait longuement excerpté en 1875 (NL, KSA 8, 9[1]). Le soupçon se renverse alors : « Qu’un philosophe voie dans la valeur de la vie un problème constitue même une objection contre lui » (§ 2). Le pessimisme philosophique n’est pas une découverte métaphysique, mais un symptôme de décrépitude vitale. Nietzsche reprend ici l’une des thèses majeures de la ''Généalogie de la morale'' : les évaluations morales expriment des états physiologiques. === § 3 : Socrate et le « peuple » — laideur et basse extraction === Cette section introduit le motif de la laideur socratique, abondamment documenté dans les sources antiques (Platon, ''Banquet'' 215a-b ; Xénophon, ''Banquet'' IV, 19). Nietzsche écrit : « Socrate appartenait, par son origine, au plus bas peuple : Socrate était de la populace. On sait, on voit encore aujourd’hui combien il était laid » (''Sokrates gehörte, seiner Herkunft nach, zum niedersten Volk: Sokrates war Pöbel. Man weiss, man sieht es selbst noch, wie hässlich er war''). Le terme allemand « Pöbel » (populace) porte une charge péjorative que Nietzsche assume pleinement. Il s’appuie sur les travaux d’Eduard Zeller (''Die Philosophie der Griechen'', 1859), qui notait le contraste entre l’aspect extérieur de Socrate et l’idéal grec de l’harmonie entre corps et âme. Mais là où Zeller y voyait une tension intéressante, Nietzsche y lit un diagnostic : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation » (§ 3). Nietzsche mobilise ensuite l’anthropologie criminelle de son temps. Citant Féré, il affirme que « les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : ''monstrum in fronte, monstrum in animo'' » (« monstre au visage, monstre dans l’âme », § 3). Cette formule latine, que Nietzsche trouve chez Féré (1888, 80), provient elle-même de la tradition physiognomonique. L’application au cas de Socrate est délibérément provocatrice : Nietzsche retourne l’image traditionnelle du sage injustement condamné en suggérant qu’il portait les stigmates du criminel. {{Bas de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} {{AutoCat}} s2mwpnpt67rcm5klfprage5dzg0bjnh 768749 768748 2026-06-27T03:06:43Z PandaMystique 119061 768749 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} == Introduction : que signifie mettre Socrate en procès ? == Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l’interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' (''Götzen-Dämmerung''), intitulé « Le problème de Socrate » (''Das Problem des Sokrates''). Nietzsche y soumet le fondateur présumé de la philosophie occidentale à un examen sans ménagement : loin d’incarner l’apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d’une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s’inscrit dans une stratégie plus vaste : en brisant l’idole Socrate, Nietzsche entend ébranler l’édifice entier de la philosophie morale occidentale. == Contexte : genèse et place du chapitre dans l'œuvre == === Circonstances de rédaction === Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d’abord le titre « Sokrates als Problem » (« Socrate comme problème »), puis fut intégré à un projet plus large sur « la philosophie comme décadence » (KSA 14, 413). Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92], où Socrate est qualifié de « moment de la plus profonde perversité dans l’histoire de l’humanité ». === Continuité et ruptures avec les œuvres antérieures === La critique de Socrate traverse l’œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l’« Urbild des theoretischen Optimisten » (« archétype de l’optimiste théorique », GT 15). Nietzsche y opposait l’esprit dionysien, tragique et affirmatif, au rationalisme socratique, qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique prend une inflexion physiologique nouvelle : sous l’influence de lectures médicales récentes — notamment Charles Féré (''Dégénérescence et Criminalité'', 1888) et les travaux d’anthropologie criminelle de Lombroso —, Nietzsche pathologise Socrate. Le philosophe n’est plus seulement un adversaire intellectuel : il est un décadent, un malade, dont la pensée exprime un organisme en voie de décomposition. === La thèse centrale === Nietzsche soutient que la philosophie socratique — avec son équation « raison = vertu = bonheur » — constitue, non pas une conquête de l’esprit, mais le symptôme d’une dégénérescence (''Degenerescenz''). Les « instincts en anarchie » de Socrate l’auraient contraint à ériger la raison en tyran pour se dominer lui-même. Cette solution individuelle, étendue à toute une civilisation en déclin (l’Athènes du V{{e}} siècle), aurait inauguré deux millénaires de philosophie hostile à la vie. La décadence — terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui donner une portée physiologique — désigne ici la désagrégation des instincts vitaux et l’incapacité à affirmer l’existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === ==== Structure argumentative du passage ==== Cette première section remplit une fonction d’ouverture programmatique. Elle se déploie en quatre mouvements : * Le constat (lignes 1-4) énonce l’unanimité des sages sur la non-valeur de la vie. * L’exemple paradigmatique (lignes 4-6) s’appuie sur les dernières paroles de Socrate. * Le renversement herméneutique (lignes 6-10) transforme un argument d’autorité en symptôme de maladie. * L’image conclusive (lignes 10-11) figure la sagesse comme un corbeau attiré par la charogne. Cette structure mime un syllogisme apparent pour le retourner aussitôt : là où la tradition concluait à la vérité d’un jugement unanime, Nietzsche conclut à la pathologie commune des juges. ==== Analyse détaillée ==== ===== 1. Le jugement unanime des sages sur la vie ===== « De tout temps, les plus sages ont porté le même jugement : elle ne vaut rien » L’ouverture est brusque. Nietzsche ne commence pas par une question prudente, mais par une affirmation qui se donne pour un fait acquis. Le syntagme « de tout temps » (''zu allen Zeiten'') confère à l’énoncé une portée transhistorique : il ne s’agit pas d’une école particulière, mais d’un trait que Nietzsche présente comme constant de la sagesse philosophique depuis ses origines. L’expression « elle ne vaut rien » (''es taugt nichts'') mérite attention. Le verbe allemand « taugen » signifie « être bon à », « convenir », « avoir de la valeur ». La formule est volontairement triviale, presque grossière : Nietzsche fait parler les « sages » comme s’ils prononçaient un verdict de comptoir. Cette trivialisation prépare la dégradation ultérieure de leur prestige. ====== Les quatre tonalités du discours des sages ====== Nietzsche caractérise ce jugement par quatre attributs coordonnés : * « plein de doute » (''voll Zweifel'') ; * « plein de mélancolie » (''voll Schwermuth'') ; * « plein de lassitude de la vie » (''voll Müdigkeit am Leben'') ; * « plein de résistance contre la vie » (''voll Widerstand gegen das Leben''). Cette énumération dessine une progression : du doute intellectuel à la mélancolie affective, de la fatigue existentielle à l’hostilité active. Le « contre la vie » (''gegen das Leben'') final annonce le thème central du chapitre : la philosophie comme entreprise de négation vitale. Le terme « Schwermuth » (mélancolie) appartient au vocabulaire médico-psychologique du XIX{{e}} siècle. Il désigne un état dépressif que la psychiatrie de l’époque — notamment chez Jean-Étienne Esquirol et Wilhelm Griesinger — tenait pour pathologique. En l’attribuant aux sages, Nietzsche prépare son diagnostic : leur jugement n’exprime pas une vérité objective, mais un état morbide. ===== 2. Les dernières paroles de Socrate ===== ====== La source platonicienne ====== Nietzsche fait référence au ''Phédon'' de Platon (118a), où Socrate, après avoir bu la ciguë, prononce ses dernières paroles : « Ô Criton, nous devons un coq à Asclépios ; acquittez cette dette, n’y manquez pas » (traduction Schleiermacher). Asclépios (Esculape en latin) est le dieu grec de la médecine. Le coq était l’offrande traditionnelle qu’on lui faisait après une guérison. La phrase de Socrate signifie donc, littéralement, qu’il remercie Asclépios de l’avoir guéri d’une maladie. ====== L’interprétation nietzschéenne ====== Nietzsche reformule ces paroles de manière significative : « vivre — cela signifie être longtemps malade ». Cette paraphrase n’est pas dans le texte platonicien. Elle constitue une interprétation des derniers mots, selon laquelle la « maladie » dont Socrate se dit guéri n’est autre que la vie elle-même. Cette lecture n’est pas une invention de Nietzsche. Elle s’inscrit dans une tradition interprétative ancienne, remontant aux scholies d’Olympiodore (VI{{e}} siècle). Karl Steinhart, le professeur de grec de Nietzsche à Schulpforta, avait explicitement défendu cette interprétation dans ses annotations à la traduction des dialogues de Platon : « Socrate aussi se sent, à l’instant de mourir, guéri de la maladie de la vie terrestre et libéré des liens entravants du corps » (Steinhart 1854, 577). Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi 1994) et l’avait utilisée pour ses cours. En 1864, Steinhart l’avait recommandé à Karl Schaarschmidt comme « une nature profonde et rêveuse, passionnément attachée à la philosophie, notamment platonicienne, dans laquelle il est déjà assez initié » (KGB I 4, 338). ====== La reprise du ''Gai Savoir'' ====== Cette interprétation des dernières paroles de Socrate apparaît déjà dans ''Le Gai Savoir'' (§ 340), dans un passage intitulé « Socrate mourant » : {{Citation bloc|J'admire la bravoure et la sagesse de Socrate dans tout ce qu'il fit, dit — et ne dit pas. […] J'aurais voulu qu'il se fût tu aussi au dernier instant de sa vie — peut-être appartiendrait-il alors à un ordre d'esprits encore plus élevé. Était-ce la mort ou le poison ou la piété ou la méchanceté — quelque chose lui délia la langue en cet instant et il dit : "Ô Criton, je dois un coq à Asclépios." Ce "dernier mot" ridicule et terrible signifie, pour qui a des oreilles : "Ô Criton, la vie est une maladie !" Est-ce possible ! Un homme comme lui, qui avait vécu gaiement et comme un soldat aux yeux de tous — était pessimiste ! | FW 340, KSA 3, 569}} La différence entre les deux textes est instructive. Dans ''Le Gai Savoir'', Nietzsche exprime encore de l’admiration pour Socrate et se dit déçu par ses dernières paroles. Dans le ''Crépuscule'', l’admiration a disparu : Socrate n’est plus qu’un « décadent » parmi d’autres. ====== L’évolution de l’image de Socrate chez Nietzsche ====== Cette évolution peut se résumer ainsi : * Dans ''La Naissance de la tragédie'' (1872), Socrate est l’« archétype de l’optimiste théorique » (GT 15), le destructeur de la culture tragique grecque. Mais Nietzsche, alors sous l’influence de Schopenhauer, demeure encore proche d’un pessimisme qui valorise la négation du vouloir-vivre. * Dans ''Le Gai Savoir'' (1882), Socrate apparaît comme un pessimiste secret, ce qui le rapproche paradoxalement de Schopenhauer ; mais Nietzsche commence, en même temps, à prendre ses distances avec le pessimisme. * Dans le ''Crépuscule'' (1888), Socrate est désormais un « décadent » et un nihiliste, c’est-à-dire un négateur de la vie, que Nietzsche, devenu partisan d’une affirmation de l’existence, attaque de front. ===== 3. Le renversement herméneutique : du ''consensus sapientium'' au diagnostic de maladie ===== ====== Le ''consensus sapientium'' comme argument traditionnel ====== L’expression latine « consensus sapientium » (« accord des sages ») désigne un argument classique : l’unanimité des autorités intellectuelles sur un point constituerait une preuve de sa vérité. Cette idée remonte à la ''Topique'' d’Aristote (I 1, 100b 20 sq.), selon laquelle les opinions généralement admises (''endoxa''), même si elles ne sont pas des preuves au sens strict, peuvent être utiles à la recherche. Nietzsche avait déjà discuté ce concept dans ''Humain, trop humain'' (I, § 110), mais dans un autre sens. Il y citait le poème de Goethe ''Kophtisches Lied'' (1827) : « Alle die Weisesten aller der Zeiten / lächeln und winken und stimmen mit ein » (« Tous les très sages de tous les temps / sourient, font signe et acquiescent »). Dans ce passage antérieur, Nietzsche se rangeait du côté des sages contre le « ''consensus gentium'' » (accord des peuples), qu’il tenait pour un indice de sottise. Ici, au contraire, il retourne le soupçon contre les sages eux-mêmes : leur accord ne prouve pas leur vérité, mais leur maladie commune. ====== « Nos pessimistes » ====== L’expression « nos pessimistes » (''unsre Pessimisten'') désigne d’abord Schopenhauer et ses disciples. Les manuscrits préparatoires (cahiers W II 5, 50 et 51) nommaient explicitement Schopenhauer, que la version publiée a rendu anonyme (KSA 14, 413). Cette « déconcrétisation » (''Entkonkretisierung''), selon le terme d’Andreas Urs Sommer, déplace la critique : elle quitte la polémique contemporaine pour prendre la forme d’une affirmation générale. Schopenhauer avait fait du pessimisme le cœur de sa philosophie. Dans ''Le Monde comme volonté et représentation'' (livre IV, § 53-71), il soutenait que la vie est essentiellement souffrance et que la sagesse consiste dans la « négation du vouloir-vivre » (''Verneinung des Willens zum Leben''). Les dernières paroles de Socrate semblaient confirmer cette thèse : même le plus sage des hommes reconnaissait que la vie est une maladie. ====== Le renversement nietzschéen ====== Nietzsche inverse entièrement l’argument : * Position traditionnelle : les sages s’accordent à déprécier la vie ; cet accord prouve la vérité de leur jugement. * Position nietzschéenne : les sages s’accordent à déprécier la vie ; cet accord prouve qu’ils partagent une pathologie commune. Le passage du « vrai » (wahr) au « malade » (krank) est le pivot du texte. Nietzsche ne discute pas le contenu du jugement des sages (la vie vaut-elle ou non quelque chose ?) : il déplace la question vers les conditions de production de ce jugement. La méthode est généalogique : comprendre d’où vient une évaluation, plutôt que décider abstraitement si elle est vraie. ====== Le « nous » et les « Hyperboréens » ====== Le texte oppose un « on » (man) passé à un « nous » (wir) présent. Ce « nous » désigne ceux qui ont surmonté le pessimisme et pratiquent la « grande santé » (''die große Gesundheit''). Dans les manuscrits, ce groupe était identifié aux « Hyperboréens » ou aux « immoralistes » — termes par lesquels Nietzsche désigne des esprits libres capables d’affirmer la vie sans réserve. Les Hyperboréens, dans la mythologie grecque, étaient un peuple légendaire vivant au-delà du vent du nord (Borée), dans une contrée de félicité permanente. Nietzsche reprend ce terme dans l’ouverture de ''L’Antéchrist'' : « Regardons-nous en face. Nous sommes des Hyperboréens » (« Avant-propos »). ===== 4. L’image du corbeau et de la charogne ===== ====== La symbolique du corbeau ====== La section se clôt sur une image saisissante : « La sagesse n’apparaîtrait-elle pas sur terre comme un corbeau qu’une légère odeur de charogne met en joie ? » Le corbeau (''Rabe'') est un charognard. En l’associant à la sagesse philosophique, Nietzsche suggère que celle-ci se nourrit de ce qui est mort ou mourant. La philosophie serait attirée par la décomposition vitale comme le corbeau par les cadavres. Cette image opère une substitution symbolique révélatrice. L’emblème traditionnel de la philosophie est la chouette de Minerve (Athéna), oiseau de sagesse et de clairvoyance nocturne. Hegel, dans la préface des ''Principes de la philosophie du droit'' (1820), avait formulé cette image : « La chouette de Minerve ne prend son vol qu’à la tombée de la nuit. » Nietzsche remplace la chouette — oiseau noble, associé à la réflexion — par le corbeau — charognard, associé à la mort et à la putréfaction. ====== Les sources mythologiques ====== Le corbeau possède toutefois une symbolique ambivalente. Dans la mythologie nordique, les deux corbeaux Hugin et Munin (« Pensée » et « Mémoire ») accompagnent Odin et lui rapportent ce qui se passe dans le monde. Dans la ''Götterdämmerung'' de Wagner — dont le titre allemand est proche de celui du ''Crépuscule des idoles'' (''Götzen-Dämmerung'') —, les corbeaux d’Odin apparaissent à plusieurs reprises, notamment au moment où Hagen assassine Siegfried (acte III, scène 2). Jakob Grimm, dans sa ''Deutsche Mythologie'', que Nietzsche connaissait, notait la parenté entre le corbeau et le loup comme animaux sacrés d’Apollon — dieu de la clarté rationnelle. Cette ambivalence — le corbeau comme figure de la sagesse et comme charognard — est précisément ce que Nietzsche exploite pour suggérer que la « sagesse » philosophique est, en réalité, une attirance morbide pour ce qui décline. ====== L’odeur de charogne (''Aas'') ====== Le mot allemand « ''Aas'' » (charogne) est violent. Il évoque non seulement la mort, mais la décomposition, la puanteur, le dégoût. La vie que les philosophes jugent « sans valeur » n’est pas simplement niée : elle est présentée comme un cadavre dont la philosophie se repaît. Cette image prépare le diagnostic du chapitre : les philosophes ne jugent pas la vie de l’extérieur, en observateurs neutres ; ils sont eux-mêmes des organismes qui déclinent, attirés par ce qui leur ressemble. === § 2 : La valeur de la vie est-elle évaluable ? === Nietzsche pousse plus loin sa position : la question même de la valeur de la vie est illégitime. « La valeur de la vie ne peut pas être évaluée » (''Der Werth des Lebens kann nicht abgeschätzt werden''). Pourquoi ? Parce que le vivant est juge et partie : il ne peut s’extraire de la vie pour la juger objectivement. L’expression « valeur de la vie » (''Werth des Lebens'') fait écho au titre de l’ouvrage d’Eugen Dühring (''Der Werth des Lebens'', 1865), que Nietzsche avait longuement excerpté en 1875 (NL, KSA 8, 9[1]). Le soupçon se renverse alors : « Qu’un philosophe voie dans la valeur de la vie un problème constitue même une objection contre lui » (§ 2). Le pessimisme philosophique n’est pas une découverte métaphysique, mais un symptôme de décrépitude vitale. Nietzsche reprend ici l’une des thèses majeures de la ''Généalogie de la morale'' : les évaluations morales expriment des états physiologiques. === § 3 : Socrate et le « peuple » — laideur et basse extraction === Cette section introduit le motif de la laideur socratique, abondamment documenté dans les sources antiques (Platon, ''Banquet'' 215a-b ; Xénophon, ''Banquet'' IV, 19). Nietzsche écrit : « Socrate appartenait, par son origine, au plus bas peuple : Socrate était de la populace. On sait, on voit encore aujourd’hui combien il était laid » (''Sokrates gehörte, seiner Herkunft nach, zum niedersten Volk: Sokrates war Pöbel. Man weiss, man sieht es selbst noch, wie hässlich er war''). Le terme allemand « Pöbel » (populace) porte une charge péjorative que Nietzsche assume pleinement. Il s’appuie sur les travaux d’Eduard Zeller (''Die Philosophie der Griechen'', 1859), qui notait le contraste entre l’aspect extérieur de Socrate et l’idéal grec de l’harmonie entre corps et âme. Mais là où Zeller y voyait une tension intéressante, Nietzsche y lit un diagnostic : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation » (§ 3). Nietzsche mobilise ensuite l’anthropologie criminelle de son temps. Citant Féré, il affirme que « les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : ''monstrum in fronte, monstrum in animo'' » (« monstre au visage, monstre dans l’âme », § 3). Cette formule latine, que Nietzsche trouve chez Féré (1888, 80), provient elle-même de la tradition physiognomonique. L’application au cas de Socrate est délibérément provocatrice : Nietzsche retourne l’image traditionnelle du sage injustement condamné en suggérant qu’il portait les stigmates du criminel. {{Bas de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} {{AutoCat}} 6rkpypgyoybhdb1z25ui3h1dd6mvoqu 768750 768749 2026-06-27T03:39:20Z PandaMystique 119061 768750 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} == Introduction : que signifie mettre Socrate en procès ? == Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l’interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' (''Götzen-Dämmerung''), intitulé « Le problème de Socrate » (''Das Problem des Sokrates''). Nietzsche y soumet le fondateur présumé de la philosophie occidentale à un examen sans ménagement : loin d’incarner l’apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d’une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s’inscrit dans une stratégie plus vaste : en brisant l’idole Socrate, Nietzsche entend ébranler l’édifice entier de la philosophie morale occidentale. == Contexte : genèse et place du chapitre dans l'œuvre == === Circonstances de rédaction === Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d’abord le titre « Sokrates als Problem » (« Socrate comme problème »), puis fut intégré à un projet plus large sur « la philosophie comme décadence » (KSA 14, 413). Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92], où Socrate est qualifié de « moment de la plus profonde perversité dans l’histoire de l’humanité ». === Continuité et ruptures avec les œuvres antérieures === La critique de Socrate traverse l’œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l’« Urbild des theoretischen Optimisten » (« archétype de l’optimiste théorique », GT 15). Nietzsche y opposait l’esprit dionysien, tragique et affirmatif, au rationalisme socratique, qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique prend une inflexion physiologique nouvelle : sous l’influence de lectures médicales récentes — notamment Charles Féré (''Dégénérescence et Criminalité'', 1888) et les travaux d’anthropologie criminelle de Lombroso —, Nietzsche pathologise Socrate. Le philosophe n’est plus seulement un adversaire intellectuel : il est un décadent, un malade, dont la pensée exprime un organisme en voie de décomposition. === La thèse centrale === Nietzsche soutient que la philosophie socratique — avec son équation « raison = vertu = bonheur » — constitue, non pas une conquête de l’esprit, mais le symptôme d’une dégénérescence (''Degenerescenz''). Les « instincts en anarchie » de Socrate l’auraient contraint à ériger la raison en tyran pour se dominer lui-même. Cette solution individuelle, étendue à toute une civilisation en déclin (l’Athènes du V{{e}} siècle), aurait inauguré deux millénaires de philosophie hostile à la vie. La décadence — terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui donner une portée physiologique — désigne ici la désagrégation des instincts vitaux et l’incapacité à affirmer l’existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === ==== Structure argumentative du passage ==== Cette première section remplit une fonction d’ouverture programmatique. Elle se déploie en quatre mouvements : * Le constat (lignes 1-4) énonce l’unanimité des sages sur la non-valeur de la vie. * L’exemple paradigmatique (lignes 4-6) s’appuie sur les dernières paroles de Socrate. * Le renversement herméneutique (lignes 6-10) transforme un argument d’autorité en symptôme de maladie. * L’image conclusive (lignes 10-11) figure la sagesse comme un corbeau attiré par la charogne. Cette structure mime un syllogisme apparent pour le retourner aussitôt : là où la tradition concluait à la vérité d’un jugement unanime, Nietzsche conclut à la pathologie commune des juges. ==== Analyse détaillée ==== ===== 1. Le jugement unanime des sages sur la vie ===== « De tout temps, les plus sages ont porté le même jugement : elle ne vaut rien » L’ouverture est brusque. Nietzsche ne commence pas par une question prudente, mais par une affirmation qui se donne pour un fait acquis. Le syntagme « de tout temps » (''zu allen Zeiten'') confère à l’énoncé une portée transhistorique : il ne s’agit pas d’une école particulière, mais d’un trait que Nietzsche présente comme constant de la sagesse philosophique depuis ses origines. L’expression « elle ne vaut rien » (''es taugt nichts'') mérite attention. Le verbe allemand « taugen » signifie « être bon à », « convenir », « avoir de la valeur ». La formule est volontairement triviale, presque grossière : Nietzsche fait parler les « sages » comme s’ils prononçaient un verdict de comptoir. Cette trivialisation prépare la dégradation ultérieure de leur prestige. ====== Les quatre tonalités du discours des sages ====== Nietzsche caractérise ce jugement par quatre attributs coordonnés : * « plein de doute » (''voll Zweifel'') ; * « plein de mélancolie » (''voll Schwermuth'') ; * « plein de lassitude de la vie » (''voll Müdigkeit am Leben'') ; * « plein de résistance contre la vie » (''voll Widerstand gegen das Leben''). Cette énumération dessine une progression : du doute intellectuel à la mélancolie affective, de la fatigue existentielle à l’hostilité active. Le « contre la vie » (''gegen das Leben'') final annonce le thème central du chapitre : la philosophie comme entreprise de négation vitale. Le terme « Schwermuth » (mélancolie) appartient au vocabulaire médico-psychologique du XIX{{e}} siècle. Il désigne un état dépressif que la psychiatrie de l’époque — notamment chez Jean-Étienne Esquirol et Wilhelm Griesinger — tenait pour pathologique. En l’attribuant aux sages, Nietzsche prépare son diagnostic : leur jugement n’exprime pas une vérité objective, mais un état morbide. ===== 2. Les dernières paroles de Socrate ===== ====== La source platonicienne ====== Nietzsche fait référence au ''Phédon'' de Platon (118a), où Socrate, après avoir bu la ciguë, prononce ses dernières paroles : « Ô Criton, nous devons un coq à Asclépios ; acquittez cette dette, n’y manquez pas » (traduction Schleiermacher). Asclépios (Esculape en latin) est le dieu grec de la médecine. Le coq était l’offrande traditionnelle qu’on lui faisait après une guérison. La phrase de Socrate signifie donc, littéralement, qu’il remercie Asclépios de l’avoir guéri d’une maladie. ====== L’interprétation nietzschéenne ====== Nietzsche reformule ces paroles de manière significative : « vivre — cela signifie être longtemps malade ». Cette paraphrase n’est pas dans le texte platonicien. Elle constitue une interprétation des derniers mots, selon laquelle la « maladie » dont Socrate se dit guéri n’est autre que la vie elle-même. Cette lecture n’est pas une invention de Nietzsche. Elle s’inscrit dans une tradition interprétative ancienne, remontant aux scholies d’Olympiodore (VI{{e}} siècle). Karl Steinhart, le professeur de grec de Nietzsche à Schulpforta, avait explicitement défendu cette interprétation dans ses annotations à la traduction des dialogues de Platon : « Socrate aussi se sent, à l’instant de mourir, guéri de la maladie de la vie terrestre et libéré des liens entravants du corps » (Steinhart 1854, 577). Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi 1994) et l’avait utilisée pour ses cours. En 1864, Steinhart l’avait recommandé à Karl Schaarschmidt comme « une nature profonde et rêveuse, passionnément attachée à la philosophie, notamment platonicienne, dans laquelle il est déjà assez initié » (KGB I 4, 338). ====== La reprise du ''Gai Savoir'' ====== Cette interprétation des dernières paroles de Socrate apparaît déjà dans ''Le Gai Savoir'' (§ 340), dans un passage intitulé « Socrate mourant » : {{Citation bloc|J'admire la bravoure et la sagesse de Socrate dans tout ce qu'il fit, dit — et ne dit pas. […] J'aurais voulu qu'il se fût tu aussi au dernier instant de sa vie — peut-être appartiendrait-il alors à un ordre d'esprits encore plus élevé. Était-ce la mort ou le poison ou la piété ou la méchanceté — quelque chose lui délia la langue en cet instant et il dit : "Ô Criton, je dois un coq à Asclépios." Ce "dernier mot" ridicule et terrible signifie, pour qui a des oreilles : "Ô Criton, la vie est une maladie !" Est-ce possible ! Un homme comme lui, qui avait vécu gaiement et comme un soldat aux yeux de tous — était pessimiste ! | FW 340, KSA 3, 569}} La différence entre les deux textes est instructive. Dans ''Le Gai Savoir'', Nietzsche exprime encore de l’admiration pour Socrate et se dit déçu par ses dernières paroles. Dans le ''Crépuscule'', l’admiration a disparu : Socrate n’est plus qu’un « décadent » parmi d’autres. ====== L’évolution de l’image de Socrate chez Nietzsche ====== Cette évolution peut se résumer ainsi : * Dans ''La Naissance de la tragédie'' (1872), Socrate est l’« archétype de l’optimiste théorique » (GT 15), le destructeur de la culture tragique grecque. Mais Nietzsche, alors sous l’influence de Schopenhauer, demeure encore proche d’un pessimisme qui valorise la négation du vouloir-vivre. * Dans ''Le Gai Savoir'' (1882), Socrate apparaît comme un pessimiste secret, ce qui le rapproche paradoxalement de Schopenhauer ; mais Nietzsche commence, en même temps, à prendre ses distances avec le pessimisme. * Dans le ''Crépuscule'' (1888), Socrate est désormais un « décadent » et un nihiliste, c’est-à-dire un négateur de la vie, que Nietzsche, devenu partisan d’une affirmation de l’existence, attaque de front. ===== 3. Le renversement herméneutique : du ''consensus sapientium'' au diagnostic de maladie ===== ====== Le ''consensus sapientium'' comme argument traditionnel ====== L’expression latine « consensus sapientium » (« accord des sages ») désigne un argument classique : l’unanimité des autorités intellectuelles sur un point constituerait une preuve de sa vérité. Cette idée remonte à la ''Topique'' d’Aristote (I 1, 100b 20 sq.), selon laquelle les opinions généralement admises (''endoxa''), même si elles ne sont pas des preuves au sens strict, peuvent être utiles à la recherche. Nietzsche avait déjà discuté ce concept dans ''Humain, trop humain'' (I, § 110), mais dans un autre sens. Il y citait le poème de Goethe ''Kophtisches Lied'' (1827) : « Alle die Weisesten aller der Zeiten / lächeln und winken und stimmen mit ein » (« Tous les très sages de tous les temps / sourient, font signe et acquiescent »). Dans ce passage antérieur, Nietzsche se rangeait du côté des sages contre le « ''consensus gentium'' » (accord des peuples), qu’il tenait pour un indice de sottise. Ici, au contraire, il retourne le soupçon contre les sages eux-mêmes : leur accord ne prouve pas leur vérité, mais leur maladie commune. ====== « Nos pessimistes » ====== L’expression « nos pessimistes » (''unsre Pessimisten'') désigne d’abord Schopenhauer et ses disciples. Les manuscrits préparatoires (cahiers W II 5, 50 et 51) nommaient explicitement Schopenhauer, que la version publiée a rendu anonyme (KSA 14, 413). Cette « déconcrétisation » (''Entkonkretisierung''), selon le terme d’Andreas Urs Sommer, déplace la critique : elle quitte la polémique contemporaine pour prendre la forme d’une affirmation générale. Schopenhauer avait fait du pessimisme le cœur de sa philosophie. Dans ''Le Monde comme volonté et représentation'' (livre IV, § 53-71), il soutenait que la vie est essentiellement souffrance et que la sagesse consiste dans la « négation du vouloir-vivre » (''Verneinung des Willens zum Leben''). Les dernières paroles de Socrate semblaient confirmer cette thèse : même le plus sage des hommes reconnaissait que la vie est une maladie. ====== Le renversement nietzschéen ====== Nietzsche inverse entièrement l’argument : * Position traditionnelle : les sages s’accordent à déprécier la vie ; cet accord prouve la vérité de leur jugement. * Position nietzschéenne : les sages s’accordent à déprécier la vie ; cet accord prouve qu’ils partagent une pathologie commune. Le passage du « vrai » (wahr) au « malade » (krank) est le pivot du texte. Nietzsche ne discute pas le contenu du jugement des sages (la vie vaut-elle ou non quelque chose ?) : il déplace la question vers les conditions de production de ce jugement. La méthode est généalogique : comprendre d’où vient une évaluation, plutôt que décider abstraitement si elle est vraie. ====== Le « nous » et les « Hyperboréens » ====== Le texte oppose un « on » (man) passé à un « nous » (wir) présent. Ce « nous » désigne ceux qui ont surmonté le pessimisme et pratiquent la « grande santé » (''die große Gesundheit''). Dans les manuscrits, ce groupe était identifié aux « Hyperboréens » ou aux « immoralistes » — termes par lesquels Nietzsche désigne des esprits libres capables d’affirmer la vie sans réserve. Les Hyperboréens, dans la mythologie grecque, étaient un peuple légendaire vivant au-delà du vent du nord (Borée), dans une contrée de félicité permanente. Nietzsche reprend ce terme dans l’ouverture de ''L’Antéchrist'' : « Regardons-nous en face. Nous sommes des Hyperboréens » (« Avant-propos »). ===== 4. L’image du corbeau et de la charogne ===== ====== La symbolique du corbeau ====== La section se clôt sur une image saisissante : « La sagesse n’apparaîtrait-elle pas sur terre comme un corbeau qu’une légère odeur de charogne met en joie ? » Le corbeau (''Rabe'') est un charognard. En l’associant à la sagesse philosophique, Nietzsche suggère que celle-ci se nourrit de ce qui est mort ou mourant. La philosophie serait attirée par la décomposition vitale comme le corbeau par les cadavres. Cette image opère une substitution symbolique révélatrice. L’emblème traditionnel de la philosophie est la chouette de Minerve (Athéna), oiseau de sagesse et de clairvoyance nocturne. Hegel, dans la préface des ''Principes de la philosophie du droit'' (1820), avait formulé cette image : « La chouette de Minerve ne prend son vol qu’à la tombée de la nuit. » Nietzsche remplace la chouette — oiseau noble, associé à la réflexion — par le corbeau — charognard, associé à la mort et à la putréfaction. ====== Les sources mythologiques ====== Le corbeau possède toutefois une symbolique ambivalente. Dans la mythologie nordique, les deux corbeaux Hugin et Munin (« Pensée » et « Mémoire ») accompagnent Odin et lui rapportent ce qui se passe dans le monde. Dans la ''Götterdämmerung'' de Wagner — dont le titre allemand est proche de celui du ''Crépuscule des idoles'' (''Götzen-Dämmerung'') —, les corbeaux d’Odin apparaissent à plusieurs reprises, notamment au moment où Hagen assassine Siegfried (acte III, scène 2). Jakob Grimm, dans sa ''Deutsche Mythologie'', que Nietzsche connaissait, notait la parenté entre le corbeau et le loup comme animaux sacrés d’Apollon — dieu de la clarté rationnelle. Cette ambivalence — le corbeau comme figure de la sagesse et comme charognard — est précisément ce que Nietzsche exploite pour suggérer que la « sagesse » philosophique est, en réalité, une attirance morbide pour ce qui décline. ====== L’odeur de charogne (''Aas'') ====== Le mot allemand « ''Aas'' » (charogne) est violent. Il évoque non seulement la mort, mais la décomposition, la puanteur, le dégoût. La vie que les philosophes jugent « sans valeur » n’est pas simplement niée : elle est présentée comme un cadavre dont la philosophie se repaît. Cette image prépare le diagnostic du chapitre : les philosophes ne jugent pas la vie de l’extérieur, en observateurs neutres ; ils sont eux-mêmes des organismes qui déclinent, attirés par ce qui leur ressemble. === § 2 : La valeur de la vie est-elle évaluable ? === Nietzsche pousse plus loin sa position : la question même de la valeur de la vie est illégitime. « La valeur de la vie ne peut pas être évaluée » (''Der Werth des Lebens kann nicht abgeschätzt werden''). Pourquoi ? Parce que le vivant est juge et partie : il ne peut s’extraire de la vie pour la juger objectivement. L’expression « valeur de la vie » (''Werth des Lebens'') fait écho au titre de l’ouvrage d’Eugen Dühring (''Der Werth des Lebens'', 1865), que Nietzsche avait longuement excerpté en 1875 (NL, KSA 8, 9[1]). Le soupçon se renverse alors : « Qu’un philosophe voie dans la valeur de la vie un problème constitue même une objection contre lui » (§ 2). Le pessimisme philosophique n’est pas une découverte métaphysique, mais un symptôme de décrépitude vitale. Nietzsche reprend ici l’une des thèses majeures de la ''Généalogie de la morale'' : les évaluations morales expriment des états physiologiques. === § 3 : Socrate et le « peuple » — laideur et basse extraction === Cette section introduit le motif de la laideur socratique, abondamment documenté dans les sources antiques (Platon, ''Banquet'' 215a-b ; Xénophon, ''Banquet'' IV, 19). Nietzsche écrit : « Socrate appartenait, par son origine, au plus bas peuple : Socrate était de la populace. On sait, on voit encore aujourd’hui combien il était laid » (''Sokrates gehörte, seiner Herkunft nach, zum niedersten Volk: Sokrates war Pöbel. Man weiss, man sieht es selbst noch, wie hässlich er war''). Le terme allemand « Pöbel » (populace) porte une charge péjorative que Nietzsche assume pleinement. Il s’appuie sur les travaux d’Eduard Zeller (''Die Philosophie der Griechen'', 1859), qui notait le contraste entre l’aspect extérieur de Socrate et l’idéal grec de l’harmonie entre corps et âme. Mais là où Zeller y voyait une tension intéressante, Nietzsche y lit un diagnostic : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation » (§ 3). Nietzsche mobilise ensuite l’anthropologie criminelle de son temps. Citant Féré, il affirme que « les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : ''monstrum in fronte, monstrum in animo'' » (« monstre au visage, monstre dans l’âme », § 3). Cette formule latine, que Nietzsche trouve chez Féré (1888, 80), provient elle-même de la tradition physiognomonique. L’application au cas de Socrate est délibérément provocatrice : Nietzsche retourne l’image traditionnelle du sage injustement condamné en suggérant qu’il portait les stigmates du criminel. === § 4 : Les signes de la décadence et l'équation socratique === Ce paragraphe énumère les signes de la décadence socratique qui s'ajoutent à la laideur. {{Citation bloc|La décadence de Socrate ne se trahit pas seulement par l'anarchie avouée de ses instincts : elle se trahit aussi par la superfétation du logique [{{lang|de|''Superfötation des Logischen''}}] et par cette malveillance bilieuse qui le distingue.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;4 ; KSA 6, {{p.|69}}. La référence éditoriale renvoie à Friedrich Nietzsche, {{lang|de|''Sämtliche Werke. Kritische Studienausgabe''}} (KSA), éd. G. Colli et M. Montinari, Berlin/Munich, De Gruyter/dtv, 1980.</ref>}} Le terme « superfétation » est emprunté à la médecine (une seconde conception survenant au cours d'une grossesse) : Nietzsche suggère que la faculté logique est pathologiquement surdéveloppée, hypertrophiée. Andreas Urs Sommer note que ce rapprochement entre la « superfétation » et le démon socratique figurait déjà dans ''La Naissance de la tragédie'' (§&nbsp;13). Nietzsche médicalise ensuite le fameux ''daimonion'' : {{Citation|N'oublions pas non plus ces hallucinations auditives qui, sous le nom de « démon de Socrate », ont reçu une interprétation religieuse.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;4 ; KSA 6, {{p.|69}}.</ref> La source en est Francis Galton, qui rangeait Socrate parmi les sujets prédisposés aux crises nerveuses et aux hallucinations<ref>Francis Galton, ''Inquiries into Human Faculty and its Development'', Londres, Macmillan, 1883.</ref>. Tout, chez Socrate, serait « exagéré, ''buffo'', caricature ». Le paragraphe s'achève sur la première formulation de l'équation centrale : {{Citation bloc|1=Je cherche à comprendre de quelle idiosyncrasie [{{lang|de|''Idiosynkrasie''}}] procède cette équation socratique, raison = vertu = bonheur : la plus bizarre de toutes les équations, qui a contre elle en particulier tous les instincts de l'ancien Hellène.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;4 ; KSA 6, {{p.|69}}.</ref>}} Le terme « idiosyncrasie », médical, désigne une constitution organique singulière : la philosophie socratique exprime une pathologie individuelle, non une vérité universelle. Les manuscrits consignent une équation alternative, antérieure à Socrate<ref>Variante des manuscrits préparatoires (Mp XVI 4) : {{lang|de|1=''Tugend = Instinkt = Grund-Unbewußtheit''}} (« vertu = instinct = inconscience fondamentale »), KSA 14, {{pp.|413-414}}.</ref>. === § 5 : La dialectique comme défaite du goût aristocratique === Nietzsche aborde ici la dialectique et observe un renversement du goût : {{Citation|Avec Socrate, le goût grec bascule en faveur de la dialectique : que se passe-t-il là au juste ? Avant tout, un goût distingué s'en trouve vaincu ; avec la dialectique, la populace l'emporte.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;5 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''der Pöbel kommt mit der Dialektik obenauf''}}.</ref> Avant Socrate, « on rejetait dans la bonne société les manières dialectiques ; elles passaient pour de mauvaises manières, elles compromettaient ». L'homme bien né n'a pas besoin de prouver : il possède l'autorité. {{Citation|Il est indécent de montrer ses cinq doigts. Ce qui a besoin d'abord d'être prouvé n'a que peu de valeur.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;5 ; KSA 6, {{p.|70}}.</ref> L'expression « étalage de raisons » ({{lang|de|''Etalage von Gründen''}}) emploie un gallicisme que Nietzsche affectionne. La dialectique se présente comme l'arme de qui ne dispose pas de l'autorité naturelle. === § 6 : La dialectique comme légitime défense === Nietzsche resserre : {{Citation|La dialectique ne peut être qu'une légitime défense.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;6 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Nothwehr''}}.</ref> Elle est l'arme de ceux qui n'en ont pas d'autre. Les variantes manuscrites contenaient une remarque sur les Juifs comme dialecticiens, que la version publiée supprime, témoignant d'un travail de révision<ref>Variante du cahier W II 5, 85 (KGW IX 8), supprimée dans la version définitive.</ref>. La comparaison avec ''Reineke Fuchs'' (le goupil rusé de l'épopée de Goethe) éclaire le propos : comme le renard qui échappe deux fois à la mort par ses discours « dialectiques », Socrate compense par la ruse argumentative une infériorité de position<ref>{{lang|de|''Reineke Fuchs''}} (1794). Sur la connaissance qu'en avait Nietzsche, voir le commentaire de Sommer, qui renvoie à Victor Hehn (1888).</ref>. === § 7 : L'ironie socratique comme ressentiment === Cette section traite de l'ironie : {{Citation|L'ironie de Socrate est-elle une expression de révolte [{{lang|de|''Ausdruck von Revolte''}}] ? un ressentiment de la populace [{{lang|de|''Pöbel-Ressentiment''}}] ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;7 ; KSA 6, {{p.|70}}.</ref> Le terme « ressentiment », que Nietzsche écrit en français, est l'un des concepts clés de la ''Généalogie de la morale'' : le mécanisme par lequel les faibles, incapables d'agir, se vengent symboliquement par une inversion des valeurs<ref>Voir ''Généalogie de la morale'', première dissertation, §&nbsp;10 ; KSA 5, {{pp.|270-273}}.</ref>. La formule de Nietzsche est tranchante : {{Citation|L'ironie du dialecticien est la férocité de la vengeance plébéienne [{{lang|de|''die Ferocität der Pöbel-Rache''}}] : les opprimés ont leur férocité dans les froids coups de couteau du syllogisme.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;7 ; KSA 6, {{p.|70}}.</ref> Le mécanisme est précisé : {{Citation|Le dialecticien laisse à son adversaire le soin de prouver qu'il n'est pas un idiot ; il le rend furieux et impuissant à la fois. Le dialecticien dépotentialise [{{lang|de|''depotenzirt''}}] l'intellect de son adversaire.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;7 ; KSA 6, {{p.|70}}.</ref> La dialectique ne convainc pas : elle neutralise. === § 8 : Socrate « érotique » === Brève section qui introduit une dimension inattendue : {{Citation|Socrate était aussi un grand érotique.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;8 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Sokrates war auch ein grosser Erotiker''}}.</ref> L'allusion au rôle de Socrate dans le ''Banquet'' de Platon est transparente. Nietzsche suggère que la dialectique fonctionnait comme une nouvelle forme d’''agôn'' (compétition). Là où Eduard Zeller, puis Franz Susemihl, spiritualisaient l'éros socratique, Nietzsche réintroduit l'élément sensuel et pédérastique que la tradition académique tendait à occulter<ref>Franz Susemihl, « {{lang|de|Ueber die composition des platonischen gastmahls}} », ''{{lang|de|Philologus}}'', 1851 ; Eduard Zeller, ''{{lang|de|Die Philosophie der Griechen}}'', 2{{e}} partie, Tübingen, 1859.</ref>. === § 9 : Socrate, témoin lucide du déclin === La section opère un renversement partiel : Socrate n'est plus seulement l'agent du déclin, il en est le témoin clairvoyant. {{Citation bloc|Il regarda derrière ses nobles Athéniens ; il comprit que son cas, son idiosyncrasie de cas, n'était déjà plus un cas exceptionnel. La même espèce de dégénérescence [{{lang|de|''Degenerescenz''}}] se préparait partout en silence : le vieil Athènes touchait à sa fin.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;9 ; KSA 6, {{p.|71}}.</ref>}} Nietzsche lui reconnaît une lucidité diagnostique : {{Citation|Partout les instincts étaient en anarchie ; partout on était à cinq pas de l'excès.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''fünf Schritt weit vom Excess''}}.</ref> Le paragraphe reprend l'anecdote du physiognomoniste sous une seconde version, plus proche de la tradition cicéronienne : {{Citation|C'est vrai, dit-il, mais je suis devenu maître de toutes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Dies ist wahr, aber ich wurde über alle Herr''}}.</ref> Les deux répliques que Nietzsche prête à Socrate (« Vous me connaissez, Monsieur ! » au §&nbsp;3, « je suis devenu maître de toutes » ici) renvoient à la même anecdote, celle de Zopyre, transmise par Cicéron<ref>Cicéron, ''Tusculanes'', IV, 80 ; voir aussi ''De Fato'', V, 10.</ref>. Sommer souligne que cette section rapproche l'Athènes du {{Ve}} siècle avant notre ère de l'Europe du {{XIXe}} siècle : dans les deux cas s'impose un diagnostic de décadence, et le philosophe (Socrate hier, Nietzsche aujourd'hui) intervient en médecin de la culture<ref>Andreas Urs Sommer, ''{{lang|de|Kommentar zu Nietzsches Der Fall Wagner, Götzen-Dämmerung}}'', Berlin, De Gruyter, 2012.</ref>. === § 10 : La raison érigée en tyran === Le cœur de l'argumentation : {{Citation bloc|Quand on a besoin de faire de la raison un tyran, comme fit Socrate, il faut que le danger soit considérable de voir quelque chose d'autre jouer le tyran.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;10 ; KSA 6, {{p.|72}}.</ref>}} Ce quelque chose d'autre, ce sont les instincts. La raison n'est pas érigée en maîtresse par amour de la vérité, mais par nécessité vitale de contrôle. L'équation {{lang|de|1=''Vernunft = Tugend = Glück''}} (raison = vertu = bonheur), introduite au §&nbsp;4, est ici reprise et qualifiée. Nietzsche conclut : {{Citation|Le moralisme des philosophes grecs à partir de Platon est pathologiquement conditionné.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;10 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''pathologisch bedingt''}}.</ref> Comme le note Sommer, c'est la seule occurrence explicite du champ lexical de la pathologie dans tout le ''Crépuscule des idoles'', ce qui en souligne le poids. === § 11 : L'équivoque du remède socratique === Cette section examine l'efficacité apparente du remède : {{Citation|Il semblait être un médecin, un sauveur.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;11 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''er schien ein Arzt, ein Heiland zu sein''}}.</ref> La métaphore du philosophe-médecin remonte à Platon lui-même, mais Nietzsche la retourne : Socrate n'était pas un vrai médecin, car sa thérapie était illusoire<ref>Platon conçoit le philosophe comme une sorte de médecin chargé de la thérapie de l'âme ({{lang|grc|θεραπεύειν τὴν ψυχήν}} ; ''Cratyle'', 440c ; ''Gorgias'', 513d).</ref>. La mise au pas des instincts par la raison ne guérit pas la décadence : elle la masque et la prolonge. D'où la formule définitionnelle : {{Citation bloc|Devoir combattre les instincts, c'est la formule de la décadence : tant que la vie est ascendante, bonheur égale instinct.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;11 ; KSA 6, {{p.|73}}. Texte allemand : {{lang|de|''Glück gleich Instinkt''}}.</ref>}} Ce paragraphe introduit la distinction, décisive pour la suite du livre, entre vie ascendante ({{lang|de|''aufsteigendes Leben''}}) et vie descendante. === § 12 : La mort volontaire de Socrate === Le chapitre s'achève sur une interprétation de la mort de Socrate : {{Citation bloc|Socrate voulait mourir : ce n'est pas Athènes, c'est lui qui se donna la coupe de ciguë, il força Athènes à la coupe de ciguë.<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;12 ; KSA 6, {{p.|73}}.</ref>}} Nietzsche s'appuie sur Jacob Burckhardt, qui notait que Socrate « voulait effectivement la mort »<ref>Jacob Burckhardt, ''{{lang|de|Griechische Kulturgeschichte}}''.</ref>. La fin du chapitre forme une boucle avec le début : les dernières paroles sont réinterprétées une dernière fois. {{Citation bloc|Socrate n'est pas un médecin, se dit-il tout bas : ici la mort seule est médecin… Socrate lui-même n'avait fait qu'être longtemps malade…<ref>''Crépuscule des idoles'', « Le problème de Socrate », §&nbsp;12 ; KSA 6, {{p.|73}}.</ref>}} Reconnaissant l'échec de sa thérapie rationnelle, Socrate ne conclut plus que la vie est une maladie, mais que seule sa vie l'était. L'ironie finale est que cette lucidité ferait de lui, conformément à l'oracle de Delphes, le plus sage des hommes, d'une sagesse qui pourtant se nie elle-même. Cette reprise variée de l'ouverture scelle la composition rigoureuse de l'ensemble du chapitre. == Notes et références == {{Références}} {{Bas de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} {{AutoCat}} hvok5m8gu26825nx3uklsp0kg066xju 768751 768750 2026-06-27T04:27:01Z PandaMystique 119061 768751 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} == Introduction : que signifie mettre Socrate en procès ? == Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l’interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' (''Götzen-Dämmerung''), intitulé « Le problème de Socrate » (''Das Problem des Sokrates''). Nietzsche y soumet le fondateur présumé de la philosophie occidentale à un examen sans ménagement : loin d’incarner l’apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d’une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s’inscrit dans une stratégie plus vaste : en brisant l’idole Socrate, Nietzsche entend ébranler l’édifice entier de la philosophie morale occidentale. == Contexte : genèse et place du chapitre == Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d'abord le titre « {{lang|de|Sokrates als Problem}} » (« Socrate comme problème »), avant d'être intégré à un projet plus vaste sur « la philosophie comme {{lang|fr|décadence}} »<ref>KSA 14, {{p.|413}}. La référence éditoriale renvoie à Friedrich Nietzsche, {{lang|de|''Sämtliche Werke. Kritische Studienausgabe''}} (KSA), éd. G. Colli et M. Montinari, Berlin/Munich, De Gruyter/dtv, 1980.</ref>. Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92] (KSA 13, {{pp.|268-270}}). C'est dans un fragment distinct, lié au plan du « {{lang|de|Wille zur Macht}} », que Socrate est qualifié de « moment de la plus profonde perversité dans l'histoire de l'humanité »<ref>NL 1888, KSA 13, 14[111] (KSA 13, {{p.|289}}) ; voir le commentaire de Sommer, qui rattache cette note au projet d'un chapitre sur « la philosophie comme {{lang|fr|décadence}} ».</ref>. La critique de Socrate traverse l'œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l'« archétype de l'optimiste théorique » ({{lang|de|''Urbild des theoretischen Optimisten''}})<ref>''La Naissance de la tragédie'', § 15 ; KSA 1, {{p.|100}}.</ref>. Nietzsche y opposait l'esprit dionysien, tragique et affirmatif, au rationalisme socratique qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique se charge d'une dimension physiologique nouvelle : sous l'influence de lectures médicales récentes, notamment Charles Féré (''Dégénérescence et criminalité'', 1888) et l'anthropologie criminelle de Cesare Lombroso, Nietzsche interprète Socrate en termes pathologiques : il est désormais présenté comme {{lang|fr|décadent}}. Le durcissement du jugement est net : Socrate est recodé comme négateur de la vie. Le chapitre conserve néanmoins une réelle ambivalence, puisque Socrate y est aussi présenté comme stratège, inventeur d'un nouvel ''agôn'', « grand érotique » (§ 8) et témoin lucide du déclin athénien (§ 9). Le durcissement porte donc sur l'évaluation d'ensemble, non sur la reconnaissance de la puissance de Socrate. == La thèse centrale == Nietzsche soutient que la philosophie socratique, avec son équation « raison = vertu = bonheur », constitue non pas une conquête de l'esprit, mais le symptôme d'une dégénérescence ({{lang|de|''Degenerescenz''}}). Les « instincts en anarchie » de Socrate l'auraient contraint à ériger la raison en tyran pour se maîtriser. Cette solution individuelle, généralisée à une civilisation en déclin (l'Athènes du {{Ve}} siècle avant notre ère), aurait inauguré, selon Nietzsche, une longue tradition philosophique tendant à subordonner la vie à la raison et à la morale. La {{lang|fr|décadence}}, terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui conférer une charge physiologique, désigne ici la désagrégation des instincts vitaux et l'incapacité à affirmer l'existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === Le chapitre s'ouvre sur un constat provocateur : {{Citation|Sur la vie, de tout temps, les plus sages ont porté le même jugement : elle ne vaut rien…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''Über das Leben haben zu allen Zeiten die Weisesten gleich geurtheilt: es taugt nichts…''}}</ref> Nietzsche prête à ces sages quatre tonalités convergentes : un son « plein de doute, plein de mélancolie, plein de lassitude de la vie, plein de résistance contre la vie ». L'unanimité visée est celle des philosophes, de Socrate aux pessimistes contemporains, qui auraient déprécié l'existence. Vient alors l'exemple de Socrate mourant, qu'il faut citer avec précision, car Nietzsche ne reprend pas Platon mot pour mot. Le ''Phédon'' (118a) porte, au pluriel, « Ô Criton, nous devons un coq à Asclépios ». Littéralement, Socrate demande seulement qu'on acquitte une dette cultuelle envers Asclépios, dieu de la médecine : le coq était l'offrande traditionnelle que l'on faisait au dieu après une guérison. L'idée que cette guérison désignerait la vie elle-même n'est pas le sens littéral de la phrase, mais une interprétation rendue plausible par le contexte religieux et médical. Nietzsche, de fait, donne une version déjà interprétée, au singulier et augmentée : {{Citation|vivre, c'est être longtemps malade : je dois un coq au sauveur Asclépios.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''leben — das heisst lange krank sein: ich bin dem Heilande Asklepios einen Hahn schuldig''}}.</ref> Le mot « sauveur » ({{lang|de|''Heiland''}}) et l'ajout « vivre, c'est être longtemps malade » insèrent dans la bouche de Socrate la lecture que Nietzsche veut en tirer. Cette interprétation, déjà présente dans ''Le Gai Savoir'' (§ 340), prolonge une tradition exégétique que Nietzsche connaissait depuis Pforta : son professeur de grec Karl Steinhart avait commenté ce passage en écrivant que Socrate « se sent guéri de la maladie de la vie terrestre et libéré des liens entravants du corps »<ref>Karl Steinhart, dans ses annotations à la traduction de Platon, Leipzig, 1854, {{p.|577}}. Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi).</ref>. La section se referme sur une question puis une image. À l'argument traditionnel (« Le {{lang|la|consensus sapientium}} prouve la vérité »), Nietzsche substitue le soupçon : « Il doit bien y avoir ici quelque chose de malade. » Puis vient la métaphore qui clôt réellement le paragraphe : {{Citation|La sagesse n'apparaîtrait-elle pas sur terre comme un corbeau qu'une petite odeur de charogne met en joie ?…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''als Rabe, den ein kleiner Geruch von Aas begeistert''}}.</ref> L'image substitue au symbole noble de la philosophie (la chouette de Minerve) un charognard attiré par ce qui décline. On peut y entendre, avec Sommer, des échos interprétatifs plutôt que des sources attestées : le corbeau, oiseau ambivalent, est aussi associé à la sagesse (les corbeaux d'Odin) et apparaît chez Wagner (''{{lang|de|Götterdämmerung}}'', dont le titre est proche du {{lang|de|''Götzen-Dämmerung''}} nietzschéen). Ces rapprochements éclairent la portée du passage sans qu'on puisse les tenir pour ses sources certaines. === § 2 : Symptomatologie et valeur de la vie === Le pivot méthodologique se trouve ici. Nietzsche renvoie d'abord explicitement à son premier livre : {{Citation|J'ai reconnu Socrate et Platon comme des symptômes de déclin, comme pseudo-grecs, anti-grecs (''Naissance de la tragédie'', 1872).}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Verfalls-Symptome''}}.</ref> Le {{lang|la|consensus}} des sages reçoit alors sa réinterprétation décisive : il « prouve bien plutôt qu'eux-mêmes, ces très sages, concordaient physiologiquement sur quelque point, pour se tenir de la même façon négativement devant la vie »<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}.</ref>. De là découle la thèse épistémologique : {{Citation|Les jugements de valeur sur la vie, pour ou contre, ne peuvent en fin de compte jamais être vrais : ils n'ont de valeur que comme symptômes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Symptome''}}.</ref> La raison en est que la valeur de la vie est inévaluable. La formulation exacte de Nietzsche est : « cette étonnante finesse, que la valeur de la vie ne peut pas être évaluée » ({{lang|de|''dass der Werth des Lebens nicht abgeschätzt werden kann''}}). Le vivant ne peut évaluer la vie, « parce qu'il est partie, voire objet du litige, et non juge » ; le mort ne le peut pas non plus, pour une autre raison laissée ironiquement implicite. L'expression « valeur de la vie » ({{lang|de|''Werth des Lebens''}}) fait écho au titre de l'ouvrage d'Eugen Dühring (''{{lang|de|Der Werth des Lebens}}'', 1865), que Nietzsche avait longuement excerpté en 1875<ref>NL 1875, KSA 8, 9[1] (KSA 8, {{pp.|131-181}}).</ref>. La conclusion renverse les termes : qu'un philosophe voie un problème dans la valeur de la vie est « une objection contre lui, un point d'interrogation sur sa sagesse, une non-sagesse ({{lang|de|''Unweisheit''}}) ». Le paragraphe s'achève sur une transition vers la suite : « Mais je reviens au problème de Socrate. » === § 3 : Basse extraction, laideur et anthropologie criminelle === Cette section concentre l'argument physiognomonique : {{Citation|Socrate appartenait, par son origine, au plus bas peuple : Socrate était populace. On sait, on voit encore aujourd'hui combien il était laid.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Pöbel''}}.</ref> La laideur de Socrate était de notoriété antique (Platon, ''Banquet'' 215a-b et 221d-e, comparaison avec le silène Marsyas ; Xénophon, ''Banquet'' IV, 19 et V, 5-7, le concours de beauté). Nietzsche s'appuie surtout sur Eduard Zeller, qui notait le contraste « non grec » entre l'apparence de Socrate et l'idéal d'harmonie du corps et de l'âme<ref>Eduard Zeller, ''{{lang|de|Die Philosophie der Griechen}}'', 2{{e}} partie, Tübingen, 1859, {{pp.|59-60}}.</ref>. Là où Zeller voyait une tension, Nietzsche lit un verdict : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation. Socrate était-il même un Grec ? » Vient ensuite le rapprochement avec le criminel : {{Citation|Les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : {{lang|la|monstrum in fronte, monstrum in animo}}. Mais le criminel est un décadent. Socrate était-il un criminel typique ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}.</ref> Deux précisions s'imposent. D'abord, la source : la formule latine et la référence à Lombroso proviennent directement de Charles Féré, passage que Nietzsche avait souligné<ref>Charles Féré, ''Dégénérescence et criminalité'', Paris, Alcan, 1888, {{p.|80}}. La concordance des extraits figure chez Lampl (1986).</ref>. Ensuite, la portée logique : Nietzsche ne déclare pas que Socrate est un criminel. Il pose une question (figure de la ''dubitatio'') et procède par une inférence sciemment invalide (les criminels sont laids ; Socrate est laid ; donc Socrate serait criminel), c'est-à-dire une affirmation du conséquent, comme l'ont relevé Sommer et Pichler. Le scandale réside moins dans le contenu que dans la posture : Nietzsche se range un instant du côté des accusateurs de Socrate. L'anecdote du physiognomoniste vient confirmer la provocation : un étranger expert en visages dit à Socrate qu'il recèle « tous les mauvais vices et appétits », et Socrate répond simplement : {{Citation|Vous me connaissez, Monsieur !}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Sie kennen mich, mein Herr!''}}</ref> === § 4 : Les signes de la décadence et l'équation socratique === Ce paragraphe ne reprend pas l'anecdote du physiognomoniste : il en tire les conséquences en énumérant les autres signes de la décadence socratique. {{Citation|La décadence de Socrate ne se trahit pas seulement par l'anarchie avouée de ses instincts : elle se trahit aussi par la superfétation du logique et par cette malveillance bilieuse qui le distingue.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Superfötation des Logischen''}}.</ref> Le terme « superfétation » est emprunté à la médecine (une seconde conception survenant au cours d'une grossesse) : Nietzsche suggère que la faculté logique est pathologiquement surdéveloppée. Sommer note que le rapprochement entre cette « superfétation » et le démon socratique figurait déjà dans ''La Naissance de la tragédie'' (§ 13). Nietzsche médicalise ensuite le fameux ''daimonion'' : {{Citation|N'oublions pas non plus ces hallucinations auditives qui, sous le nom de « démon de Socrate », ont reçu une interprétation religieuse.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}.</ref> La source en est Francis Galton, qui rangeait Socrate parmi les sujets prédisposés aux crises nerveuses et aux hallucinations<ref>Francis Galton, ''Inquiries into Human Faculty and its Development'', Londres, Macmillan, 1883, {{p.|176}}.</ref>. Tout, chez Socrate, serait « exagéré, ''buffo'', caricature ». Le paragraphe s'achève sur la première formulation de l'équation centrale : {{Citation|1=Je cherche à comprendre de quelle idiosyncrasie procède cette équation socratique, raison = vertu = bonheur : la plus bizarre de toutes les équations, qui a contre elle en particulier tous les instincts de l'ancien Hellène.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Idiosynkrasie''}}.</ref> Le terme « idiosyncrasie », médical, désigne une constitution organique singulière : la philosophie socratique exprime une pathologie individuelle, non une vérité universelle. Les manuscrits consignent une équation alternative, antérieure à Socrate<ref>Variante des manuscrits préparatoires (Mp XVI 4) : {{lang|de|2=''Tugend = Instinkt = Grund-Unbewußtheit''}} (« vertu = instinct = inconscience fondamentale »), KSA 14, {{pp.|413-414}}.</ref>. === § 5 : La dialectique comme défaite du goût aristocratique === Nietzsche aborde ici la dialectique et observe un renversement du goût : {{Citation|Avec Socrate, le goût grec bascule en faveur de la dialectique : que se passe-t-il là au juste ? Avant tout, un goût distingué s'en trouve vaincu ; avec la dialectique, la populace l'emporte.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 5 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''der Pöbel kommt mit der Dialektik obenauf''}}.</ref> Avant Socrate, « on rejetait dans la bonne société les manières dialectiques ; elles passaient pour de mauvaises manières, elles compromettaient ». L'homme bien né n'a pas besoin de prouver : il possède l'autorité. « Il est indécent de montrer ses cinq doigts. Ce qui a besoin d'abord d'être prouvé n'a que peu de valeur. » L'expression « étalage de raisons » ({{lang|de|''Etalage von Gründen''}}) emploie un gallicisme que Nietzsche affectionne. La dialectique se présente comme l'arme de qui ne dispose pas de l'autorité naturelle. === § 6 : La dialectique comme légitime défense === Nietzsche resserre : {{Citation|La dialectique ne peut être qu'une légitime défense.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 6 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Nothwehr''}}.</ref> Elle est l'arme de ceux qui n'en ont pas d'autre. Les variantes manuscrites contenaient une remarque sur les Juifs comme dialecticiens, que la version publiée supprime, témoignant d'un travail de révision<ref>Variante du cahier W II 5, 85 (KGW IX 8), supprimée dans la version définitive.</ref>. La comparaison avec ''{{lang|de|Reineke Fuchs}}'' (le goupil rusé de l'épopée de Goethe, 1794) éclaire le propos : comme le renard qui échappe deux fois à la mort par ses discours « dialectiques », Socrate compense par la ruse argumentative une infériorité de position<ref>Sur la connaissance qu'avait Nietzsche de l'œuvre de Goethe, voir le commentaire de Sommer, qui renvoie à Victor Hehn (1888).</ref>. === § 7 : L'ironie socratique comme ressentiment === Cette section traite de l'ironie : {{Citation|L'ironie de Socrate est-elle une expression de révolte ? un ressentiment de la populace ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Ausdruck von Revolte''}} ; {{lang|de|''Pöbel-Ressentiment''}}.</ref> Le terme « ressentiment », que Nietzsche écrit en français, est l'un des concepts clés de la ''Généalogie de la morale''. La formule de Nietzsche est tranchante : {{Citation|L'ironie du dialecticien est la férocité de la vengeance plébéienne : les opprimés ont leur férocité dans les froids coups de couteau du syllogisme.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''die Ferocität der Pöbel-Rache''}}.</ref> Il importe ici de distinguer deux usages du ressentiment. Dans la ''Généalogie de la morale'', le ressentiment est créateur : il invente des valeurs, forge le couple « bon / méchant » et prend sa revanche de façon imaginaire, sur le terrain moral<ref>''Généalogie de la morale'', première dissertation, § 10 ; KSA 5, {{pp.|270-273}}.</ref>. Au § 7, l'ironie dialectique ne crée pas de valeurs nouvelles : elle fournit une arme tactique dans l'''agôn'' intellectuel, qui humilie l'adversaire et le rend impuissant. La continuité tient au mécanisme, la vengeance de qui ne peut agir directement ; la différence tient au terrain, la transvaluation morale d'un côté, le duel argumentatif de l'autre. Le mécanisme est précisé : « Le dialecticien laisse à son adversaire le soin de prouver qu'il n'est pas un idiot ; il le rend furieux et impuissant à la fois. Le dialecticien dépotentialise ({{lang|de|''depotenzirt''}}) l'intellect de son adversaire. » La dialectique ne convainc pas : elle neutralise. === § 8 : Socrate « érotique » === Brève section qui introduit une dimension inattendue : {{Citation|Socrate était aussi un grand érotique.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 8 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Sokrates war auch ein grosser Erotiker''}}.</ref> L'allusion au rôle de Socrate dans le ''Banquet'' de Platon est transparente. Nietzsche suggère que la dialectique fonctionnait comme une nouvelle forme d'''agôn''. Là où Zeller, puis Franz Susemihl, spiritualisaient l'éros socratique, Nietzsche réintroduit l'élément sensuel et pédérastique que la tradition académique tendait à occulter<ref>Franz Susemihl, « {{lang|de|Ueber die composition des platonischen gastmahls}} », {{lang|de|''Philologus''}}, 1851.</ref>. === § 9 : Socrate, témoin lucide du déclin === La section opère un renversement partiel : Socrate n'est plus seulement l'agent du déclin, il en est le témoin clairvoyant. {{Citation bloc|Il regarda derrière ses nobles Athéniens ; il comprit que son cas, son idiosyncrasie de cas, n'était déjà plus un cas exceptionnel. La même espèce de dégénérescence se préparait partout en silence : la vieille Athènes touchait à sa fin.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Degenerescenz''}}.</ref>}} Nietzsche lui reconnaît une lucidité diagnostique : « Partout les instincts étaient en anarchie ; partout on était à cinq pas de l'excès. » Le paragraphe reprend l'anecdote du physiognomoniste sous une seconde version, plus proche de la tradition cicéronienne : {{Citation|C'est vrai, dit-il, mais je suis devenu maître de toutes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Dies ist wahr, aber ich wurde über alle Herr''}}.</ref> Les deux répliques que Nietzsche prête à Socrate (« Vous me connaissez, Monsieur ! » au § 3, « je suis devenu maître de toutes » ici) renvoient à la même anecdote, celle de Zopyre, transmise par Cicéron<ref>Cicéron, ''Tusculanes'', IV, 80 ; voir aussi ''De Fato'', V, 10.</ref>. Sommer souligne que cette section rapproche l'Athènes du {{Ve}} siècle avant notre ère de l'Europe du {{XIXe}} siècle : dans les deux cas s'impose un diagnostic de décadence, et le philosophe (Socrate hier, Nietzsche aujourd'hui) intervient en médecin de la culture. === § 10 : La raison érigée en tyran === Le cœur de l'argumentation : {{Citation bloc|Quand on a besoin de faire de la raison un tyran, comme fit Socrate, il faut que le danger soit considérable de voir quelque chose d'autre jouer le tyran.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}.</ref>}} Ce quelque chose d'autre, ce sont les instincts. La raison n'est pas érigée en maîtresse par amour de la vérité, mais par nécessité vitale de contrôle. L'équation {{lang|de|2=''Vernunft = Tugend = Glück''}} (raison = vertu = bonheur), introduite au § 4, est ici reprise et qualifiée. Nietzsche conclut : {{Citation|Le moralisme des philosophes grecs à partir de Platon est pathologiquement conditionné.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''pathologisch bedingt''}}.</ref> Comme le note Sommer, c'est la seule occurrence explicite du champ lexical de la pathologie dans tout le ''Crépuscule des idoles'', ce qui en souligne le poids. === § 11 : L'équivoque du remède socratique === Cette section examine l'efficacité apparente du remède : {{Citation|Il semblait être un médecin, un sauveur.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''er schien ein Arzt, ein Heiland zu sein''}}.</ref> La métaphore du philosophe-médecin remonte à Platon lui-même, mais Nietzsche la retourne : Socrate n'était pas un vrai médecin, car sa thérapie était illusoire<ref>Platon conçoit le philosophe comme une sorte de médecin chargé de la thérapie de l'âme ({{lang|grc|θεραπεύειν τὴν ψυχήν}} ; ''Cratyle'', 440c ; ''Gorgias'', 513d).</ref>. La mise au pas des instincts par la raison ne guérit pas la décadence : elle la masque et la prolonge. D'où la formule définitionnelle : {{Citation bloc|Devoir combattre les instincts, c'est la formule de la décadence : tant que la vie est ascendante, bonheur égale instinct.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|73}}. Texte allemand : {{lang|de|''Glück gleich Instinkt''}}.</ref>}} Ce paragraphe introduit la distinction, décisive pour la suite du livre, entre vie ascendante ({{lang|de|''aufsteigendes Leben''}}) et vie descendante. === § 12 : La mort volontaire de Socrate === Le chapitre s'achève sur une interprétation de la mort de Socrate : {{Citation bloc|Socrate voulait mourir : ce n'est pas Athènes, c'est lui qui se donna la coupe de ciguë, il força Athènes à la coupe de ciguë.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Nietzsche s'appuie sur Jacob Burckhardt, qui notait que Socrate « voulait effectivement la mort »<ref>Jacob Burckhardt, ''{{lang|de|Griechische Kulturgeschichte}}''.</ref>. La fin du chapitre forme une boucle avec le début : les dernières paroles sont réinterprétées une dernière fois. {{Citation bloc|Socrate n'est pas un médecin, se dit-il tout bas : ici la mort seule est médecin… Socrate lui-même n'avait fait qu'être longtemps malade…<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Reconnaissant l'échec de sa thérapie rationnelle, Socrate ne conclut plus que la vie est une maladie, mais que seule sa vie l'était. L'ironie finale est que cette lucidité ferait de lui, conformément à l'oracle de Delphes, le plus sage des hommes, d'une sagesse qui pourtant se nie elle-même. Cette reprise variée de l'ouverture scelle la composition rigoureuse de l'ensemble du chapitre. == Étude de passage : § 4 et § 9 == Le passage le plus délicat est celui qui articule le diagnostic individuel et le diagnostic collectif. Au § 4, Nietzsche cherche l'« idiosyncrasie » d'où procède l'équation « raison = vertu = bonheur ». Au § 9, cette idiosyncrasie cesse d'être un cas isolé. L'italique de Nietzsche sur « derrière » ({{lang|de|''hinter''}}) et sur « son » cas ({{lang|de|''sein''}}) est significatif : le premier indique que Socrate perçoit ce que dissimule la façade aristocratique, le second souligne le retournement par lequel une anomalie individuelle se révèle être un état généralisé. Le jeu sur {{lang|de|''Fall''}} (à la fois « cas » et « chute ») renforce la dimension diagnostique. Le terme {{lang|de|''Degenerescenz''}} mérite attention : Nietzsche l'emprunte à Féré, où il désigne un processus de dégradation héréditaire observé chez les criminels et les aliénés cliniquement internés. En l'appliquant à l'Athènes classique, Nietzsche opère un transfert provocateur : la civilisation tenue pour l'apogée de la culture grecque serait en réalité un organisme en décomposition. == Controverses interprétatives == Les grandes lectures du chapitre se distinguent par l'axe qu'elles privilégient. Lecture métaphysique, chez Martin Heidegger (cours sur Nietzsche, 1936-1940) : la critique de Socrate s'inscrit dans l'histoire de l'oubli de l'Être, le rationalisme socratique inaugurant la métaphysique comme onto-théologie. Heidegger reproche cependant à Nietzsche de demeurer lui-même métaphysicien par sa doctrine de la volonté de puissance. Lecture psychologique et admirative, chez Walter Kaufmann : loin d'une condamnation sans appel, le rapport de Nietzsche à Socrate serait celui d'une rivalité entre deux philosophes-médecins. ''Par-delà bien et mal'' (§ 212) reconnaît d'ailleurs à la thérapie socratique une légitimité « pour son temps »<ref>''Par-delà bien et mal'', § 212 ; KSA 5, {{pp.|146-147}}.</ref>. Lecture philologique et contextualiste, chez Andreas Urs Sommer, et lecture médicale et stratégique, chez Sabine Wahrig-Schmidt : toutes deux insistent sur le rôle des sources médicales de 1888, mais en tirent des accents différents. Sommer reconstitue précisément les emprunts et les variantes manuscrites ; Wahrig-Schmidt met en garde contre une lecture littérale, le vocabulaire médical étant mobilisé de manière stratégique, pour subvertir les valorisations traditionnelles, non pour livrer un diagnostic clinique. Lecture rhétorique et auto-référentielle, enfin, chez Bruno Roche, Yannick Souladié et Enrico Müller : Nietzsche critique la dialectique tout en l'utilisant, dénonce l'ironie comme ressentiment tout en la pratiquant. Müller parle d'une « figure d'interprétation paradoxale » par laquelle la pathologie socratique est elle-même pathologisée, le véritable médecin n'étant plus Socrate mais Nietzsche. La tension se lit comme une aporie ou comme une ironie au second degré : on ne sortirait de la dialectique qu'en la traversant. == Ce que Nietzsche affirme et ce qu'on lui prête == Nietzsche affirme : que le jugement négatif des philosophes sur la vie est un symptôme de déclin vital, non une vérité objective ; que Socrate souffrait d'une anarchie des instincts qu'il a maîtrisée en faisant de la raison un tyran ; que l'équation « raison = vertu = bonheur » rompt avec les instincts de l'ancien hellénisme ; que la dialectique est l'arme des faibles, une forme de ressentiment ; que la philosophie depuis Socrate est « pathologiquement conditionnée ». On lui prête à tort un rejet total de la raison : il ne condamne pas la raison comme telle, mais son érection en tyran contre les instincts, revendiquant pour lui-même une « clarté de dialecticien »<ref>''Ecce Homo'', « Pourquoi je suis si sage », § 1 ; KSA 6, {{p.|265}}.</ref>. On lui prête à tort un éloge inconditionnel des instincts : l'idéal est leur coordination hiérarchique, non leur anarchie, laquelle est précisément le symptôme de la décadence. On lui prête à tort une condamnation morale de Socrate : sa critique se veut « physiologique », non un blâme. On lui prête enfin à tort l'identification de Socrate à un criminel : la question « Socrate était-il un criminel typique ? » est une provocation reposant sur une inférence invalide, et Nietzsche réserve par ailleurs au criminel une réelle sympathie, le tenant pour « le type de l'homme fort placé dans des conditions défavorables »<ref>''Crépuscule des idoles'', « Flâneries d'un inactuel », § 45 ; KSA 6, {{p.|146}}.</ref>. Or tel n'est précisément pas le Socrate qu'il décrit. == Synthèse == Le chapitre développe, en douze sections rigoureusement composées, une thèse à plusieurs niveaux. Au plan physiologique, Socrate est un décadent dont les instincts sont désagrégés. Au plan historique, l'Athènes du {{Ve}} siècle traverse une crise dont Socrate généralise la solution personnelle. Au plan philosophique, l'équation « raison = vertu = bonheur » ouvre, selon Nietzsche, une longue tradition tendant à subordonner la vie à la raison et à la morale. Au plan stratégique, s'attaquer à l'idole Socrate permet de viser l'ensemble de la tradition rationaliste et moraliste, et de préparer ''L'Antéchrist''. La structure suit un crescendo : ouverture sur les dernières paroles de Socrate (§ 1), portrait physiologique et anthropologique (§ 3-4), analyse de la dialectique comme arme des faibles (§ 5-8), diagnostic de la raison-tyran (§ 9-11), puis reprise variée de l'ouverture (§ 12). L'ambivalence persiste néanmoins : Socrate est aussi reconnu clairvoyant (§ 9), et sa mort volontaire revêt une forme de sagesse (§ 12). Nietzsche semble reconnaître en lui un adversaire à sa mesure, voire un prédécesseur dans la tâche de médecin de la culture, ce qui fragilise l'apparente univocité de la condamnation. == Notes et références == {{Références|colonnes=2}} == Sources anciennes == Platon, ''Apologie'', ''Criton'', ''Phédon'', ''Banquet'' ; Xénophon, ''Mémorables'', ''Banquet'' ; Aristophane, ''Les Nuées'' ; Cicéron, ''Tusculanes'' IV, 80 (anecdote de Zopyre). 8pn1lcicxzvk0owd3hi5q48hz0hp3tg 768752 768751 2026-06-27T05:12:29Z PandaMystique 119061 768752 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} == Introduction : que signifie mettre Socrate en procès ? == [[Fichier:Socrates Louvre.jpg|vignette|upright|Buste de Socrate, copie romaine du {{Ier}} siècle d'après un original grec parfois attribué à Lysippe. Paris, musée du Louvre.]] Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l'interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' ({{lang|de|''Götzen-Dämmerung''}}), intitulé « Le problème de Socrate » ({{lang|de|''Das Problem des Sokrates''}}). Nietzsche y soumet Socrate, figure fondatrice de la philosophie morale occidentale, à un examen sans ménagement : loin d'incarner l'apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d'une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s'inscrit dans une stratégie plus vaste : en brisant l'idole Socrate, Nietzsche entend ébranler tout l'édifice de la tradition rationaliste et morale. == Contexte : genèse et place du chapitre == Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d'abord le titre « {{lang|de|Sokrates als Problem}} » (« Socrate comme problème »), avant d'être intégré à un projet plus vaste sur « la philosophie comme {{lang|fr|décadence}} »<ref>KSA 14, {{p.|413}}. La référence éditoriale renvoie à Friedrich Nietzsche, {{lang|de|''Sämtliche Werke. Kritische Studienausgabe''}} (KSA), éd. G. Colli et M. Montinari, Berlin/Munich, De Gruyter/dtv, 1980.</ref>. Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92] (KSA 13, {{pp.|268-270}}). C'est dans un fragment distinct, lié au plan de la [[Nietzsche : Introduction à sa philosophie/Volonté de puissance|volonté de puissance]] (« {{lang|de|Wille zur Macht}} »), que Socrate est qualifié de « moment de la plus profonde perversité dans l'histoire de l'humanité »<ref>NL 1888, KSA 13, 14[111] (KSA 13, {{p.|289}}) ; voir le commentaire de Sommer, qui rattache cette note au projet d'un chapitre sur « la philosophie comme {{lang|fr|décadence}} ».</ref>. La critique de Socrate traverse l'œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l'« archétype de l'optimiste théorique » ({{lang|de|''Urbild des theoretischen Optimisten''}})<ref>''La Naissance de la tragédie'', § 15 ; KSA 1, {{p.|100}}.</ref>. Nietzsche y opposait l'[[Nietzsche : Introduction à sa philosophie/L'Apollinien et le Dionysien|esprit dionysien]], tragique et affirmatif, au rationalisme socratique qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique se charge d'une dimension physiologique nouvelle : sous l'influence de lectures médicales récentes, notamment Charles Féré (''Dégénérescence et criminalité'', 1888) et l'anthropologie criminelle de Cesare Lombroso, Nietzsche interprète Socrate en termes pathologiques : il est désormais présenté comme {{lang|fr|décadent}}. Le durcissement du jugement est net : Socrate est recodé comme négateur de la vie. Le chapitre conserve néanmoins une réelle ambivalence, puisque Socrate y est aussi présenté comme stratège, inventeur d'un nouvel ''agôn'', « grand érotique » (§ 8) et témoin lucide du déclin athénien (§ 9). Le durcissement porte donc sur l'évaluation d'ensemble, non sur la reconnaissance de la puissance de Socrate. == La thèse centrale == Nietzsche soutient que la philosophie socratique, avec son équation « raison = vertu = bonheur », constitue non pas une conquête de l'esprit, mais le symptôme d'une dégénérescence ({{lang|de|''Degenerescenz''}}). Les « instincts en anarchie » de Socrate l'auraient contraint à ériger la raison en tyran pour se maîtriser. Cette solution individuelle, généralisée à une civilisation en déclin (l'Athènes du Ve siècle avant notre ère), aurait inauguré, selon Nietzsche, une longue tradition philosophique tendant à subordonner la vie à la raison et à la morale. La {{lang|fr|décadence}}, terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui conférer une charge physiologique, désigne ici la désagrégation des instincts vitaux et l'incapacité à affirmer l'existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === Le chapitre s'ouvre sur un constat provocateur : {{Citation|Sur la vie, de tout temps, les plus sages ont porté le même jugement : elle ne vaut rien…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''Über das Leben haben zu allen Zeiten die Weisesten gleich geurtheilt: es taugt nichts…''}}</ref> Nietzsche prête à ces sages quatre tonalités convergentes : un son « plein de doute, plein de mélancolie, plein de lassitude de la vie, plein de résistance contre la vie ». L'unanimité visée est celle des philosophes, de Socrate aux pessimistes contemporains, qui auraient déprécié l'existence. Vient alors l'exemple de Socrate mourant, qu'il faut citer avec précision, car Nietzsche ne reprend pas Platon mot pour mot. Le ''Phédon'' (118a) porte, au pluriel, « Ô Criton, nous devons un coq à Asclépios ». Littéralement, Socrate demande seulement qu'on acquitte une dette cultuelle envers Asclépios, dieu de la médecine : le coq était l'offrande traditionnelle que l'on faisait au dieu après une guérison. L'idée que cette guérison désignerait la vie elle-même n'est pas le sens littéral de la phrase, mais une interprétation rendue plausible par le contexte religieux et médical. Nietzsche, de fait, donne une version déjà interprétée, au singulier et augmentée : {{Citation|vivre, c'est être longtemps malade : je dois un coq au sauveur Asclépios.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''leben — das heisst lange krank sein: ich bin dem Heilande Asklepios einen Hahn schuldig''}}. La traduction française de référence (Henri Albert, 1908) rend le passage : « Vivre — c'est être longtemps malade : je dois un coq à Esculape libérateur. »</ref> Le mot « sauveur » ({{lang|de|''Heiland''}}) et l'ajout « vivre, c'est être longtemps malade » insèrent dans la bouche de Socrate la lecture que Nietzsche veut en tirer. Cette interprétation, déjà présente dans ''Le Gai Savoir'' (§ 340), prolonge une tradition exégétique que Nietzsche connaissait depuis Pforta : son professeur de grec Karl Steinhart avait commenté ce passage en écrivant que Socrate « se sent guéri de la maladie de la vie terrestre et libéré des liens entravants du corps »<ref>Karl Steinhart, dans ses annotations à la traduction de Platon, Leipzig, 1854, {{p.|577}}. Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi).</ref>. La section se referme sur une question puis une image. À l'argument traditionnel (« Le {{lang|la|consensus sapientium}} prouve la vérité »), Nietzsche substitue le soupçon : « Il doit bien y avoir ici quelque chose de malade. » Puis vient la métaphore qui clôt réellement le paragraphe : {{Citation|La sagesse n'apparaîtrait-elle pas sur terre comme un corbeau qu'une petite odeur de charogne met en joie ?…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''als Rabe, den ein kleiner Geruch von Aas begeistert''}}.</ref> L'image substitue au symbole noble de la philosophie (la chouette de Minerve) un charognard attiré par ce qui décline. On peut y entendre, avec Sommer, des échos interprétatifs plutôt que des sources attestées : le corbeau, oiseau ambivalent, est aussi associé à la sagesse (les corbeaux d'Odin) et apparaît chez Wagner (''{{lang|de|Götterdämmerung}}'', dont le titre est proche du {{lang|de|''Götzen-Dämmerung''}} nietzschéen). Ces rapprochements éclairent la portée du passage sans qu'on puisse les tenir pour ses sources certaines. === § 2 : Symptomatologie et valeur de la vie === [[Fichier:Plato Silanion Musei Capitolini MC1377.jpg|vignette|upright|Buste de Platon, copie romaine d'après un original grec du IVe siècle av. J.-C. Nietzsche associe Socrate et Platon comme « symptômes de déclin ».]] Le pivot méthodologique se trouve ici. Nietzsche renvoie d'abord explicitement à son premier livre : {{Citation|J'ai reconnu Socrate et Platon comme des symptômes de déclin, comme pseudo-grecs, anti-grecs (''Naissance de la tragédie'', 1872).}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Verfalls-Symptome''}}.</ref> Le {{lang|la|consensus}} des sages reçoit alors sa réinterprétation : il « prouve bien plutôt qu'eux-mêmes, ces très sages, concordaient physiologiquement sur quelque point, pour se tenir de la même façon négativement devant la vie »<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}.</ref>. De là découle la thèse épistémologique : {{Citation|Les jugements de valeur sur la vie, pour ou contre, ne peuvent en fin de compte jamais être vrais : ils n'ont de valeur que comme symptômes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Symptome''}}.</ref> La raison en est que la valeur de la vie est inévaluable. La formulation exacte de Nietzsche est : « cette étonnante finesse, que la valeur de la vie ne peut pas être évaluée » ({{lang|de|''dass der Werth des Lebens nicht abgeschätzt werden kann''}}). Le vivant ne peut évaluer la vie, « parce qu'il est partie, voire objet du litige, et non juge » ; le mort ne le peut pas non plus, pour une autre raison laissée ironiquement implicite. L'expression « valeur de la vie » ({{lang|de|''Werth des Lebens''}}) fait écho au titre de l'ouvrage d'Eugen Dühring (''{{lang|de|Der Werth des Lebens}}'', 1865), que Nietzsche avait longuement excerpté en 1875<ref>NL 1875, KSA 8, 9[1] (KSA 8, {{pp.|131-181}}). Henri Albert signale d'ailleurs en note que la pointe vise Dühring, auteur de ''La Valeur de la vie''.</ref>. La conclusion renverse les termes : qu'un philosophe voie un problème dans la valeur de la vie est « une objection contre lui, un point d'interrogation sur sa sagesse, une non-sagesse ({{lang|de|''Unweisheit''}}) ». Le paragraphe s'achève sur une transition vers la suite : « Mais je reviens au problème de Socrate. » === § 3 : Basse extraction, laideur et anthropologie criminelle === Cette section concentre l'argument physiognomonique : {{Citation|Socrate appartenait, par son origine, au plus bas peuple : Socrate était populace. On sait, on voit encore aujourd'hui combien il était laid.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Pöbel''}}.</ref> La laideur de Socrate était de notoriété antique (Platon, ''Banquet'' 215a-b et 221d-e, comparaison avec le silène Marsyas ; Xénophon, ''Banquet'' IV, 19 et V, 5-7, le concours de beauté). Nietzsche s'appuie surtout sur Eduard Zeller, qui notait le contraste « non grec » entre l'apparence de Socrate et l'idéal d'harmonie du corps et de l'âme<ref>Eduard Zeller, ''{{lang|de|Die Philosophie der Griechen}}'', 2{{e}} partie, Tübingen, 1859, {{pp.|59-60}}.</ref>. Là où Zeller voyait une tension, Nietzsche lit un verdict : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation. Socrate était-il même un Grec ? » Vient ensuite le rapprochement avec le criminel : {{Citation|Les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : {{lang|la|monstrum in fronte, monstrum in animo}}. Mais le criminel est un décadent. Socrate était-il un criminel typique ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}.</ref> Deux précisions s'imposent. D'abord, la source : la formule latine et la référence à Lombroso proviennent directement de Charles Féré, passage que Nietzsche avait souligné<ref>Charles Féré, ''Dégénérescence et criminalité'', Paris, Alcan, 1888, {{p.|80}}. La concordance des extraits figure chez Lampl (1986).</ref>. Ensuite, la portée logique : Nietzsche ne déclare pas que Socrate est un criminel. Il pose une question (figure de la ''dubitatio'') et procède par une inférence sciemment invalide (les criminels sont laids ; Socrate est laid ; donc Socrate serait criminel), c'est-à-dire une affirmation du conséquent, comme l'ont relevé Sommer et Pichler. Le scandale réside moins dans le contenu que dans la posture : Nietzsche se range un instant du côté des accusateurs de Socrate. L'anecdote du physiognomoniste vient confirmer la provocation : un étranger expert en visages dit à Socrate qu'il recèle « tous les mauvais vices et appétits », et Socrate répond simplement : {{Citation|Vous me connaissez, Monsieur !}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Sie kennen mich, mein Herr!''}}</ref> === § 4 : Les signes de la décadence et l'équation socratique === Ce paragraphe ne reprend pas l'anecdote du physiognomoniste : il en tire les conséquences en énumérant les autres signes de la décadence socratique. {{Citation|La décadence de Socrate ne se trahit pas seulement par l'anarchie avouée de ses instincts : elle se trahit aussi par la superfétation du logique et par cette malveillance bilieuse qui le distingue.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Superfötation des Logischen''}}.</ref> Le terme « superfétation » est emprunté à la médecine (une seconde conception survenant au cours d'une grossesse) : Nietzsche suggère que la faculté logique est pathologiquement surdéveloppée. Sommer note que le rapprochement entre cette « superfétation » et le démon socratique figurait déjà dans ''La Naissance de la tragédie'' (§ 13). Nietzsche médicalise ensuite le fameux ''daimonion'' : {{Citation|N'oublions pas non plus ces hallucinations auditives qui, sous le nom de « démon de Socrate », ont reçu une interprétation religieuse.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}.</ref> La source en est Francis Galton, qui rangeait Socrate parmi les sujets prédisposés aux crises nerveuses et aux hallucinations<ref>Francis Galton, ''Inquiries into Human Faculty and its Development'', Londres, Macmillan, 1883, {{p.|176}}.</ref>. Tout, chez Socrate, serait « exagéré, ''buffo'', caricature ». Le paragraphe s'achève sur la première formulation de l'équation centrale : {{Citation|1=Je cherche à comprendre de quelle idiosyncrasie procède cette équation socratique, raison = vertu = bonheur : la plus bizarre de toutes les équations, qui a contre elle en particulier tous les instincts de l'ancien Hellène.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Idiosynkrasie''}}.</ref> Le terme « idiosyncrasie », médical, désigne une constitution organique singulière : la philosophie socratique exprime une pathologie individuelle, non une vérité universelle. Les manuscrits consignent une équation alternative, antérieure à Socrate<ref>Variante des manuscrits préparatoires (Mp XVI 4) : {{lang|de|2=''Tugend = Instinkt = Grund-Unbewußtheit''}} (« vertu = instinct = inconscience fondamentale »), KSA 14, {{pp.|413-414}}.</ref>. === § 5 : La dialectique comme défaite du goût aristocratique === Nietzsche aborde ici la dialectique et observe un renversement du goût : {{Citation|Avec Socrate, le goût grec bascule en faveur de la dialectique : que se passe-t-il là au juste ? Avant tout, un goût distingué s'en trouve vaincu ; avec la dialectique, la populace l'emporte.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 5 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''der Pöbel kommt mit der Dialektik obenauf''}}.</ref> Avant Socrate, « on rejetait dans la bonne société les manières dialectiques ; elles passaient pour de mauvaises manières, elles compromettaient ». L'homme bien né n'a pas besoin de prouver : il possède l'autorité. « Il est indécent de montrer ses cinq doigts. Ce qui a besoin d'abord d'être prouvé n'a que peu de valeur. » Bruno Roche éclaire l'enjeu social de ce basculement. La logique à l'œuvre dans la dialectique tend à ramener les différences à l'identique, à rendre l'autre (le noble, l'élevé) égal à soi (le commun). Là où la hiérarchie aristocratique repose sur des distinctions que la vie pose d'elle-même, la dialectique introduit un principe d'uniformisation, en ouvrant à tous l'accès à l'idée et au savoir. Le savoir antique était un bien rare, réservé à un petit nombre (ésotérique) ; avec Socrate, il devient exotérique, accessible au plus grand nombre, et la plèbe revendique le droit de penser. L'expression « étalage de raisons » ({{lang|de|''Etalage von Gründen''}}) emploie un gallicisme que Nietzsche affectionne. La dialectique se présente ainsi comme l'arme de qui ne dispose pas de l'autorité naturelle. === § 6 : La dialectique comme légitime défense === [[Fichier:Reineke Fuchs.jpg|vignette|Reineke Fuchs, gravure d'après Wilhelm von Kaulbach (édition Cotta, 1857). Le goupil échappe deux fois à la mort par son habileté de parole : image du dialecticien impuissant selon Nietzsche.]] Nietzsche resserre : {{Citation|La dialectique ne peut être qu'une légitime défense.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 6 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Nothwehr''}}.</ref> Elle est l'arme de qui n'en possède pas d'autre, le recours de celui qui doit arracher son droit par la discussion faute de pouvoir l'imposer. Le texte publié range dans cette catégorie trois figures : {{Citation|Les Juifs étaient pour cette raison dialecticiens ; Reineke Fuchs l'était ; et Socrate l'était-il aussi ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 6 ; KSA 6, {{p.|70}}, l. 17. Texte allemand : {{lang|de|''Die Juden waren deshalb Dialektiker; Reineke Fuchs war es; Sokrates war es auch?''}}</ref> Le rapprochement appelle un cadrage. La mention des Juifs reprend un lieu commun de l'époque : l'idée d'une « dialectique juive » ou « rabbinique » circulait dans les lectures de Nietzsche, de Luther à Herder et à David Friedrich Strauss, comme le documente Sommer. Quant à ''Reineke Fuchs'', le goupil de l'épopée de Goethe que Nietzsche connaissait par Victor Hehn, il échappe par deux fois à la mort grâce à son habileté de parole. Le motif commun aux trois figures est que la dialectique est, selon Nietzsche, le propre du déraciné et du faible, qui compensent par la ruse argumentative une infériorité de position. Roche en précise le ressort : l'efficacité de la dialectique tient à ce qu'elle fait douter le fort en le sommant de justifier sa force ; le faible l'emporte le jour où le fort, contraint de s'expliquer, en vient à douter de lui-même. === § 7 : L'ironie socratique comme ressentiment === Cette section traite de l'ironie : {{Citation|L'ironie de Socrate est-elle une expression de révolte ? un ressentiment de la populace ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Ausdruck von Revolte''}} ; {{lang|de|''Pöbel-Ressentiment''}}.</ref> Le terme « ressentiment », que Nietzsche écrit en français, est l'un des concepts clés de la ''Généalogie de la morale''. La formule de Nietzsche est tranchante : {{Citation|L'ironie du dialecticien est la férocité de la vengeance plébéienne : les opprimés ont leur férocité dans les froids coups de couteau du syllogisme.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''die Ferocität der Pöbel-Rache''}}.</ref> Il importe ici de distinguer deux usages du ressentiment. Dans la ''Généalogie de la morale'', le ressentiment est créateur : il invente des valeurs, forge le couple « bon / méchant » et prend sa revanche de façon imaginaire, sur le terrain moral<ref>''Généalogie de la morale'', première dissertation, § 10 ; KSA 5, {{pp.|270-273}}.</ref>. Au § 7, l'ironie dialectique ne crée pas de valeurs nouvelles : elle fournit une arme tactique dans l'''agôn'' intellectuel, qui humilie l'adversaire et le rend impuissant. La continuité tient au mécanisme, la vengeance de qui ne peut agir directement ; la différence tient au terrain, la transvaluation morale d'un côté, le duel argumentatif de l'autre. Le mécanisme est précisé : « Le dialecticien laisse à son adversaire le soin de prouver qu'il n'est pas un idiot ; il le rend furieux et impuissant à la fois. Le dialecticien dépotentialise ({{lang|de|''depotenzirt''}}) l'intellect de son adversaire. » La dialectique ne convainc pas : elle neutralise. === § 8 : Socrate « érotique » et le nouvel ''agôn'' === Brève section qui introduit une dimension inattendue : {{Citation|Socrate était aussi un grand érotique.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 8 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Sokrates war auch ein grosser Erotiker''}}.</ref> L'allusion au rôle de Socrate dans le ''Banquet'' de Platon est transparente. Mais Nietzsche fait surtout de la dialectique une nouvelle forme d'''agôn'', une lutte inédite offerte à ceux qui ne pouvaient plus lutter autrement. Roche le formule ainsi : Socrate « vient à point nommé » lorsque l'instinct de combat (''agôn'') et de conquête (''eros'') ne trouve plus à s'employer dans une vie créatrice de formes et d'institutions nouvelles. Le tournoi dialectique remplace alors le concours gymnique ou poétique. La fascination qu'il exerce a son revers : certains interlocuteurs s'en plaignent, tel Ménon, qui se dit engourdi par Socrate comme par la torpille, ce poisson dont la décharge paralyse, la paralysie étant ici une figure de la fascination<ref>Platon, ''Ménon'', 80a-c.</ref>. Là où Zeller, puis Franz Susemihl, spiritualisaient l'éros socratique, Nietzsche réintroduit l'élément sensuel que la tradition académique tendait à occulter<ref>Franz Susemihl, « {{lang|de|Ueber die composition des platonischen gastmahls}} », {{lang|de|''Philologus''}}, 1851.</ref>. === § 9 : Socrate, témoin lucide du déclin === La section opère un renversement partiel : Socrate n'est plus seulement l'agent du déclin, il en est le témoin clairvoyant. {{Citation bloc|Il regarda derrière ses nobles Athéniens ; il comprit que son cas, son idiosyncrasie de cas, n'était déjà plus un cas exceptionnel. La même espèce de dégénérescence se préparait partout en silence : la vieille Athènes touchait à sa fin.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Degenerescenz''}}.</ref>}} Nietzsche lui reconnaît une lucidité diagnostique : « Partout les instincts étaient en anarchie ; partout on était à cinq pas de l'excès. » Le paragraphe reprend l'anecdote du physiognomoniste sous une seconde version, plus proche de la tradition cicéronienne : {{Citation|C'est vrai, dit-il, mais je suis devenu maître de toutes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Dies ist wahr, aber ich wurde über alle Herr''}}.</ref> Les deux répliques que Nietzsche prête à Socrate (« Vous me connaissez, Monsieur ! » au § 3, « je suis devenu maître de toutes » ici) renvoient à la même anecdote, celle de Zopyre, transmise par Cicéron<ref>Cicéron, ''Tusculanes'', IV, 80 ; voir aussi ''De Fato'', V, 10.</ref>. Sommer souligne que cette section rapproche l'Athènes du Ve siècle avant notre ère de l'Europe du {{XIXe}} siècle : dans les deux cas s'impose un diagnostic de décadence, et le philosophe (Socrate hier, Nietzsche aujourd'hui) intervient en médecin de la culture. === § 10 : La raison érigée en tyran === Le cœur de l'argumentation : {{Citation bloc|Quand on a besoin de faire de la raison un tyran, comme fit Socrate, il faut que le danger soit considérable de voir quelque chose d'autre jouer le tyran.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}.</ref>}} Ce quelque chose d'autre, ce sont les instincts. La raison n'est pas érigée en maîtresse par amour de la vérité, mais par nécessité vitale de contrôle. Roche parle d'un « contre-tyran » : lorsque les instincts, n'étant plus guidés par une force créatrice, deviennent eux-mêmes tyranniques, il faut leur opposer une instance plus forte qu'eux, la raison. Le rationalisme n'est donc pas un choix de la raison, mais une exigence de la vie déclinante, son ultime planche de salut. L'équation {{lang|de|2=''Vernunft = Tugend = Glück''}} (raison = vertu = bonheur), introduite au § 4, est ici reprise et qualifiée. Nietzsche conclut : {{Citation|Le moralisme des philosophes grecs à partir de Platon est pathologiquement conditionné.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''pathologisch bedingt''}}.</ref> Comme le note Sommer, c'est la seule occurrence explicite du champ lexical de la pathologie dans tout le ''Crépuscule des idoles'', ce qui en souligne le poids. === § 11 : L'équivoque du remède socratique === Cette section examine l'efficacité apparente du remède : {{Citation|Il semblait être un médecin, un sauveur.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''er schien ein Arzt, ein Heiland zu sein''}}.</ref> La métaphore du philosophe-médecin de l'âme est platonicienne, mais Nietzsche la retourne : Socrate n'était pas un vrai médecin, car sa thérapie était illusoire<ref>Sur le philosophe comme médecin de l'âme chez Platon, voir notamment le ''Gorgias''.</ref>. La mise au pas des instincts par la raison ne guérit pas la décadence : elle la masque et la prolonge. D'où la formule définitionnelle : {{Citation bloc|Devoir combattre les instincts, c'est la formule de la décadence : tant que la vie est ascendante, bonheur égale instinct.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|73}}. Texte allemand : {{lang|de|''Glück gleich Instinkt''}}.</ref>}} Ce paragraphe introduit la distinction, importante pour la suite du livre, entre vie ascendante ({{lang|de|''aufsteigendes Leben''}}) et vie descendante. === § 12 : La mort volontaire de Socrate === [[Fichier:Jacques-Louis David - The Death of Socrates - Google Art Project.jpg|vignette|gauche|''La Mort de Socrate'' (Jacques-Louis David, 1787), New York, Metropolitan Museum of Art. Socrate saisit la coupe de ciguë tout en poursuivant son discours.]] Le chapitre s'achève sur une interprétation de la mort de Socrate : {{Citation bloc|Socrate voulait mourir : ce n'est pas Athènes, c'est lui qui se donna la coupe de ciguë, il força Athènes à la coupe de ciguë.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Nietzsche s'appuie sur Jacob Burckhardt, qui notait que Socrate « voulait effectivement la mort »<ref>Jacob Burckhardt, ''{{lang|de|Griechische Kulturgeschichte}}''.</ref>. La fin du chapitre forme une boucle avec le début : les dernières paroles sont réinterprétées une dernière fois. {{Citation bloc|Socrate n'est pas un médecin, se dit-il tout bas : ici la mort seule est médecin… Socrate lui-même n'avait fait qu'être longtemps malade…<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Reconnaissant l'échec de sa thérapie rationnelle, Socrate ne conclut plus que la vie est une maladie, mais que seule sa vie l'était. L'ironie finale est que cette lucidité ferait de lui, conformément à l'oracle de Delphes, le plus sage des hommes, d'une sagesse qui pourtant se nie elle-même. Cette reprise variée de l'ouverture scelle la composition rigoureuse de l'ensemble du chapitre. == Étude de passage : § 4 et § 9 == Le passage le plus délicat est celui qui articule le diagnostic individuel et le diagnostic collectif. Au § 4, Nietzsche cherche l'« idiosyncrasie » d'où procède l'équation « raison = vertu = bonheur ». Au § 9, cette idiosyncrasie cesse d'être un cas isolé. L'italique de Nietzsche sur « derrière » ({{lang|de|''hinter''}}) et sur « son » cas ({{lang|de|''sein''}}) est significatif : le premier indique que Socrate perçoit ce que dissimule la façade aristocratique, le second souligne le retournement par lequel une anomalie individuelle se révèle être un état généralisé. Le jeu sur {{lang|de|''Fall''}} (à la fois « cas » et « chute ») renforce la dimension diagnostique. Le terme {{lang|de|''Degenerescenz''}} mérite attention : Nietzsche l'emprunte à Féré, où il désigne un processus de dégradation héréditaire observé chez les criminels et les aliénés cliniquement internés. En l'appliquant à l'Athènes classique, Nietzsche opère un transfert provocateur : la civilisation tenue pour l'apogée de la culture grecque serait en réalité un organisme en décomposition. == Controverses interprétatives == Les grandes lectures du chapitre se distinguent par l'axe qu'elles privilégient. Lecture métaphysique, chez Martin Heidegger (cours sur Nietzsche, 1936-1940) : la critique de Socrate s'inscrit dans l'histoire de l'oubli de l'Être, le rationalisme socratique inaugurant la métaphysique comme onto-théologie. Heidegger reproche cependant à Nietzsche de demeurer lui-même métaphysicien par sa doctrine de la volonté de puissance. Lecture psychologique et admirative, chez Walter Kaufmann : loin d'une condamnation sans appel, le rapport de Nietzsche à Socrate serait celui d'une rivalité entre deux philosophes-médecins. ''Par-delà bien et mal'' (§ 212) reconnaît d'ailleurs à la thérapie socratique une légitimité « pour son temps »<ref>''Par-delà bien et mal'', § 212 ; KSA 5, {{pp.|146-147}}.</ref>. Lecture philologique et contextualiste, chez Andreas Urs Sommer, et lecture médicale et stratégique, chez Sabine Wahrig-Schmidt : toutes deux insistent sur le rôle des sources médicales de 1888, mais en tirent des accents différents. Sommer reconstitue précisément les emprunts et les variantes manuscrites ; Wahrig-Schmidt met en garde contre une lecture littérale, le vocabulaire médical étant mobilisé de manière stratégique, pour subvertir les valorisations traditionnelles, non pour livrer un diagnostic clinique. Lecture rhétorique et auto-référentielle, enfin, chez Bruno Roche, Yannick Souladié et Enrico Müller : Nietzsche critique la dialectique tout en l'utilisant, dénonce l'ironie comme ressentiment tout en la pratiquant. Müller parle d'une « figure d'interprétation paradoxale » par laquelle la pathologie socratique est elle-même pathologisée, le véritable médecin n'étant plus Socrate mais Nietzsche. La tension se lit comme une aporie ou comme une ironie au second degré : on ne sortirait de la dialectique qu'en la traversant. Une objection de fond mérite d'être mentionnée. Roche fait observer qu'en présentant Socrate comme l'idolâtre de la raison, Nietzsche paraît oublier que, pour Socrate, la dialectique n'atteint jamais tout à fait son terme, le Bien demeurant ineffable et transcendant ; cette transcendance interdirait précisément de lire le socratisme comme une idolâtrie de la raison, contrairement à ce que suggère le § 10. Roche relève en outre une tension interne à l'œuvre : le ''Crépuscule'' fait de Socrate un coupable, alors que la logique déterministe de Nietzsche, comme ses autres textes, n'en font qu'un symptôme du déclin, c'est-à-dire un destin et non une faute. Dans une autre direction, Gilles Deleuze (''Nietzsche et la philosophie'', 1962) souligne le caractère anti-dialectique de la pensée nietzschéenne : ce que Nietzsche récuse chez Platon, l'idée que la raison puisse fonder par concepts successifs un inconditionné, il le récuse aussi bien chez Hegel, faute d'admettre une quelconque puissance créatrice de la négativité. == Ce que Nietzsche affirme et ce qu'on lui prête == Nietzsche affirme : que le jugement négatif des philosophes sur la vie est un symptôme de déclin vital, non une vérité objective ; que Socrate souffrait d'une anarchie des instincts qu'il a maîtrisée en faisant de la raison un tyran ; que l'équation « raison = vertu = bonheur » rompt avec les instincts de l'ancien hellénisme ; que la dialectique est l'arme des faibles, une forme de ressentiment ; que la philosophie depuis Socrate est « pathologiquement conditionnée ». On lui prête à tort un rejet total de la raison : il ne condamne pas la raison comme telle, mais son érection en tyran contre les instincts, revendiquant pour lui-même une « clarté de dialecticien »<ref>''Ecce Homo'', « Pourquoi je suis si sage », § 1 ; KSA 6, {{p.|265}}.</ref>. On lui prête à tort un éloge inconditionnel des instincts : l'idéal est leur coordination hiérarchique, non leur anarchie, laquelle est précisément le symptôme de la décadence. On lui prête à tort une condamnation morale de Socrate : sa critique se veut « physiologique », non un blâme. On lui prête enfin à tort l'identification de Socrate à un criminel : la question « Socrate était-il un criminel typique ? » est une provocation reposant sur une inférence invalide, et Nietzsche réserve par ailleurs au criminel une réelle sympathie, le tenant pour « le type de l'homme fort placé dans des conditions défavorables »<ref>''Crépuscule des idoles'', « Flâneries d'un inactuel », § 45 ; KSA 6, {{p.|146}}.</ref>. Or tel n'est précisément pas le Socrate qu'il décrit. == Synthèse == Le chapitre développe, en douze sections rigoureusement composées, une thèse à plusieurs niveaux. Au plan physiologique, Socrate est un décadent dont les instincts sont désagrégés. Au plan historique, l'Athènes du Ve siècle traverse une crise dont Socrate généralise la solution personnelle. Au plan philosophique, l'équation « raison = vertu = bonheur » ouvre, selon Nietzsche, une longue tradition tendant à subordonner la vie à la raison et à la morale. Au plan stratégique, s'attaquer à l'idole Socrate permet de viser l'ensemble de la tradition rationaliste et moraliste, et de préparer ''L'Antéchrist''. La structure suit un crescendo : ouverture sur les dernières paroles de Socrate (§ 1), portrait physiologique et anthropologique (§ 3-4), analyse de la dialectique comme arme des faibles (§ 5-8), diagnostic de la raison-tyran (§ 9-11), puis reprise variée de l'ouverture (§ 12). L'ambivalence persiste néanmoins : Socrate est aussi reconnu clairvoyant (§ 9), et sa mort volontaire revêt une forme de sagesse (§ 12). Nietzsche semble reconnaître en lui un adversaire à sa mesure, voire un prédécesseur dans la tâche de médecin de la culture, ce qui fragilise l'apparente univocité de la condamnation. == Notes et références == {{Références|colonnes=2}} == Sources anciennes == Platon, ''Apologie'', ''Criton'', ''Phédon'', ''Banquet'', ''Ménon'' ; Xénophon, ''Mémorables'', ''Banquet'' ; Aristophane, ''Les Nuées'' ; Cicéron, ''Tusculanes'' IV, 80 (anecdote de Zopyre). == Liens externes == * Le chapitre en traduction française : [[s:Le Crépuscule des Idoles/Le Problème de Socrate|« Le Problème de Socrate »]], trad. Henri Albert, Mercure de France, 1908, sur Wikisource. p3mx3w4505rl7011zzpw8s7nfcq7abd 768753 768752 2026-06-27T05:13:13Z PandaMystique 119061 /* § 9 : Socrate, témoin lucide du déclin */ 768753 wikitext text/x-wiki {| style="width:100%; margin:1em 0; background:#f3f6fb; border:1px solid #d9e2ef; border-radius:14px; border-collapse:separate; border-spacing:0; box-shadow:0 2px 8px rgba(0,0,0,.06); font-size:92%;" |- | style="padding:10px 14px; width:25%;" |[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/Maximes et Traits|Maximes et Traits]] | style="padding:12px 14px; text-align:center; width:50%;"| <div style="font-size:145%; font-weight:600; color:#324a72; line-height:1.15;">'''''Crépuscule des idoles'''''</div> <div style="margin-top:3px; font-size:98%; color:#556b86; line-height:1.5;">'''ou Comment on philosophe avec un marteau '''</div> | style="padding:10px 14px; text-align:right; width:25%;"|[[Nietzsche : Introduction à sa philosophie/Crépuscule des idoles/La « raison » dans la philosophie|La « raison » dans la philosophie]] |} {{Haut de page|Philosophie/Nietzsche/Crépuscule des idoles/Sommaire}} == Introduction : que signifie mettre Socrate en procès ? == [[Fichier:Socrates Louvre.jpg|vignette|upright|Buste de Socrate, copie romaine du {{Ier}} siècle d'après un original grec parfois attribué à Lysippe. Paris, musée du Louvre.]] Peut-on juger de la valeur de la vie ? Et si la question, en elle-même, révélait déjà une maladie ? Telle est l'interrogation qui ouvre le deuxième chapitre du ''Crépuscule des idoles'' ({{lang|de|''Götzen-Dämmerung''}}), intitulé « Le problème de Socrate » ({{lang|de|''Das Problem des Sokrates''}}). Nietzsche y soumet Socrate, figure fondatrice de la philosophie morale occidentale, à un examen sans ménagement : loin d'incarner l'apogée de la sagesse grecque, Socrate en marquerait, selon lui, le déclin. Son rationalisme serait le symptôme d'une dégénérescence physiologique : la raison devient un tyran là où les instincts fléchissent. Cette thèse s'inscrit dans une stratégie plus vaste : en brisant l'idole Socrate, Nietzsche entend ébranler tout l'édifice de la tradition rationaliste et morale. == Contexte : genèse et place du chapitre == Dans les manuscrits préparatoires (Mappe XVI 4), le chapitre portait d'abord le titre « {{lang|de|Sokrates als Problem}} » (« Socrate comme problème »), avant d'être intégré à un projet plus vaste sur « la philosophie comme {{lang|fr|décadence}} »<ref>KSA 14, {{p.|413}}. La référence éditoriale renvoie à Friedrich Nietzsche, {{lang|de|''Sämtliche Werke. Kritische Studienausgabe''}} (KSA), éd. G. Colli et M. Montinari, Berlin/Munich, De Gruyter/dtv, 1980.</ref>. Le matériau brut du chapitre se trouve rassemblé dans le fragment posthume NL 1888, KSA 13, 14[92] (KSA 13, {{pp.|268-270}}). C'est dans un fragment distinct, lié au plan de la [[Nietzsche : Introduction à sa philosophie/Volonté de puissance|volonté de puissance]] (« {{lang|de|Wille zur Macht}} »), que Socrate est qualifié de « moment de la plus profonde perversité dans l'histoire de l'humanité »<ref>NL 1888, KSA 13, 14[111] (KSA 13, {{p.|289}}) ; voir le commentaire de Sommer, qui rattache cette note au projet d'un chapitre sur « la philosophie comme {{lang|fr|décadence}} ».</ref>. La critique de Socrate traverse l'œuvre nietzschéenne depuis ''La Naissance de la tragédie'' (1872), où le philosophe athénien apparaît comme l'« archétype de l'optimiste théorique » ({{lang|de|''Urbild des theoretischen Optimisten''}})<ref>''La Naissance de la tragédie'', § 15 ; KSA 1, {{p.|100}}.</ref>. Nietzsche y opposait l'[[Nietzsche : Introduction à sa philosophie/L'Apollinien et le Dionysien|esprit dionysien]], tragique et affirmatif, au rationalisme socratique qui aurait détruit la culture tragique grecque. Dans le ''Crépuscule'', cette critique se charge d'une dimension physiologique nouvelle : sous l'influence de lectures médicales récentes, notamment Charles Féré (''Dégénérescence et criminalité'', 1888) et l'anthropologie criminelle de Cesare Lombroso, Nietzsche interprète Socrate en termes pathologiques : il est désormais présenté comme {{lang|fr|décadent}}. Le durcissement du jugement est net : Socrate est recodé comme négateur de la vie. Le chapitre conserve néanmoins une réelle ambivalence, puisque Socrate y est aussi présenté comme stratège, inventeur d'un nouvel ''agôn'', « grand érotique » (§ 8) et témoin lucide du déclin athénien (§ 9). Le durcissement porte donc sur l'évaluation d'ensemble, non sur la reconnaissance de la puissance de Socrate. == La thèse centrale == Nietzsche soutient que la philosophie socratique, avec son équation « raison = vertu = bonheur », constitue non pas une conquête de l'esprit, mais le symptôme d'une dégénérescence ({{lang|de|''Degenerescenz''}}). Les « instincts en anarchie » de Socrate l'auraient contraint à ériger la raison en tyran pour se maîtriser. Cette solution individuelle, généralisée à une civilisation en déclin (l'Athènes du Ve siècle avant notre ère), aurait inauguré, selon Nietzsche, une longue tradition philosophique tendant à subordonner la vie à la raison et à la morale. La {{lang|fr|décadence}}, terme que Nietzsche emprunte à la critique littéraire française (Paul Bourget) avant de lui conférer une charge physiologique, désigne ici la désagrégation des instincts vitaux et l'incapacité à affirmer l'existence. == Analyse des douze sections == === § 1 : Le jugement des sages sur la vie === Le chapitre s'ouvre sur un constat provocateur : {{Citation|Sur la vie, de tout temps, les plus sages ont porté le même jugement : elle ne vaut rien…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''Über das Leben haben zu allen Zeiten die Weisesten gleich geurtheilt: es taugt nichts…''}}</ref> Nietzsche prête à ces sages quatre tonalités convergentes : un son « plein de doute, plein de mélancolie, plein de lassitude de la vie, plein de résistance contre la vie ». L'unanimité visée est celle des philosophes, de Socrate aux pessimistes contemporains, qui auraient déprécié l'existence. Vient alors l'exemple de Socrate mourant, qu'il faut citer avec précision, car Nietzsche ne reprend pas Platon mot pour mot. Le ''Phédon'' (118a) porte, au pluriel, « Ô Criton, nous devons un coq à Asclépios ». Littéralement, Socrate demande seulement qu'on acquitte une dette cultuelle envers Asclépios, dieu de la médecine : le coq était l'offrande traditionnelle que l'on faisait au dieu après une guérison. L'idée que cette guérison désignerait la vie elle-même n'est pas le sens littéral de la phrase, mais une interprétation rendue plausible par le contexte religieux et médical. Nietzsche, de fait, donne une version déjà interprétée, au singulier et augmentée : {{Citation|vivre, c'est être longtemps malade : je dois un coq au sauveur Asclépios.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''leben — das heisst lange krank sein: ich bin dem Heilande Asklepios einen Hahn schuldig''}}. La traduction française de référence (Henri Albert, 1908) rend le passage : « Vivre — c'est être longtemps malade : je dois un coq à Esculape libérateur. »</ref> Le mot « sauveur » ({{lang|de|''Heiland''}}) et l'ajout « vivre, c'est être longtemps malade » insèrent dans la bouche de Socrate la lecture que Nietzsche veut en tirer. Cette interprétation, déjà présente dans ''Le Gai Savoir'' (§ 340), prolonge une tradition exégétique que Nietzsche connaissait depuis Pforta : son professeur de grec Karl Steinhart avait commenté ce passage en écrivant que Socrate « se sent guéri de la maladie de la vie terrestre et libéré des liens entravants du corps »<ref>Karl Steinhart, dans ses annotations à la traduction de Platon, Leipzig, 1854, {{p.|577}}. Nietzsche avait emprunté plusieurs fois cette édition à la bibliothèque universitaire de Bâle (Crescenzi).</ref>. La section se referme sur une question puis une image. À l'argument traditionnel (« Le {{lang|la|consensus sapientium}} prouve la vérité »), Nietzsche substitue le soupçon : « Il doit bien y avoir ici quelque chose de malade. » Puis vient la métaphore qui clôt réellement le paragraphe : {{Citation|La sagesse n'apparaîtrait-elle pas sur terre comme un corbeau qu'une petite odeur de charogne met en joie ?…}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 1 ; KSA 6, {{p.|67}}. Texte allemand : {{lang|de|''als Rabe, den ein kleiner Geruch von Aas begeistert''}}.</ref> L'image substitue au symbole noble de la philosophie (la chouette de Minerve) un charognard attiré par ce qui décline. On peut y entendre, avec Sommer, des échos interprétatifs plutôt que des sources attestées : le corbeau, oiseau ambivalent, est aussi associé à la sagesse (les corbeaux d'Odin) et apparaît chez Wagner (''{{lang|de|Götterdämmerung}}'', dont le titre est proche du {{lang|de|''Götzen-Dämmerung''}} nietzschéen). Ces rapprochements éclairent la portée du passage sans qu'on puisse les tenir pour ses sources certaines. === § 2 : Symptomatologie et valeur de la vie === [[Fichier:Plato Silanion Musei Capitolini MC1377.jpg|vignette|upright|Buste de Platon, copie romaine d'après un original grec du IVe siècle av. J.-C. Nietzsche associe Socrate et Platon comme « symptômes de déclin ».]] Le pivot méthodologique se trouve ici. Nietzsche renvoie d'abord explicitement à son premier livre : {{Citation|J'ai reconnu Socrate et Platon comme des symptômes de déclin, comme pseudo-grecs, anti-grecs (''Naissance de la tragédie'', 1872).}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Verfalls-Symptome''}}.</ref> Le {{lang|la|consensus}} des sages reçoit alors sa réinterprétation : il « prouve bien plutôt qu'eux-mêmes, ces très sages, concordaient physiologiquement sur quelque point, pour se tenir de la même façon négativement devant la vie »<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}.</ref>. De là découle la thèse épistémologique : {{Citation|Les jugements de valeur sur la vie, pour ou contre, ne peuvent en fin de compte jamais être vrais : ils n'ont de valeur que comme symptômes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 2 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Symptome''}}.</ref> La raison en est que la valeur de la vie est inévaluable. La formulation exacte de Nietzsche est : « cette étonnante finesse, que la valeur de la vie ne peut pas être évaluée » ({{lang|de|''dass der Werth des Lebens nicht abgeschätzt werden kann''}}). Le vivant ne peut évaluer la vie, « parce qu'il est partie, voire objet du litige, et non juge » ; le mort ne le peut pas non plus, pour une autre raison laissée ironiquement implicite. L'expression « valeur de la vie » ({{lang|de|''Werth des Lebens''}}) fait écho au titre de l'ouvrage d'Eugen Dühring (''{{lang|de|Der Werth des Lebens}}'', 1865), que Nietzsche avait longuement excerpté en 1875<ref>NL 1875, KSA 8, 9[1] (KSA 8, {{pp.|131-181}}). Henri Albert signale d'ailleurs en note que la pointe vise Dühring, auteur de ''La Valeur de la vie''.</ref>. La conclusion renverse les termes : qu'un philosophe voie un problème dans la valeur de la vie est « une objection contre lui, un point d'interrogation sur sa sagesse, une non-sagesse ({{lang|de|''Unweisheit''}}) ». Le paragraphe s'achève sur une transition vers la suite : « Mais je reviens au problème de Socrate. » === § 3 : Basse extraction, laideur et anthropologie criminelle === Cette section concentre l'argument physiognomonique : {{Citation|Socrate appartenait, par son origine, au plus bas peuple : Socrate était populace. On sait, on voit encore aujourd'hui combien il était laid.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|68}}. Texte allemand : {{lang|de|''Pöbel''}}.</ref> La laideur de Socrate était de notoriété antique (Platon, ''Banquet'' 215a-b et 221d-e, comparaison avec le silène Marsyas ; Xénophon, ''Banquet'' IV, 19 et V, 5-7, le concours de beauté). Nietzsche s'appuie surtout sur Eduard Zeller, qui notait le contraste « non grec » entre l'apparence de Socrate et l'idéal d'harmonie du corps et de l'âme<ref>Eduard Zeller, ''{{lang|de|Die Philosophie der Griechen}}'', 2{{e}} partie, Tübingen, 1859, {{pp.|59-60}}.</ref>. Là où Zeller voyait une tension, Nietzsche lit un verdict : « La laideur, en elle-même déjà une objection, est chez les Grecs presque une réfutation. Socrate était-il même un Grec ? » Vient ensuite le rapprochement avec le criminel : {{Citation|Les anthropologues parmi les criminalistes nous disent que le criminel typique est laid : {{lang|la|monstrum in fronte, monstrum in animo}}. Mais le criminel est un décadent. Socrate était-il un criminel typique ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}.</ref> Deux précisions s'imposent. D'abord, la source : la formule latine et la référence à Lombroso proviennent directement de Charles Féré, passage que Nietzsche avait souligné<ref>Charles Féré, ''Dégénérescence et criminalité'', Paris, Alcan, 1888, {{p.|80}}. La concordance des extraits figure chez Lampl (1986).</ref>. Ensuite, la portée logique : Nietzsche ne déclare pas que Socrate est un criminel. Il pose une question (figure de la ''dubitatio'') et procède par une inférence sciemment invalide (les criminels sont laids ; Socrate est laid ; donc Socrate serait criminel), c'est-à-dire une affirmation du conséquent, comme l'ont relevé Sommer et Pichler. Le scandale réside moins dans le contenu que dans la posture : Nietzsche se range un instant du côté des accusateurs de Socrate. L'anecdote du physiognomoniste vient confirmer la provocation : un étranger expert en visages dit à Socrate qu'il recèle « tous les mauvais vices et appétits », et Socrate répond simplement : {{Citation|Vous me connaissez, Monsieur !}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 3 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Sie kennen mich, mein Herr!''}}</ref> === § 4 : Les signes de la décadence et l'équation socratique === Ce paragraphe ne reprend pas l'anecdote du physiognomoniste : il en tire les conséquences en énumérant les autres signes de la décadence socratique. {{Citation|La décadence de Socrate ne se trahit pas seulement par l'anarchie avouée de ses instincts : elle se trahit aussi par la superfétation du logique et par cette malveillance bilieuse qui le distingue.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Superfötation des Logischen''}}.</ref> Le terme « superfétation » est emprunté à la médecine (une seconde conception survenant au cours d'une grossesse) : Nietzsche suggère que la faculté logique est pathologiquement surdéveloppée. Sommer note que le rapprochement entre cette « superfétation » et le démon socratique figurait déjà dans ''La Naissance de la tragédie'' (§ 13). Nietzsche médicalise ensuite le fameux ''daimonion'' : {{Citation|N'oublions pas non plus ces hallucinations auditives qui, sous le nom de « démon de Socrate », ont reçu une interprétation religieuse.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}.</ref> La source en est Francis Galton, qui rangeait Socrate parmi les sujets prédisposés aux crises nerveuses et aux hallucinations<ref>Francis Galton, ''Inquiries into Human Faculty and its Development'', Londres, Macmillan, 1883, {{p.|176}}.</ref>. Tout, chez Socrate, serait « exagéré, ''buffo'', caricature ». Le paragraphe s'achève sur la première formulation de l'équation centrale : {{Citation|1=Je cherche à comprendre de quelle idiosyncrasie procède cette équation socratique, raison = vertu = bonheur : la plus bizarre de toutes les équations, qui a contre elle en particulier tous les instincts de l'ancien Hellène.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 4 ; KSA 6, {{p.|69}}. Texte allemand : {{lang|de|''Idiosynkrasie''}}.</ref> Le terme « idiosyncrasie », médical, désigne une constitution organique singulière : la philosophie socratique exprime une pathologie individuelle, non une vérité universelle. Les manuscrits consignent une équation alternative, antérieure à Socrate<ref>Variante des manuscrits préparatoires (Mp XVI 4) : {{lang|de|2=''Tugend = Instinkt = Grund-Unbewußtheit''}} (« vertu = instinct = inconscience fondamentale »), KSA 14, {{pp.|413-414}}.</ref>. === § 5 : La dialectique comme défaite du goût aristocratique === Nietzsche aborde ici la dialectique et observe un renversement du goût : {{Citation|Avec Socrate, le goût grec bascule en faveur de la dialectique : que se passe-t-il là au juste ? Avant tout, un goût distingué s'en trouve vaincu ; avec la dialectique, la populace l'emporte.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 5 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''der Pöbel kommt mit der Dialektik obenauf''}}.</ref> Avant Socrate, « on rejetait dans la bonne société les manières dialectiques ; elles passaient pour de mauvaises manières, elles compromettaient ». L'homme bien né n'a pas besoin de prouver : il possède l'autorité. « Il est indécent de montrer ses cinq doigts. Ce qui a besoin d'abord d'être prouvé n'a que peu de valeur. » Bruno Roche éclaire l'enjeu social de ce basculement. La logique à l'œuvre dans la dialectique tend à ramener les différences à l'identique, à rendre l'autre (le noble, l'élevé) égal à soi (le commun). Là où la hiérarchie aristocratique repose sur des distinctions que la vie pose d'elle-même, la dialectique introduit un principe d'uniformisation, en ouvrant à tous l'accès à l'idée et au savoir. Le savoir antique était un bien rare, réservé à un petit nombre (ésotérique) ; avec Socrate, il devient exotérique, accessible au plus grand nombre, et la plèbe revendique le droit de penser. L'expression « étalage de raisons » ({{lang|de|''Etalage von Gründen''}}) emploie un gallicisme que Nietzsche affectionne. La dialectique se présente ainsi comme l'arme de qui ne dispose pas de l'autorité naturelle. === § 6 : La dialectique comme légitime défense === [[Fichier:Reineke Fuchs.jpg|vignette|Reineke Fuchs, gravure d'après Wilhelm von Kaulbach (édition Cotta, 1857). Le goupil échappe deux fois à la mort par son habileté de parole : image du dialecticien impuissant selon Nietzsche.]] Nietzsche resserre : {{Citation|La dialectique ne peut être qu'une légitime défense.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 6 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Nothwehr''}}.</ref> Elle est l'arme de qui n'en possède pas d'autre, le recours de celui qui doit arracher son droit par la discussion faute de pouvoir l'imposer. Le texte publié range dans cette catégorie trois figures : {{Citation|Les Juifs étaient pour cette raison dialecticiens ; Reineke Fuchs l'était ; et Socrate l'était-il aussi ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 6 ; KSA 6, {{p.|70}}, l. 17. Texte allemand : {{lang|de|''Die Juden waren deshalb Dialektiker; Reineke Fuchs war es; Sokrates war es auch?''}}</ref> Le rapprochement appelle un cadrage. La mention des Juifs reprend un lieu commun de l'époque : l'idée d'une « dialectique juive » ou « rabbinique » circulait dans les lectures de Nietzsche, de Luther à Herder et à David Friedrich Strauss, comme le documente Sommer. Quant à ''Reineke Fuchs'', le goupil de l'épopée de Goethe que Nietzsche connaissait par Victor Hehn, il échappe par deux fois à la mort grâce à son habileté de parole. Le motif commun aux trois figures est que la dialectique est, selon Nietzsche, le propre du déraciné et du faible, qui compensent par la ruse argumentative une infériorité de position. Roche en précise le ressort : l'efficacité de la dialectique tient à ce qu'elle fait douter le fort en le sommant de justifier sa force ; le faible l'emporte le jour où le fort, contraint de s'expliquer, en vient à douter de lui-même. === § 7 : L'ironie socratique comme ressentiment === Cette section traite de l'ironie : {{Citation|L'ironie de Socrate est-elle une expression de révolte ? un ressentiment de la populace ?}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''Ausdruck von Revolte''}} ; {{lang|de|''Pöbel-Ressentiment''}}.</ref> Le terme « ressentiment », que Nietzsche écrit en français, est l'un des concepts clés de la ''Généalogie de la morale''. La formule de Nietzsche est tranchante : {{Citation|L'ironie du dialecticien est la férocité de la vengeance plébéienne : les opprimés ont leur férocité dans les froids coups de couteau du syllogisme.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 7 ; KSA 6, {{p.|70}}. Texte allemand : {{lang|de|''die Ferocität der Pöbel-Rache''}}.</ref> Il importe ici de distinguer deux usages du ressentiment. Dans la ''Généalogie de la morale'', le ressentiment est créateur : il invente des valeurs, forge le couple « bon / méchant » et prend sa revanche de façon imaginaire, sur le terrain moral<ref>''Généalogie de la morale'', première dissertation, § 10 ; KSA 5, {{pp.|270-273}}.</ref>. Au § 7, l'ironie dialectique ne crée pas de valeurs nouvelles : elle fournit une arme tactique dans l'''agôn'' intellectuel, qui humilie l'adversaire et le rend impuissant. La continuité tient au mécanisme, la vengeance de qui ne peut agir directement ; la différence tient au terrain, la transvaluation morale d'un côté, le duel argumentatif de l'autre. Le mécanisme est précisé : « Le dialecticien laisse à son adversaire le soin de prouver qu'il n'est pas un idiot ; il le rend furieux et impuissant à la fois. Le dialecticien dépotentialise ({{lang|de|''depotenzirt''}}) l'intellect de son adversaire. » La dialectique ne convainc pas : elle neutralise. === § 8 : Socrate « érotique » et le nouvel ''agôn'' === Brève section qui introduit une dimension inattendue : {{Citation|Socrate était aussi un grand érotique.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 8 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Sokrates war auch ein grosser Erotiker''}}.</ref> L'allusion au rôle de Socrate dans le ''Banquet'' de Platon est transparente. Mais Nietzsche fait surtout de la dialectique une nouvelle forme d'''agôn'', une lutte inédite offerte à ceux qui ne pouvaient plus lutter autrement. Roche le formule ainsi : Socrate « vient à point nommé » lorsque l'instinct de combat (''agôn'') et de conquête (''eros'') ne trouve plus à s'employer dans une vie créatrice de formes et d'institutions nouvelles. Le tournoi dialectique remplace alors le concours gymnique ou poétique. La fascination qu'il exerce a son revers : certains interlocuteurs s'en plaignent, tel Ménon, qui se dit engourdi par Socrate comme par la torpille, ce poisson dont la décharge paralyse, la paralysie étant ici une figure de la fascination<ref>Platon, ''Ménon'', 80a-c.</ref>. Là où Zeller, puis Franz Susemihl, spiritualisaient l'éros socratique, Nietzsche réintroduit l'élément sensuel que la tradition académique tendait à occulter<ref>Franz Susemihl, « {{lang|de|Ueber die composition des platonischen gastmahls}} », {{lang|de|''Philologus''}}, 1851.</ref>. === § 9 : Socrate, témoin lucide du déclin === La section opère un renversement partiel : Socrate n'est plus seulement l'agent du déclin, il en est le témoin clairvoyant. {{Citation bloc|Il regarda derrière ses nobles Athéniens ; il comprit que son cas, son idiosyncrasie de cas, n'était déjà plus un cas exceptionnel. La même espèce de dégénérescence se préparait partout en silence : la vieille Athènes touchait à sa fin.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Degenerescenz''}}.</ref>}} Nietzsche lui reconnaît une lucidité diagnostique : « Partout les instincts étaient en anarchie ; partout on était à cinq pas de l'excès. » Le paragraphe reprend l'anecdote du physiognomoniste sous une seconde version, plus proche de la tradition cicéronienne : {{Citation|C'est vrai, dit-il, mais je suis devenu maître de toutes.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 9 ; KSA 6, {{p.|71}}. Texte allemand : {{lang|de|''Dies ist wahr, aber ich wurde über alle Herr''}}.</ref> Les deux répliques que Nietzsche prête à Socrate (« Vous me connaissez, Monsieur ! » au § 3, « je suis devenu maître de toutes » ici) renvoient à la même anecdote, celle de Zopyre, transmise par Cicéron<ref>Cicéron, ''Tusculanes'', IV, 80 ; voir aussi ''De Fato'', V, 10.</ref>. Sommer souligne que cette section rapproche l'Athènes du Ve siècle avant notre ère de l'Europe du XIXe siècle : dans les deux cas s'impose un diagnostic de décadence, et le philosophe (Socrate hier, Nietzsche aujourd'hui) intervient en médecin de la culture. === § 10 : La raison érigée en tyran === Le cœur de l'argumentation : {{Citation bloc|Quand on a besoin de faire de la raison un tyran, comme fit Socrate, il faut que le danger soit considérable de voir quelque chose d'autre jouer le tyran.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}.</ref>}} Ce quelque chose d'autre, ce sont les instincts. La raison n'est pas érigée en maîtresse par amour de la vérité, mais par nécessité vitale de contrôle. Roche parle d'un « contre-tyran » : lorsque les instincts, n'étant plus guidés par une force créatrice, deviennent eux-mêmes tyranniques, il faut leur opposer une instance plus forte qu'eux, la raison. Le rationalisme n'est donc pas un choix de la raison, mais une exigence de la vie déclinante, son ultime planche de salut. L'équation {{lang|de|2=''Vernunft = Tugend = Glück''}} (raison = vertu = bonheur), introduite au § 4, est ici reprise et qualifiée. Nietzsche conclut : {{Citation|Le moralisme des philosophes grecs à partir de Platon est pathologiquement conditionné.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 10 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''pathologisch bedingt''}}.</ref> Comme le note Sommer, c'est la seule occurrence explicite du champ lexical de la pathologie dans tout le ''Crépuscule des idoles'', ce qui en souligne le poids. === § 11 : L'équivoque du remède socratique === Cette section examine l'efficacité apparente du remède : {{Citation|Il semblait être un médecin, un sauveur.}}<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|72}}. Texte allemand : {{lang|de|''er schien ein Arzt, ein Heiland zu sein''}}.</ref> La métaphore du philosophe-médecin de l'âme est platonicienne, mais Nietzsche la retourne : Socrate n'était pas un vrai médecin, car sa thérapie était illusoire<ref>Sur le philosophe comme médecin de l'âme chez Platon, voir notamment le ''Gorgias''.</ref>. La mise au pas des instincts par la raison ne guérit pas la décadence : elle la masque et la prolonge. D'où la formule définitionnelle : {{Citation bloc|Devoir combattre les instincts, c'est la formule de la décadence : tant que la vie est ascendante, bonheur égale instinct.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 11 ; KSA 6, {{p.|73}}. Texte allemand : {{lang|de|''Glück gleich Instinkt''}}.</ref>}} Ce paragraphe introduit la distinction, importante pour la suite du livre, entre vie ascendante ({{lang|de|''aufsteigendes Leben''}}) et vie descendante. === § 12 : La mort volontaire de Socrate === [[Fichier:Jacques-Louis David - The Death of Socrates - Google Art Project.jpg|vignette|gauche|''La Mort de Socrate'' (Jacques-Louis David, 1787), New York, Metropolitan Museum of Art. Socrate saisit la coupe de ciguë tout en poursuivant son discours.]] Le chapitre s'achève sur une interprétation de la mort de Socrate : {{Citation bloc|Socrate voulait mourir : ce n'est pas Athènes, c'est lui qui se donna la coupe de ciguë, il força Athènes à la coupe de ciguë.<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Nietzsche s'appuie sur Jacob Burckhardt, qui notait que Socrate « voulait effectivement la mort »<ref>Jacob Burckhardt, ''{{lang|de|Griechische Kulturgeschichte}}''.</ref>. La fin du chapitre forme une boucle avec le début : les dernières paroles sont réinterprétées une dernière fois. {{Citation bloc|Socrate n'est pas un médecin, se dit-il tout bas : ici la mort seule est médecin… Socrate lui-même n'avait fait qu'être longtemps malade…<ref>''Crépuscule des idoles'', « Le problème de Socrate », § 12 ; KSA 6, {{p.|73}}.</ref>}} Reconnaissant l'échec de sa thérapie rationnelle, Socrate ne conclut plus que la vie est une maladie, mais que seule sa vie l'était. L'ironie finale est que cette lucidité ferait de lui, conformément à l'oracle de Delphes, le plus sage des hommes, d'une sagesse qui pourtant se nie elle-même. Cette reprise variée de l'ouverture scelle la composition rigoureuse de l'ensemble du chapitre. == Étude de passage : § 4 et § 9 == Le passage le plus délicat est celui qui articule le diagnostic individuel et le diagnostic collectif. Au § 4, Nietzsche cherche l'« idiosyncrasie » d'où procède l'équation « raison = vertu = bonheur ». Au § 9, cette idiosyncrasie cesse d'être un cas isolé. L'italique de Nietzsche sur « derrière » ({{lang|de|''hinter''}}) et sur « son » cas ({{lang|de|''sein''}}) est significatif : le premier indique que Socrate perçoit ce que dissimule la façade aristocratique, le second souligne le retournement par lequel une anomalie individuelle se révèle être un état généralisé. Le jeu sur {{lang|de|''Fall''}} (à la fois « cas » et « chute ») renforce la dimension diagnostique. Le terme {{lang|de|''Degenerescenz''}} mérite attention : Nietzsche l'emprunte à Féré, où il désigne un processus de dégradation héréditaire observé chez les criminels et les aliénés cliniquement internés. En l'appliquant à l'Athènes classique, Nietzsche opère un transfert provocateur : la civilisation tenue pour l'apogée de la culture grecque serait en réalité un organisme en décomposition. == Controverses interprétatives == Les grandes lectures du chapitre se distinguent par l'axe qu'elles privilégient. Lecture métaphysique, chez Martin Heidegger (cours sur Nietzsche, 1936-1940) : la critique de Socrate s'inscrit dans l'histoire de l'oubli de l'Être, le rationalisme socratique inaugurant la métaphysique comme onto-théologie. Heidegger reproche cependant à Nietzsche de demeurer lui-même métaphysicien par sa doctrine de la volonté de puissance. Lecture psychologique et admirative, chez Walter Kaufmann : loin d'une condamnation sans appel, le rapport de Nietzsche à Socrate serait celui d'une rivalité entre deux philosophes-médecins. ''Par-delà bien et mal'' (§ 212) reconnaît d'ailleurs à la thérapie socratique une légitimité « pour son temps »<ref>''Par-delà bien et mal'', § 212 ; KSA 5, {{pp.|146-147}}.</ref>. Lecture philologique et contextualiste, chez Andreas Urs Sommer, et lecture médicale et stratégique, chez Sabine Wahrig-Schmidt : toutes deux insistent sur le rôle des sources médicales de 1888, mais en tirent des accents différents. Sommer reconstitue précisément les emprunts et les variantes manuscrites ; Wahrig-Schmidt met en garde contre une lecture littérale, le vocabulaire médical étant mobilisé de manière stratégique, pour subvertir les valorisations traditionnelles, non pour livrer un diagnostic clinique. Lecture rhétorique et auto-référentielle, enfin, chez Bruno Roche, Yannick Souladié et Enrico Müller : Nietzsche critique la dialectique tout en l'utilisant, dénonce l'ironie comme ressentiment tout en la pratiquant. Müller parle d'une « figure d'interprétation paradoxale » par laquelle la pathologie socratique est elle-même pathologisée, le véritable médecin n'étant plus Socrate mais Nietzsche. La tension se lit comme une aporie ou comme une ironie au second degré : on ne sortirait de la dialectique qu'en la traversant. Une objection de fond mérite d'être mentionnée. Roche fait observer qu'en présentant Socrate comme l'idolâtre de la raison, Nietzsche paraît oublier que, pour Socrate, la dialectique n'atteint jamais tout à fait son terme, le Bien demeurant ineffable et transcendant ; cette transcendance interdirait précisément de lire le socratisme comme une idolâtrie de la raison, contrairement à ce que suggère le § 10. Roche relève en outre une tension interne à l'œuvre : le ''Crépuscule'' fait de Socrate un coupable, alors que la logique déterministe de Nietzsche, comme ses autres textes, n'en font qu'un symptôme du déclin, c'est-à-dire un destin et non une faute. Dans une autre direction, Gilles Deleuze (''Nietzsche et la philosophie'', 1962) souligne le caractère anti-dialectique de la pensée nietzschéenne : ce que Nietzsche récuse chez Platon, l'idée que la raison puisse fonder par concepts successifs un inconditionné, il le récuse aussi bien chez Hegel, faute d'admettre une quelconque puissance créatrice de la négativité. == Ce que Nietzsche affirme et ce qu'on lui prête == Nietzsche affirme : que le jugement négatif des philosophes sur la vie est un symptôme de déclin vital, non une vérité objective ; que Socrate souffrait d'une anarchie des instincts qu'il a maîtrisée en faisant de la raison un tyran ; que l'équation « raison = vertu = bonheur » rompt avec les instincts de l'ancien hellénisme ; que la dialectique est l'arme des faibles, une forme de ressentiment ; que la philosophie depuis Socrate est « pathologiquement conditionnée ». On lui prête à tort un rejet total de la raison : il ne condamne pas la raison comme telle, mais son érection en tyran contre les instincts, revendiquant pour lui-même une « clarté de dialecticien »<ref>''Ecce Homo'', « Pourquoi je suis si sage », § 1 ; KSA 6, {{p.|265}}.</ref>. On lui prête à tort un éloge inconditionnel des instincts : l'idéal est leur coordination hiérarchique, non leur anarchie, laquelle est précisément le symptôme de la décadence. On lui prête à tort une condamnation morale de Socrate : sa critique se veut « physiologique », non un blâme. On lui prête enfin à tort l'identification de Socrate à un criminel : la question « Socrate était-il un criminel typique ? » est une provocation reposant sur une inférence invalide, et Nietzsche réserve par ailleurs au criminel une réelle sympathie, le tenant pour « le type de l'homme fort placé dans des conditions défavorables »<ref>''Crépuscule des idoles'', « Flâneries d'un inactuel », § 45 ; KSA 6, {{p.|146}}.</ref>. Or tel n'est précisément pas le Socrate qu'il décrit. == Synthèse == Le chapitre développe, en douze sections rigoureusement composées, une thèse à plusieurs niveaux. Au plan physiologique, Socrate est un décadent dont les instincts sont désagrégés. Au plan historique, l'Athènes du Ve siècle traverse une crise dont Socrate généralise la solution personnelle. Au plan philosophique, l'équation « raison = vertu = bonheur » ouvre, selon Nietzsche, une longue tradition tendant à subordonner la vie à la raison et à la morale. Au plan stratégique, s'attaquer à l'idole Socrate permet de viser l'ensemble de la tradition rationaliste et moraliste, et de préparer ''L'Antéchrist''. La structure suit un crescendo : ouverture sur les dernières paroles de Socrate (§ 1), portrait physiologique et anthropologique (§ 3-4), analyse de la dialectique comme arme des faibles (§ 5-8), diagnostic de la raison-tyran (§ 9-11), puis reprise variée de l'ouverture (§ 12). L'ambivalence persiste néanmoins : Socrate est aussi reconnu clairvoyant (§ 9), et sa mort volontaire revêt une forme de sagesse (§ 12). Nietzsche semble reconnaître en lui un adversaire à sa mesure, voire un prédécesseur dans la tâche de médecin de la culture, ce qui fragilise l'apparente univocité de la condamnation. == Notes et références == {{Références|colonnes=2}} == Sources anciennes == Platon, ''Apologie'', ''Criton'', ''Phédon'', ''Banquet'', ''Ménon'' ; Xénophon, ''Mémorables'', ''Banquet'' ; Aristophane, ''Les Nuées'' ; Cicéron, ''Tusculanes'' IV, 80 (anecdote de Zopyre). == Liens externes == * Le chapitre en traduction française : [[s:Le Crépuscule des Idoles/Le Problème de Socrate|« Le Problème de Socrate »]], trad. Henri Albert, Mercure de France, 1908, sur Wikisource. 1ytdpvwlj2nc0x342ztd0qlvkj73g84 Fonctionnement d'un ordinateur/Les circuits incrémenteurs/décrémenteurs 0 83953 768727 768656 2026-06-26T15:17:44Z Mewtow 31375 /* Le demi-additionneur */ 768727 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} ===Le demi-additionneur basé sur une modification de la retenue=== Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il peu être intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. Une source d'économie est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 4usvj4ppm9rsdc5q27hlsv41hjti913 768728 768727 2026-06-26T15:18:02Z Mewtow 31375 /* Le demi-additionneur basé sur une modification de la retenue */ 768728 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'économie est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 9ictmudrgzl6b8361rcb16l2p30rnh0 768729 768728 2026-06-26T15:18:24Z Mewtow 31375 /* Le demi-additionneur basé sur une modification de la retenue */ 768729 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 6dpo0f5k7zlpvpw6gntuuc9wasuk0qc 768731 768729 2026-06-26T15:31:22Z Mewtow 31375 /* Le demi-additionneur basé sur une modification de la retenue */ 768731 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 1je7qu6xg3oq4aw4mwgy8id9oxh4dcr 768732 768731 2026-06-26T15:31:32Z Mewtow 31375 /* Le demi-additionneur basé sur une modification de la retenue */ 768732 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 66p9hvykvlgpur00zwck1503h8s6dqz 768736 768732 2026-06-27T00:24:57Z Mewtow 31375 /* Les incrémenteurs à anticipation de retenue */ 768736 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. ==Les décrémenteurs== Les circuits décrémenteurs font l'inverse d'un incrémenteur : au lieu d'ajouter 1 à un opérande, ils lui soustraient 1. La différence n'est pas énorme, ce qui fait que les circuits incrémenteurs et décrémenteurs se ressemblent beaucoup. Là où les incrémenteurs sont fabriqués à partir de demi-additionneurs, les décrémenteurs sont bâtis avec des demi-soustracteurs. Un demi-soustracteur soustrait deux bits. Pour comprendre comment soustraire deux bits, traitons les quatres cas possibles un par un. Premièrement, soustraire zéro à un bit ne changera rien : * 0 - 0 = 0 ; * 1 - 0 = 1. Si on soustrait 1 à un bit qui vaut 1, on obtient zéro. * 1 - 1 = 0. Maintenant, que se passe-t-il si on soustrait 1 à 0 ? Voici le résultat : * 0 - 1 = 1 et une retenue. La retenue est propagée sur la colonne suivante, où elle est soustraite. Pour la décrémentation, les choses sont assez simples. La décrémentation effectue le calcul suivant : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> - 0 0 0 0 0 0 0 1 La seule colonne qui peut générer une retenue à soustraire est celle tout à droite, celle où on soustrait 1. Les autres colonnes ne font que soustraire un bit de l'opérande à la retenue provenant de la colonne précédente. Celle-ci peut valoir 1 ou 0, tout dépend de ce qui s'est passé sur la colonne précédente. Le '''demi-soustracteur''' prend un bit en opérande, et lui soustrait un second bit. Il implémente la tablie de soustraction abordée plus haut, à savoir : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Si on construit la table de vérité, et qu'on construit le circuit associé, on tombe sur ce circuit. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 060uepcuvon8nk80rrhgxkyhckksb66 768738 768736 2026-06-27T00:32:46Z Mewtow 31375 /* Les décrémenteurs */ 768738 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. ==Les décrémenteurs== Les circuits décrémenteurs font l'inverse d'un incrémenteur : au lieu d'ajouter 1 à un opérande, ils lui soustraient 1. La différence n'est pas énorme, ce qui fait que les circuits incrémenteurs et décrémenteurs se ressemblent beaucoup. Là où les incrémenteurs sont fabriqués à partir de demi-additionneurs, les décrémenteurs sont bâtis avec des demi-soustracteurs. La soustraction se fait en binaire comme en décimal. On soustrait deux chiffres, puis on doit propager une éventuelle retenue sur la colonne suivante. La retenue apparait quand le chiffre soustrait est plus grand que l'autre chiffre. Elle est propagée sur la colonne suivante, où elle doit être soustraite du résultat. Pour le dire autrement, après avoir soustrait un chiffre, on doit de plus soustraire la retenue de la colonne précédente. La décrémentation effectue le calcul suivant : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> - 0 0 0 0 0 0 0 1 La colonne la plus à droite soustrait un 1. Par contre, les colonnes suivantes soustraient un zéro. Soustraire un zéro ne change rien. Mais il ne faut pas oublier de soustraire une éventuellement retenue, propagée depuis la colonne précédente. En clair, un décrémenteur peut se construire si on sait soustraire deux bits. On soustrait un 1 sur la colonne la plus à droite, on soustrait une retenue sur les autres colonnes. Et pour soustraire deux bits, il faut utiliser un demi-soustracteur. ===Le demi-soustracteur=== Un '''demi-soustracteur''' soustrait deux bits. Pour comprendre comment soustraire deux bits, traitons les quatre cas possibles un par un. Premièrement, soustraire zéro à un bit ne changera rien : * 0 - 0 = 0 ; * 1 - 0 = 1. Si on soustrait 1 à un bit qui vaut 1, on obtient zéro. * 1 - 1 = 0. Maintenant, que se passe-t-il si on soustrait 1 à 0 ? Voici le résultat : * 0 - 1 = 1 et une retenue propagée sur la colonne suivante, où elle est soustraite. La table de soustraction est donc al suivante : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Si on construit la table de vérité, et qu'on construit le circuit associé, on tombe sur ce circuit. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> cxhlcbxa9zgnzeeedsuqic7bzkzso2y 768739 768738 2026-06-27T00:33:06Z Mewtow 31375 /* Le demi-soustracteur */ 768739 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. ==Les décrémenteurs== Les circuits décrémenteurs font l'inverse d'un incrémenteur : au lieu d'ajouter 1 à un opérande, ils lui soustraient 1. La différence n'est pas énorme, ce qui fait que les circuits incrémenteurs et décrémenteurs se ressemblent beaucoup. Là où les incrémenteurs sont fabriqués à partir de demi-additionneurs, les décrémenteurs sont bâtis avec des demi-soustracteurs. La soustraction se fait en binaire comme en décimal. On soustrait deux chiffres, puis on doit propager une éventuelle retenue sur la colonne suivante. La retenue apparait quand le chiffre soustrait est plus grand que l'autre chiffre. Elle est propagée sur la colonne suivante, où elle doit être soustraite du résultat. Pour le dire autrement, après avoir soustrait un chiffre, on doit de plus soustraire la retenue de la colonne précédente. La décrémentation effectue le calcul suivant : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> - 0 0 0 0 0 0 0 1 La colonne la plus à droite soustrait un 1. Par contre, les colonnes suivantes soustraient un zéro. Soustraire un zéro ne change rien. Mais il ne faut pas oublier de soustraire une éventuellement retenue, propagée depuis la colonne précédente. En clair, un décrémenteur peut se construire si on sait soustraire deux bits. On soustrait un 1 sur la colonne la plus à droite, on soustrait une retenue sur les autres colonnes. Et pour soustraire deux bits, il faut utiliser un demi-soustracteur. ===Le demi-soustracteur=== Un '''demi-soustracteur''' soustrait deux bits. Pour comprendre comment soustraire deux bits, traitons les quatre cas possibles un par un. Premièrement, soustraire zéro à un bit ne changera rien : * 0 - 0 = 0 ; * 1 - 0 = 1. Si on soustrait 1 à un bit qui vaut 1, on obtient zéro. * 1 - 1 = 0. Maintenant, que se passe-t-il si on soustrait 1 à 0 ? Voici le résultat : * 0 - 1 = 1 et une retenue propagée sur la colonne suivante, où elle est soustraite. La table de soustraction est donc al suivante : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Si on construit la table de vérité, et qu'on construit le circuit associé, on tombe sur ce circuit. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] ===La fusion entre incrémenteur et décrémenteur=== Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de créer un circuit capable de faire à la fois des additions et des soustractions. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 3z6m2isk8x54d7uj0jte4lonrrfqq07 768740 768739 2026-06-27T00:35:03Z Mewtow 31375 /* La fusion entre incrémenteur et décrémenteur */ 768740 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. ==Les décrémenteurs== Les circuits décrémenteurs font l'inverse d'un incrémenteur : au lieu d'ajouter 1 à un opérande, ils lui soustraient 1. La différence n'est pas énorme, ce qui fait que les circuits incrémenteurs et décrémenteurs se ressemblent beaucoup. Là où les incrémenteurs sont fabriqués à partir de demi-additionneurs, les décrémenteurs sont bâtis avec des demi-soustracteurs. La soustraction se fait en binaire comme en décimal. On soustrait deux chiffres, puis on doit propager une éventuelle retenue sur la colonne suivante. La retenue apparait quand le chiffre soustrait est plus grand que l'autre chiffre. Elle est propagée sur la colonne suivante, où elle doit être soustraite du résultat. Pour le dire autrement, après avoir soustrait un chiffre, on doit de plus soustraire la retenue de la colonne précédente. La décrémentation effectue le calcul suivant : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> - 0 0 0 0 0 0 0 1 La colonne la plus à droite soustrait un 1. Par contre, les colonnes suivantes soustraient un zéro. Soustraire un zéro ne change rien. Mais il ne faut pas oublier de soustraire une éventuellement retenue, propagée depuis la colonne précédente. En clair, un décrémenteur peut se construire si on sait soustraire deux bits. On soustrait un 1 sur la colonne la plus à droite, on soustrait une retenue sur les autres colonnes. Et pour soustraire deux bits, il faut utiliser un demi-soustracteur. ===Le demi-soustracteur=== Un '''demi-soustracteur''' soustrait deux bits. Pour comprendre comment soustraire deux bits, traitons les quatre cas possibles un par un. Premièrement, soustraire zéro à un bit ne changera rien : * 0 - 0 = 0 ; * 1 - 0 = 1. Si on soustrait 1 à un bit qui vaut 1, on obtient zéro. * 1 - 1 = 0. Maintenant, que se passe-t-il si on soustrait 1 à 0 ? Voici le résultat : * 0 - 1 = 1 et une retenue propagée sur la colonne suivante, où elle est soustraite. La table de soustraction est donc al suivante : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Si on construit la table de vérité, et qu'on construit le circuit associé, on tombe sur ce circuit. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] ===La fusion entre incrémenteur et décrémenteur=== Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de fusionner un demi-additionneur avec un demi-soustracteur. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. Le résultat est que l'on peut créer un circuit qui sert alternativement d'incrémenteur et de décrémenteur. Il suffit pour cela d'utiliser plusieurs circuits précédents, et de commander tous les inverseurs commandables avec le même bit d'entrée. Ce bit sélectionne l'opération demandée : incrémentation ou décrémentation. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> b58cfi1sm54ybtzyqua9xo9bzzijx8v 768743 768740 2026-06-27T00:41:22Z Mewtow 31375 /* Le demi-soustracteur */ 768743 wikitext text/x-wiki Le circuit '''incrémenteur''' incrémente un nombre entier. Plus précisément, il prend en entrée un nombre entier, et fournit en entier le nombre suivant, il lui ajoute 1. Une telle opération peut paraitre triviale et peu intéressante. Cependant, elle est très utilisée et est absolument cruciale pour créer des compteurs, des circuits capables de compter ou décompter, qui auront droit à un chapitre dédié. De plus, au-delà de leur utilisation dans les compteurs, les incrémenteurs étaient très utilisés sur les premiers processeurs 8 bits, comme le Z-80, le 6502, les premiers processeurs x86 comme le 8008, le 8086, le 8085, et bien d'autres. Il existe aussi des ''circuits décrémenteurs'', qui décrémentent un opérande, ainsi que des ''circuits incrémenteur-décrémenteur'', qui peuvent incrémenter ou décrémenter, selon comment on les configure. Je ne vais pas détailler ces circuits plus que ça, car de tels circuits sont assez rares, comparé à un circuit incrémenteur simple. ==Le demi-additionneur== Le circuit incrémenteur effectue l'opération suivante : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 Un incrémenteur basique doit donc faire une addition pour chaque colonne, et précisément une addition de deux bits. Il se trouve que la table d'addition est très simple en binaire. Jugez plutôt : * 0 + 0 = 0, retenue = 0 ; * 0 + 1 = 1, retenue = 0 ; * 1 + 0 = 1, retenue = 0 ; * 1 + 1 = 0, retenue = 1. Un circuit capable d'additionner deux bits est appelé un '''demi-additionneur'''. Il dispose d'une sortie S pour la somme, et C pour la retenue (''carry'' an anglais). ===Le demi-additionneur classique=== Un demi-additionneur est très simple à construire avec les techniques vues dans les premiers chapitres. Voici sa table de vérité : {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- ||0||0|| ||0||0 |- ||0||1|| ||0||1 |- ||1||0|| ||0||1 |- ||1||1|| ||1||0 |} On voit immédiatement que la colonne des retenues donne une porte ET, alors que celle du bit de somme est calculé par un XOR. {| class="flexible" |[[File:1-bit half-adder.svg|class=transparent|centre|Demi-addtionneur.]] |[[File:Half-adder.svg|centre|class=transparent|Circuit d'un demi-addtionneur.]] |} Il existe beaucoup d'autres implémentations alternatives, qui utilisent moins de portes logiques, calculent la retenue plus rapidement, consomment moins d'énergie, et autres. Et il est intéressant d'étudier quelques alternatives, surtout qu'elles serviront plus bas, quand on étudiera le circuit incrémenteur du 8085. ===Le demi-additionneur basé sur une modification de la retenue=== Une source d'amélioration est liée à la porte XOR. En pratique, une porte XOR est composée en combinant plusieurs portes logiques ET/OU/NOR/NAND ensemble. Et il se trouve qu'il y a des redondances entre celles-ci et les portes utilisées pour calculer la retenue. Par exemple, rappelons qu'une porte XOR peut être construite avec une porte ET et deux portes NOR, comme illustré ci-dessous. Et il se trouve que la porte ET interne calcule la retenue sortante. En supprimant cette redondance, on économise quelques portes logiques. De plus, on se retrouve avec un demi-additionneur qui calcule le bit de somme à partir de la retenue sortante. [[File:Demi-additionneur avec redondances éliminées.png|centre|vignette|upright=2|Demi-additionneur avec redondances éliminées]] Le circuit précédent a une interprétation logique. Si vous regardez la table de vérité, vous remarquerez que la somme de deux bits est égale à l'inverse de la retenue sortante, sauf dans le cas où les deux bits additionnés valent zéro. Et le circuit précédent est basé là-dessus. {|class="wikitable" |- ! Retenue entrante !! Opérande 1 !! !! Retenue sortante !! Bit de somme |- class="f_vert" ||0||0|| ||0||0 |- class="f_rouge" ||0||1|| ||0||1 |- class="f_rouge" ||1||0|| ||0||1 |- class="f_rouge" ||1||1|| ||1||0 |} L'idée est de calculer l'inverse du bit de somme, avant de l'inverser avec une porte NON. L'inverse du bit de somme vaut 1, soit quand la retenue est à 1, soit quand les deux bits additionnés sont à 0. La porte ET calcule la retenue sortante, la première porte NOR détecte sur les deux bits d'entrée valent zéro. Une porte OU combine les deux résultat pour obtenir l'inverse du bit d'entrée, puis une porte NOn inverse le tout pour obtenir le bit de somme adéquat. Les deux portes sont fusionnées : c'est la seconde porte NOR. [[File:Full adder HA + MUX.png|centre|vignette|upright=2.5|Demi-additionneur basé sur une inversion de la retenue sortante.]] ===Les implémentations optimisées=== Une implémentation alternative, qui n'utilise que des portes NOR, est la suivante : [[File:Demi-additionneur fait avec des portes NOR et NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NOR et NAND.]] Une implémentation alternative utilise des portes NAND. Pour rappel, il est possible de créer une porte XOR avec 4 portes NAND. La première d'entre elle fait un NAND entre les deux bits d'entrée, ce qui fait qu'elle calcule l'inverse de la retenue sortante. Le tout est illustré ci-dessous. En théorie, on devrait utiliser une porte NON pour récupérer la retenue correcte. Mais nous verrons plus bas que ce n'est pas une obligation. Nous verrons plus bas un exemple où c'est l'inverse de la retenue qui est utilisée dans les calculs, pour rendre les calculs plus rapides. [[File:Demi-additionneur fait avec des portes NAND.png|centre|vignette|upright=2|Demi-additionneur fait avec des portes NAND]] ==L'incrémenteur à propagation de retenue== Maintenant que l'on sait comment additionner deux bits, reprenons l'opération d'incrémentation : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> + 0 0 0 0 0 0 0 1 ------------------------------ Sur la colonne la plus à droite, il doit ajouter un au bit de poids faible. Pour les colonnes suivantes, il faut additionner le bit de l'opérande avec la retenue de la colonne précédente. En clair, on n'additionne que deux bits à chaque colonne : un 1 sur celle tout à droite, la retenue de la colonne précédente pour les autres. Et cela nous donne une idée de comment faire pour créer le circuit incrémenteur. Il suffit d'utiliser un demi-additionneur par colonne, et de les enchainer les uns à la suite des autres. Chaque demi-additionneur additionne le bit de l'opérande avec la retenue fournie par le demi-additionneur précédent. Le seul qui fait exception est celui pour la colonne de poids faible. Pour celui-là, il doit ajouter 1 au bit de poids faible. Le résultat est appelé un '''incrémenteur à propagation de retenue'''. Il est constitué de demi-additionneurs enchaînés les uns à la suite des autres, du bit de poids faible vers le bit de poids fort. [[File:Circuit incrémenteur.png|centre|vignette|upright=3|Circuit incrémenteur.]] Maintenant, regardons le demi-additionneur le plus à droite, celui pour le bit de poids faible. Son entrée de retenue entrante est mise à 1 pour faire l'incrémentation. Quelques incrémenteurs permettent de configurer cette entrée de retenue à 0 ou à 1, ce qui effectue : soit une opération identité (l'opérande est recopié sur la sortie), soit une incrémentation. Un tel circuit est nommé un '''incrémenteur commandable'''. Nous aurons à utiliser une fois ou deux de tels incrémenteurs commandables dans la suite du cours. L'incrémenteur à propagation de retenue est le plus simple et le plus économe en portes logiques. Mais de tels incrémenteurs sont rarement utilisés. À la place, on leur préfère des incrémenteurs plus rapides, mais qui utilisent plus de portes logiques. De tels incrémenteurs accélèrent le calcul des retenues. En effet, la rapidité d'une incrémentation est limitée par la propagation de la retenue : les retenues commencent à être calculées au bit de poids fort et on doit les calculer une par une, jusqu’à atteindre le bit de poids fort. Et cette "propagation des retenues" prend du temps, d'autant plus de temps que l'opérande est longue. Il y a deux optimisations principales, appelées le ''carry skip'' et l'anticipation de retenue, que nous allons décrire ci-dessous. ==Les incrémenteurs ''carry skip''== L'optimisation '''''carry skip''''' effectue l'incrémentation, non pas bit par bit, mais par paquets de deux bits. Le résultat est que l'incrémentation est deux fois plus rapide, ou presque. Le circuit incrémenteur est donc composé en enchainant non pas des demi-additionneurs, mais des '''incrémenteurs 2 bits''' qui incrémentent un opérande de deux bits. [[File:Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits.png|centre|vignette|upright=2.5|Circuit incrémenteur optimisé, faisant l'incrémentation par paquet de deux bits]] Reste à concevoir l'incrémenteur 2 bits. ===Les optimisations au niveau des transistors et l'exemple de l'incrémenteur du 8085 d'Intel=== Une première solution part de deux demi-additionneurs et effectue quelques simplifications au niveau des transistors et des portes logiques. Par exemple, l'Intel 8085 a utilisé un circuit optimisé, fabriqué avec des portes NAND et NOR. La raison est qu'avec les technologies de transistors CMOS actuelles, les portes NAND et NOR utilisent moins de transistors que les portes ET et OU. Et cette possibilité a été utilisée pour effectuer des simplifications assez mineures, mais toujours bonnes à prendre. Mais nous ne pouvons pas en parler en détail ici, car nous n'avons pas encore parlé en détail des transistors. Cependant, un exemple bien précis nous est accesible : celui de l’incrémenteur du processeur 8085 d'Intel. Le processeur 8085 d'Intel est un processeur 8 bits très ancien. Il contenait un incrémenteur 16 bits, qui était utilisé pour calculer des adresses mémoire. Et cet incrémenteur était un incrémenteur à propagation de retenue optimisé. Il utilisait lui aussi des incrémenteurs 2 bits un peu modifiés. L'idée était que les retenues sortant des colonnes paires étaient inversées, les colonnes impaires faisaient les calculs à partir de cette retenue inversée. Les demi-additionneurs des colonnes impaires n'étaient donc pas les mêmes que ceux des colonnes paires. Leurs tables de vérité sont différentes, leurs circuits aussi, et aucun des deux ne ressemble à un demi-additionneur normal. En réalité, ils sont fabriqués à partir des implémentations vues plus haut, qui utilisent uniquement des portes NAND ou uniquement des portes NOR. Pour comprendre l'intérêt de faire ainsi, nous devons préciser une chose importante : avec les technologies CMOS utilisées pour les processeurs depuis les années 70, les portes logiques les plus simples sont les portes NON, NOR et NAND. Les portes ET/OU sont fabriquées en combinant des portes NOR/NAND avec une porte NON, ce qui prend plus de transistors. Un demi-additionneur est donc fabriqué comme illustré ci-dessous, en logique CMOS. Seules les portes pour le calcul de la retenue sont indiquées, la porte XOR pour le bit de somme est fabriquée à partir de plusieurs portes logiques. [[File:Demi-additionneur en CMOS.png|centre|vignette|upright=2|Demi-additionneur en CMOS]] Si on enchaine deux demi-additionneurs, cela donne ceci : [[File:Brique de base de l'incrémenteur du 8085.png|centre|vignette|upright=2|Brique de base de l'incrémenteur du 8085]] La retenue doit donc traverser quatre portes logiques, dont deux portes NON. En inversant la retenue, les portes en jaune dans le schéma précédent se simplifient. Il suffit d'utiliser la loi de de Morgan pour trouver un circuit équivalent aux portes jaunes, qui n'est autre qu'une porte NOR couplée à une porte NON. Un autre moyen d'obtenir le même résultat est de prendre un demi-additionneur fabriqué avec uniquement des portes NOR, et de retirer la porte NON adéquate. Il faut ensuite corriger l'entrée de retenue de la porte XOR, pour qu'elle fasse l'addition avec la retenue correctement. Le résultat est illustré ci-dessous. [[File:Incrémenteur 2 bits de l'incrémenteur du 8085.png|centre|vignette|upright=2|Incrémenteur 2 bits de l'incrémenteur du 8085]] Le circuit utilise le même nombre de portes logiques, il n'économise pas de transistors. Par contre, la retenue n'a plus qu'à traverser deux portes logiques, au lieu de quatre. La propagation de la retenue est donc plus rapide, l'incrémentation est donc plus rapide. ===Les incrémenteurs 2 bits ''carry skip''=== Une solution alternative fabrique des incrémenteurs 2 bits qui calculent séparément les deux bits du résultat et la retenue sortante. La retenue sortante est calculée à partir des bits de l’opérande, sans propager des retenues. Ainsi, la retenue sortante est connue en avance, sans passer par deux demi-additionneurs. Pour créer un tel incrémenteur, le mieux est de partir de sa table de vérité. {|class="wikitable" |- ! Opérande !! Retenue entrante !! !! Retenue sortante !! Résultat |- | 00 || 0 || || 0 || 00 |- | 01 || 0 || || 0 || 01 |- | 10 || 0 || || 0 || 10 |- | 11 || 0 || || 0 || 11 |- | colspan="5" | |- | 00 || 1 || || 0 || 01 |- | 01 || 1 || || 0 || 10 |- | 10 || 1 || || 0 || 11 |- | 11 || 1 || || 1 || 00 |} Elle nous dit que la retenue sortante ne vaut 1 que dans un seul cas : les deux bits d'opérande valent 1, la retenue entrante vaut 1. Elle se calcule alors avec une porte ET à trois entrées. Pour les deux bits du résultat, les équations logiques ne donnent pas un résultat satisfaisant. La solution la plus simple est d'utiliser deux demi-additionneurs et de retirer les portes logiques superflues. Le résultat est alors un '''incrémenteur 2 bits ''carry skip''''', où la retenue sortante est calculée séparément du reste. [[File:Incrémenteur carry skip 2 bits.png|centre|vignette|upright=2.5|Incrémenteur ''carry skip'' 2 bits]] ==Les incrémenteurs à anticipation de retenue== L''''anticipation de retenue''' calcule la retenue d'une colonne sans attendre les retenues des colonnes précédentes. Dans le cas idéal, toutes les retenues sont calculées en parallèle, en même temps, et sont ensuite envoyées aux demi-additionneurs. Il s'agit d'une optimisation qui est utilisée pour l'incrémentation, l'addition et d'autres opérations similaires. Pour l'incrémentation, déterminer la retenue ne demande pas de calculs complexes, contrairement à l'addition. [[File:Incrémenteur à anticipation de retenues, 8 bits.png|centre|vignette|upright=2.5|Incrémenteur à anticipation de retenues, 8 bits.]] Pour le comprendre, on peut regarder comment la retenue sortant d'un demi-additionneur est formée. Elle est calculée en faisant un ET logique entre la retenue entrante et le bit d'opérande. Une retenue est donc un ET logique entre toutes les retenues précédentes. Un incrémenteur à anticipation de retenue utilise donc une porte ET à plusieurs entrées pour calculer une retenue. [[File:Anticipation de retenue pour un bit du résultat, incrémenteur.png|centre|vignette|upright=2.5|Anticipation de retenue pour un bit du résultat, incrémenteur]] En théorie, on peut utiliser une porte ET à plusieurs entrées pour chaque bit de l'opérande. Cependant, cela entrainera un cout en transistors très important. Pour éviter de gaspiller trop de portes logiques, une solution est de mélanger anticipation de retenues et propagation de retenue. Par exemple, pour un incrémenteur 32 bits, on peut découper l'opérande en 4 octets : on anticipe les retenues pour chaque octet, mais l'incrémentation de chaque octet se fait avec propagation de retenue et/ou ''carry skip''. [[File:Incrémenteur à anticipation de retenues.png|centre|vignette|upright=3|Incrémenteur hybride utilisant partiellement l'anticipation de retenues.]] Quelques processeurs utilisaient l'anticipation de retenues. Par exemple, le processeur Z-80 de Zilog utilisait un incrémenteur pour des nombres de 16 bits, ce qui demandait des performances assez élevées. Et cet incrémenteur utilisait à la fois anticipation de retenues et ''carry skip''. Il était découpé en quatre blocs avant anticipation de retenues entre eux : un bloc regroupant les 7 bits de poids faible, suivi par un bloc de 5 bits, lui-même suivi par un bloc de 3 bits, terminé par un dernier bit isolé. A l'intérieur de ces blocs, les bits sont regroupés en paires utilisant le ''carry skip''. Pour ceux qui veulent en savoir plus sur cet incrémenteur, voici un lien sur le sujet : * [https://www.righto.com/2013/11/the-z-80s-16-bit-incrementdecrement.html The Z-80's 16-bit increment/decrement circuit reverse engineered]. ==Les décrémenteurs== Les circuits décrémenteurs font l'inverse d'un incrémenteur : au lieu d'ajouter 1 à un opérande, ils lui soustraient 1. La différence n'est pas énorme, ce qui fait que les circuits incrémenteurs et décrémenteurs se ressemblent beaucoup. Là où les incrémenteurs sont fabriqués à partir de demi-additionneurs, les décrémenteurs sont bâtis avec des demi-soustracteurs. La soustraction se fait en binaire comme en décimal. On soustrait deux chiffres, puis on doit propager une éventuelle retenue sur la colonne suivante. La retenue apparait quand le chiffre soustrait est plus grand que l'autre chiffre. Elle est propagée sur la colonne suivante, où elle doit être soustraite du résultat. Pour le dire autrement, après avoir soustrait un chiffre, on doit de plus soustraire la retenue de la colonne précédente. La décrémentation effectue le calcul suivant : <math>a_7</math> <math>a_6</math> <math>a_5</math> <math>a_4</math> <math>a_3</math> <math>a_2</math> <math>a_1</math> <math>a_0</math> - 0 0 0 0 0 0 0 1 La colonne la plus à droite soustrait un 1. Par contre, les colonnes suivantes soustraient un zéro. Soustraire un zéro ne change rien. Mais il ne faut pas oublier de soustraire une éventuellement retenue, propagée depuis la colonne précédente. En clair, un décrémenteur peut se construire si on sait soustraire deux bits. On soustrait un 1 sur la colonne la plus à droite, on soustrait une retenue sur les autres colonnes. Et pour soustraire deux bits, il faut utiliser un demi-soustracteur. ===Le demi-soustracteur=== Un '''demi-soustracteur''' soustrait deux bits. Pour comprendre comment soustraire deux bits, traitons les quatre cas possibles un par un. Premièrement, soustraire zéro à un bit ne changera rien : * 0 - 0 = 0 ; * 1 - 0 = 1. Si on soustrait 1 à un bit qui vaut 1, on obtient zéro. * 1 - 1 = 0. Maintenant, que se passe-t-il si on soustrait 1 à 0 ? Voici le résultat : * 0 - 1 = 1 et une retenue propagée sur la colonne suivante, où elle est soustraite. La table de soustraction est donc al suivante : * 0 - 0 = 0 ; * 0 - 1 = 1 et une retenue ; * 1 - 0 = 1 ; * 1 - 1 = 0. Si on construit la table de vérité, et qu'on construit le circuit associé, on tombe sur ce circuit. [[File:Half Subtractor Vektor.svg|centre|vignette|Demi-soustracteur.]] un décrémenteur à propagation de retenue se construit comme un incrémenteur, sauf qu'on remplace les demi-additionneurs par des demi-soustracteurs. Il est possible d'utiliser l'anticipation de retenue, mais les circuits sont cependant différents. IOdem avec le ''carry skip'', et toute autre optimisation possible. ===La fusion entre incrémenteur et décrémenteur=== Vous l'aurez sans doute remarqué, mais le demi-soustracteur ressemble beaucoup au demi-additionneur. La seule différence est une porte NON ajoutée au bon endroit dans le demi-soustracteur. {| |[[File:Half-adder.svg|vignette|Demi-additionneur]] |[[File:Half Subtractor Vektor.svg|vignette|upright=1.3|Demi-soustracteur]] |} La conséquence est qu'il est possible de fusionner un demi-additionneur avec un demi-soustracteur. L'idée est de remplacer la porte NON du demi-soustracteur par un inverseur commandable. Si on envoie un zéro sur l'entrée de commande, l'inverseur commandable se comportera comme une porte OUI. Le circuit sera alors identique à un demi-additionneur. Si on envoie un 1 sur l'entrée de commande, l'inverseur commandable se comportera comme une porte NON. le circuit sera alors un demi-soustracteur. Le résultat est que l'on peut créer un circuit qui sert alternativement d'incrémenteur et de décrémenteur. Il suffit pour cela d'utiliser plusieurs circuits précédents, et de commander tous les inverseurs commandables avec le même bit d'entrée. Ce bit sélectionne l'opération demandée : incrémentation ou décrémentation. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les circuits de sélection | prevText=Les circuits de sélection | next=Les bascules : des mémoires de 1 bit | nextText=Les bascules : des mémoires de 1 bit }} </noinclude> 8iygonl0bgsdp5etlps7gvskalhusfj Mathc matrices/09i 0 83971 768759 2026-06-27T09:45:08Z Xhungab 23827 news 768759 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc matrices (livre)]] [[Mathc_matrices/Sommaire| Sommaire]] {{Partie{{{type|}}}| '''Matrices de Markov'''}} a1 b1 c1 Soit : a2 b2 c2 Alors 0 < x* <= 1 et x1 + x2 + x3 = 1 a3 b3 c3 a) Une des valeurs propres est égale à 1 les autres sont inférieures à 1 a1 b1 c1 b) Si : A = a2 b2 c2 à partir d'une certaine valeur de n, A^n ne va plus se modifier. a3 b3 c3 * a) '''Nous allons calculer les valeurs propres'''. * b) '''Nous allons vérifier la propriété de A^n quand n tend vers l'infinie'''. '''Exemple 1 :''' * [[Mathc matrices/09c| c00a.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09d| c00b.c ]] : Calculons A^P Nous pourrons observer qu'a partir de '''P = 13''', la valeur de '''A^P n'évolue plus'''. '''Exemple 2 : ''' * [[Mathc matrices/09e| c00c.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09f| c00d.c ]] : Calculons A^n Nous pourrons observer qu'a partir de '''P = 23''', la valeur de '''A^P n'évolue plus'''. '''Exemple 3 :''' * [[Mathc matrices/09g| c00e.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09h| c00f.c ]] : Calculons A^n Nous pourrons observer qu'a partir de '''P = 14''', la valeur de '''A^P n'évolue plus'''. {{AutoCat}} d1ysrme5vo9shvbgkpkrne5ehzc6w5c 768766 768759 2026-06-27T09:58:43Z Xhungab 23827 768766 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc matrices (livre)]] [[Mathc_matrices/Sommaire| Sommaire]] {{Partie{{{type|}}}| '''Matrices de Markov'''}} a1 b1 c1 Soit : a2 b2 c2 Alors 0 < x* <= 1 et x1 + x2 + x3 = 1 a3 b3 c3 a) Une des valeurs propres est égale à 1 les autres sont inférieures à 1 a1 b1 c1 b) Si : A = a2 b2 c2 à partir d'une certaine valeur de P, A^P ne va plus se modifier. a3 b3 c3 * a) '''Nous allons calculer les valeurs propres'''. * b) '''Nous allons vérifier la propriété de A^n quand n tend vers l'infinie'''. '''Exemple 1 :''' * [[Mathc matrices/09c| c00a.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09d| c00b.c ]] : Calculons A^P Nous pourrons observer qu'a partir de '''P = 13''', la valeur de '''A^P n'évolue plus'''. '''Exemple 2 : ''' * [[Mathc matrices/09e| c00c.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09f| c00d.c ]] : Calculons A^n Nous pourrons observer qu'a partir de '''P = 23''', la valeur de '''A^P n'évolue plus'''. '''Exemple 3 :''' * [[Mathc matrices/09g| c00e.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09h| c00f.c ]] : Calculons A^n Nous pourrons observer qu'a partir de '''P = 14''', la valeur de '''A^P n'évolue plus'''. {{AutoCat}} n22utx4d1d3sk0kakevz9t1kp7vnazx 768767 768766 2026-06-27T09:59:16Z Xhungab 23827 768767 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc matrices (livre)]] [[Mathc_matrices/Sommaire| Sommaire]] {{Partie{{{type|}}}| '''Matrices de Markov'''}} a1 b1 c1 Soit : a2 b2 c2 Alors 0 < x* <= 1 et x1 + x2 + x3 = 1 a3 b3 c3 a) Une des valeurs propres est égale à 1 les autres sont inférieures à 1 a1 b1 c1 b) Si : A = a2 b2 c2 à partir d'une certaine valeur de P, A^P ne va plus se modifier. a3 b3 c3 * a) '''Nous allons calculer les valeurs propres'''. * b) '''Nous allons vérifier la propriété de A^n quand n tend vers l'infinie'''. '''Exemple 1 :''' * [[Mathc matrices/09c| c00a.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09d| c00b.c ]] : Calculons A^P Nous pourrons observer qu'a partir de '''P = 13''', la valeur de '''A^P n'évolue plus'''. '''Exemple 2 : ''' * [[Mathc matrices/09e| c00c.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09f| c00d.c ]] : Calculons A^P Nous pourrons observer qu'a partir de '''P = 23''', la valeur de '''A^P n'évolue plus'''. '''Exemple 3 :''' * [[Mathc matrices/09g| c00e.c ]] : Calculons les vecteurs propres et les valeurs propres. * [[Mathc matrices/09h| c00f.c ]] : Calculons A^P Nous pourrons observer qu'a partir de '''P = 14''', la valeur de '''A^P n'évolue plus'''. {{AutoCat}} l9qp8tzkshgeo861xk56kdtmhicqjvz Mathc matrices/09c 0 83972 768760 2026-06-27T09:48:36Z Xhungab 23827 news 768760 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i|Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00a.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00a.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C2 /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.2,+.6, +.8,+.4 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T1 = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T1, Ev, i_mR(RCA,RCA)); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"a",P9); printf(" [V, E] = eigs (a,%d) \n\n",RCA); printf(" Ev:"); p_mR(Ev,S10,P4,C6); printf(" Eval = InvEv A Ev"); p_mR(Eval,S10,P4,C6); stop(); f_mR(A); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(T1); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows a=[ +0.200000000,+0.600000000; +0.800000000,+0.400000000] [V, E] = eigs (a,2) Ev: +0.6000 -0.7071 +0.8000 +0.7071 Eval = InvEv A Ev +1.0000 +0.0000 -0.0000 -0.4000 Press return to continue. </syntaxhighlight> {{AutoCat}} p1ujlx8r06msqk17lh8tvxqlzoi2qqs Mathc matrices/09d 0 83973 768761 2026-06-27T09:50:38Z Xhungab 23827 news 768761 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i| Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00b.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00b.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C2 #define P 13/* Try : 10, 15, 20, 25 */ /* ------------------------------------ */ /* ------------------------------------ */ double f( double x) { return(pow(x,P)); } char feq[] = "x**P"; /* ------------------------------------ */ /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.2,+.6, +.8,+.4 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **A_P = pow_mR(P, A, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T, Ev, i_mR(RCA,RCA)); double **f_Eval = i_mR(RCA,RCA); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"A",P9); printf(" A^%d\n\n",P); printf(" A^%d:",P); pE_mR(A_P,S10,P4,C6); printf(" A^%d: Ev Eval**%d InvEv",P,P); f_eigs_mR(f,Eval,f_Eval); mul_mR(Ev,f_Eval,T); mul_mR(T,InvEv,A_P); pE_mR(A_P,S10,P4,C6); stop(); f_mR(A); f_mR(A_P); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(f_Eval); f_mR(T); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows A=[ +0.200000000,+0.600000000; +0.800000000,+0.400000000] A^13 A^13: +4.2857e-01 +4.2857e-01 +5.7143e-01 +5.7143e-01 A^13: Ev Eval**13 InvEv +4.2857e-01 +4.2857e-01 +5.7143e-01 +5.7143e-01 Press return to continue. </syntaxhighlight> {{AutoCat}} 4gfvar8f87fx08o6gf9xs8idkfo4hy5 Mathc matrices/09e 0 83974 768762 2026-06-27T09:52:12Z Xhungab 23827 news 768762 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i| Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00c.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00c.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C3 /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.7,+.2,+.1, +.2,+.2,+.6, +.1,+.6,+.3 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T1 = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T1, Ev, i_mR(RCA,RCA)); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"a",P9); printf(" [V, E] = eigs (a,%d) \n\n",RCA); printf(" Ev:"); p_mR(Ev,S10,P4,C6); printf(" Eval = InvEv A Ev"); p_mR(Eval,S10,P4,C6); stop(); f_mR(A); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(T1); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows a=[ +0.700000000,+0.200000000,+0.100000000; +0.200000000,+0.200000000,+0.600000000; +0.100000000,+0.600000000,+0.300000000] [V, E] = eigs (a,3) Ev: +0.5774 +0.8128 -0.0775 +0.5774 -0.3393 +0.7427 +0.5774 -0.4735 -0.6652 Eval = InvEv A Ev +1.0000 +0.0000 +0.0000 -0.0000 +0.5583 +0.0000 +0.0000 -0.0000 -0.3583 Press return to continue. </syntaxhighlight> {{AutoCat}} dq4vf7r8znabh49wnqc0eqvs5crpw6m Mathc matrices/09f 0 83975 768763 2026-06-27T09:53:33Z Xhungab 23827 news 768763 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i| Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00d.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00d.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C3 #define P 23/* Try : 10, 15, 20, 25 */ /* ------------------------------------ */ /* ------------------------------------ */ double f( double x) { return(pow(x,P)); } char feq[] = "x**P"; /* ------------------------------------ */ /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.7,+.2,+.1, +.2,+.2,+.6, +.1,+.6,+.3 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **A_P = pow_mR(P, A, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T, Ev, i_mR(RCA,RCA)); double **f_Eval = i_mR(RCA,RCA); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"A",P9); printf(" A^%d\n\n",P); printf(" A^%d:",P); pE_mR(A_P,S10,P4,C6); printf(" A^%d: Ev Eval**%d InvEv",P,P); f_eigs_mR(f,Eval,f_Eval); mul_mR(Ev,f_Eval,T); mul_mR(T,InvEv,A_P); pE_mR(A_P,S10,P4,C6); stop(); f_mR(A); f_mR(A_P); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(f_Eval); f_mR(T); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows A=[ +0.700000000,+0.200000000,+0.100000000; +0.200000000,+0.200000000,+0.600000000; +0.100000000,+0.600000000,+0.300000000] A^23 A^23: +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 A^23: Ev Eval**23 InvEv +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 +3.3333e-01 Press return to continue. </syntaxhighlight> {{AutoCat}} 1nm4jnluaiz1lulxedsq4m1gnw7gun9 Mathc matrices/09g 0 83976 768764 2026-06-27T09:56:03Z Xhungab 23827 news 768764 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i| Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00e.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00e.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C4 /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.3,+.2,+.1,+.4, +.2,+.1,+.3,+.4, +.1,+.3,+.4,+.2, +.4,+.4,+.2,+.0 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T1 = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T1, Ev, i_mR(RCA,RCA)); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"a",P9); printf(" [V, E] = eigs (a,%d) \n\n",RCA); printf(" Ev:"); p_mR(Ev,S10,P4,C6); printf(" Eval = InvEv A Ev"); p_mR(Eval,S10,P4,C6); stop(); f_mR(A); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(T1); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows a=[ +0.300000000,+0.200000000,+0.100000000,+0.400000000; +0.200000000,+0.100000000,+0.300000000,+0.400000000; +0.100000000,+0.300000000,+0.400000000,+0.200000000; +0.400000000,+0.400000000,+0.200000000,+0.000000000] [V, E] = eigs (a,4) Ev: +0.5000 -0.3047 -0.6163 -0.5267 +0.5000 -0.5252 +0.0810 +0.6838 +0.5000 +0.0362 +0.7526 -0.4269 +0.5000 +0.7937 -0.2173 +0.2698 Eval = InvEv A Ev +1.0000 +0.0000 -0.0000 +0.0000 -0.0000 -0.4091 -0.0000 +0.0000 -0.0000 -0.0000 +0.2926 -0.0000 +0.0000 +0.0000 +0.0000 -0.0835 Press return to continue. </syntaxhighlight> {{AutoCat}} sa6a0ef07ve4b0z9s2c63xzc4je04r1 Mathc matrices/09h 0 83977 768765 2026-06-27T09:57:32Z Xhungab 23827 news 768765 wikitext text/x-wiki [[Catégorie:Mathc matrices (livre)]] [[Mathc matrices/09i| Matrices de Markov]] Installer et compiler ces fichiers dans votre répertoire de travail. {{Fichier|c00f.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as: c00f.c */ /* ------------------------------------ */ #include "v_a.h" /* ------------------------------------ */ #define RCA C4 #define P 14/* Try : 10, 15, 20, 25 */ /* ------------------------------------ */ /* ------------------------------------ */ double f( double x) { return(pow(x,P)); } char feq[] = "x**P"; /* ------------------------------------ */ /* ------------------------------------ */ int main(void) { double a[RCA*RCA]={ +.3,+.2,+.1,+.4, +.2,+.1,+.3,+.4, +.1,+.3,+.4,+.2, +.4,+.4,+.2,+.0 }; double **A = ca_A_mR(a, i_mR(RCA,RCA)); double **A_P = pow_mR(P, A, i_mR(RCA,RCA)); double **Ev = eigs_V_mR(A, i_mR(RCA,RCA)); double **InvEv = invgj_mR(Ev, i_mR(RCA,RCA)); /* Eval = InvEv A Ev */ double **T = mul_mR(InvEv, A, i_mR(RCA,RCA)); double **Eval = mul_mR(T, Ev, i_mR(RCA,RCA)); double **f_Eval = i_mR(RCA,RCA); clrscrn(); printf(" Copy/Paste into the octave windows \n"); p_Octave_mR(A,"A",P9); printf(" A^%d\n\n",P); printf(" A^%d:",P); pE_mR(A_P,S10,P4,C6); printf(" A^%d: Ev Eval**%d InvEv",P,P); f_eigs_mR(f,Eval,f_Eval); mul_mR(Ev,f_Eval,T); mul_mR(T,InvEv,A_P); pE_mR(A_P,S10,P4,C6); stop(); f_mR(A); f_mR(A_P); f_mR(Ev); f_mR(InvEv); f_mR(Eval); f_mR(f_Eval); f_mR(T); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="c"> Copy/Paste into the octave windows A=[ +0.300000000,+0.200000000,+0.100000000,+0.400000000; +0.200000000,+0.100000000,+0.300000000,+0.400000000; +0.100000000,+0.300000000,+0.400000000,+0.200000000; +0.400000000,+0.400000000,+0.200000000,+0.000000000] A^14 A^14: +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 A^14: Ev Eval**14 InvEv +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 +2.5000e-01 Press return to continue. </syntaxhighlight> {{AutoCat}} ntnefjwyn63oapfwo5gqtjgtxplwk5f