Wikilivres frwikibooks https://fr.wikibooks.org/wiki/Accueil MediaWiki 1.47.0-wmf.19 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 Discussion utilisateur:Mewtow 3 55231 772106 771983 2026-09-13T08:11:36Z Xhungab 23827 /* Demandes de prises de décision */ Réponse 772106 wikitext text/x-wiki {| width="100%" align="center" style="display:block; float:center; background:#FFF; text-size:100%; margin:.5 .5 .5 .5em; padding:2px; border:1px solid #aaa; background-color:transparent;" |---- | colspan="2" align="center" width="95%" style="height:9px; margin:.2em; padding:5px; border:1px solid #aaa; background-color:#bfbfff; font-size:130%; text-align:center; float:center" | '''Bienvenue sur Wikilivres, {{BASEPAGENAME}}&nbsp;!''' |---- | colspan="2" align="center" width="85%" style="font-size:110%" | <br/>Wikilivres est un projet francophone de rédactions de manuels pédagogiques libres. |---- | valign="middle" align="center" | [[Image:Crystal Clear app Login Manager.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Si vous désirez vous investir dans ce projet passionnant, vous êtes le bienvenu. Tous les contributeurs de Wikilivres vous invitent à corriger et développer les livres existants et à créer le votre !<br /> Prenez avant toute chose connaissance des '''[[Wikilivres:Présentation|principes fondateurs de Wikilivres]]''' à la base du projet. N'ayez aucune crainte d'abîmer la bibliothèque : toutes les modifications sont suivies par des contributeurs plus expérimentés qui pourront corriger vos éventuelles erreurs. Ne vous offensez pas de ces interventions ni des messages destinés à vous aider à comprendre le projet et ses règles. Suivez leurs conseils et n'hésitez pas à demander simplement plus d'explications ! |---- | valign="middle" align="center" | [[Image:ACE.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Lorsque vous contribuez, '''gardez à l'esprit que Wikilivres est une ''bibliothèque universelle''''', il faut donc veiller à '''respecter un point de vue vérifiable'''. De plus, le contenu doit rester conforme à notre licence d'utilisation libre (GFDL).<br> Les utilisateurs travaillent en harmonie et privilégient la discussion aussi courtoise que possible pour régler les oppositions, aussi, prenez le temps de vous y habituer. Pensez à vous présenter également sur votre [[Utilisateur:{{PAGENAME}}|page d'utilisateur]], ce qui permettra à chacun de connaître vos centres d'intérêt et de mieux vous guider vers les divers projets thématiques. Pour cela, vous pouvez employer les [[Wikilivres:Boîtes utilisateur|boîtes utilisateur]].<br /> Bien qu'il s'agisse d'un travail de rédaction complexe résultant de l'action de milliers de contributeurs francophones du monde entier, sa philosophie peut être résumée en quelques mots : '''« N'hésitez pas à l'améliorer ! »''' |---- | valign="middle" align="center" | [[Image:Plume pen w.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Au cours d'une discussion, n'oubliez pas de signer vos messages, à l'aide de quatre tildes (<nowiki>~~~~</nowiki>) ou du bouton [[Image:Bouton Signature.png|25px|lien=]] présent en haut de la fenêtre de modification. En revanche ne signez pas les livres lorsque vous en créez ou que vous les modifiez car l'historique permet de retrouver toutes vos contributions.<br> |---- | valign="middle" align="center" | [[Image:Wikibooks logo.svg|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Vous pouvez trouver des explications détaillées à partir des pages : * '''''[[Aide:Accueil|Tout l'indispensable]]''''', à lire absolument, * '''[[Aide:Syntaxe|Syntaxe]]''', les conventions d'écriture à connaître. * '''[[Aide:Poser une question|Poser une question]]''', si vous vous sentez perdu. * '''[[Aide:Comment modifier une page|Comment modifier une page]]''' Vous pourrez ajouter par la suite d'autres pages d'aide ou les informations dont vous pensez avoir besoin dans votre [[Utilisateur:{{PAGENAME}}|espace utilisateur]]. Si vous souhaitez contribuer mais que vous n'avez pas d'idées, allez faire un tour sur [[Wikilivres:Demande de livre|les demandes de livres et de traductions !]]. Bonne contribution, et n'hésitez pas à me contacter si besoin !<br> <small>PS: If you arn't French, you can consult the [[Wikilivres:Ambassade|embassy]] for help.</small> |} --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 mars 2013 à 20:42 (CET) == Page et sous-pages == Bonjour, Remarque concernant l'organisation d'un livre : il faut que les chapitres ait un titre de la forme <code>titre du livre/titre du chapitre</code> (avec un slash / servant de séparateur). Par exemple la page <code>Motivation</code> ne veut rien dire hors de son contexte : un autre livre peut également avoir un chapitre nommé '''Motivation'''. Il vaut mieux la nommer <code>Pédagogie : psychologie cognitive appliquée à l'enseignement/motivation</code>. [[Wikilivres:Conventions sur les titres]] --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 novembre 2013 à 15:13 (CET) == Share your experience and feedback as a Wikimedian in this global survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir.<ref group=survey>Le principal objectif de l’enquête est d’obtenir des retours sur le travail actuel de la Fondation Wikimédia, sans stratégie à long terme.</ref> Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Afin de vous remercier pour le temps accordé, nous livrons 20 t-shirts Wikimédia à des personnes choisies au hasard parmi celles ayant répondu à l’enquête.<ref group=survey>Questions légales : pas d’achat nécessaire. Vous devez avoir l’âge de la majorité pour participer. Soutenu par la Fondation Wikimédia (Wikimedia Foundation) située au 149 New Montgomery, San Francisco, CA, USA, 94105. Se termine le 31 janvier 2017. Le don est annulé en cas d’infraction. [[m:Community Engagement Insights/2016 contest rules|Cliquez ici pour lire les règles du concours]].</ref> Le questionnaire est disponible dans différents langages et requiert entre 20 et 40 minutes pour être complété. <strong>'''[https://wikimedia.qualtrics.com/SE/?SID=SV_6mTVlPf6O06r3mt&Aud=VAE&Src=57VAEOP Répondez-y maintenant !]'''</strong> Vous pouvez lire davantage d’informations sur [[m:Community_Engagement_Insights/About_CE_Insights|ce projet]]. Cette enquête est hébergée par un service tiers et régie par sa [[:foundation:Community_Engagement_Insights_2016_Survey_Privacy_Statement|déclaration de confidentialité]]. Visitez notre [[m:Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique à surveys@wikimedia.org. Merci ! --[[:m:User:EGalvez (WMF)|EGalvez (WMF)]] ([[:m:User talk:EGalvez (WMF)|talk]]) 13 janvier 2017 à 23:25 (CET) </div> <!-- Message envoyé par User:EGalvez (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2016/57-VAEOP&oldid=16205400 --> <references group=survey /> == Mewtow, vous aussi venez discuter de l'avenir du mouvement == Bonjour, Je viens vous inviter à rejoindre les discussions en cours sur le futur du mouvement Wikimédia. Depuis quelques jours déjà, des contributeurs, à travers divers projets et langues sur wikis, discutent de nos priorités, en tant que mouvement, pour les 15 années à venir : Quelle est la chose la plus importante à faire ? Comment maintenir ou accélérer notre progrès? Qu'est-ce qui pourrait consolider notre unité en tant que mouvement? Voici autant de questions auxquelles tous essaient d’apporter des réponses. Vous aussi, votre point de vue compte énormement. On prend l'avis de tout le monde y compris les correcteurs d'orthographe {{sourire}}. N’hésitez surtout pas à consulter la page des discussions sur [[Wikilivres:Mouvement Wikimedia/Stratégie 2017]] pour y laisser vos propositions ou pour débattre des propositions des autres. Voici quelques liens utiles sur le contexte et le processus de cette consultation : * [[M:Strategy/Wikimedia movement/2017/Process/Briefing/fr|Contexte général]], pour comprendre les objectifs et jeter un coup d'oeil aux études et statistiques connexes * [[M:Strategy/Wikimedia movement/2017/Process/fr|Calendrier et processus]], pour plus de détails sur les dates et consulter le graphique illustrant toutes les étapes * [[M:Strategy/Wikimedia_movement/2017/Frequently_asked_questions/fr|Foire Aux Questions (FAQ)]], pour les questions qui reviennent fréquemment N'hésitez pas à me contacter au besoin. Amicalement, [[Utilisateur:Samuel (WMF)|Samuel (WMF)]] ([[Discussion utilisateur:Samuel (WMF)|discussion]]) 29 mars 2017 à 17:32 (CEST) == Discussion des principes de Fonctionnement de Wikibooks == Bonjour, j'ai modifié des pages d'aide : [[Wikilivres/Introduction]], [[Wikilivres/Démarrer un wikilivre]] et créé [[Wikilivres/Pourquoi écrire sur Wikibooks ?]]. Mes modifications concernent les principes de fonctionnement de Wikibooks, sur le travail coopératif, le respect des auteurs et le droit de signer ses livres. Tous les contributeurs sont concernés. Une discussion est initiée sur [[Discussion:Wikilivres/Démarrer un wikilivre]]. J'aimerais bien avoir votre avis. [[Utilisateur:Thierry Dugnolle|Thierry Dugnolle]] ([[Discussion utilisateur:Thierry Dugnolle|discussion]]) 27 avril 2017 à 16:43 (CEST) == Notes == == Relecture == Bonjour, Afin d'éviter toute « collision » lors d'éditions simultanées, ce serait bien que tu m'indiques directement que tel ou tel chapitre est en état d'être relu ! Amitiés, [[Utilisateur:Jean-Jacques MILAN|Jean-Jacques MILAN]] ([[Discussion utilisateur:Jean-Jacques MILAN|discussion]]) 26 juin 2017 à 10:09 (CEST). :Bonjour, :Pour le moment, à l'exception des trois chapitres sur les satellites et les corps transneptuniens, tous les chapitres sont terminés et en état d'être relus/corrigés. :Cordialement. == [[Architecture des ordinateurs]] == Bonjour Mewtow, Un utilisateur [[Discussion:Architecture des ordinateurs#Fusion|suggère de fusionner]] l'ébauche de livre [[Architecture des ordinateurs]] dans [[Fonctionnement d'un ordinateur]]. Si des éléments te semblent viables, n'hésite pas à t'en servir. Sinon, je déplacerai [[Architecture des ordinateurs]] vers des brouillons afin de ne pas encombrer la wikilibrairie. Bienvenue sur Wikibooks, puisque nous ne sommes pas croisés. Bonne continuation ! Bien cordialement, 10 juillet 2017 à 16:03 (CEST) :Bonjour Savant-fou. :Après lecture du cours en question, je ne pense pas que je pourrais réutiliser quoique ce soit du cours "Architecture des ordinateurs" (que je connaissais depuis longtemps, mais n'avais pas souhaité modifier). La quasi-totalité de ce qui est présent dans ce cours l'est aussi dans le mien, avec cependant quelques exemples ou exercices en plus que je ne penses pas pertinent d'insérer dans mon ouvrage. Je ne m'opposerais pas du tout à ce que vous le déplaciez vers des brouillons, comme vous l'avez mentionné. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 10 juillet 2017 à 19:09 (CEST) ::Merci pour ta réponse. J'ai déplacé Architecture des ordinateurs vers [[Utilisateur:Merrheim/Architecture_des_ordinateurs]]. La page [[Architecture des ordinateurs]] redirige maintenant vers [[Fonctionnement d'un ordinateur]]. Bonne journée ! [[Fichier:P_physics.svg|25px|link=User:Savant-fou]]&nbsp;[[Utilisateur:Savant-fou|Savant-fou]] <small><sup>[[Discussion Utilisateur:Savant-fou|parler]]</sup></small> 11 juillet 2017 à 09:54 (CEST) == Share your experience and feedback as a Wikimedian in this global survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir. Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi·e au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Le questionnaire est disponible dans différentes langues et requiert entre 20 et 40 minutes pour être complété. <big>'''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant !]'''</big> Vous pouvez trouver davantage d’informations concernant cette enquête [[m:Special:MyLanguage/Community_Engagement_Insights/About_CE_Insights|sur la page du projet]] et voir comment vos retours aident la Fondation Wikimédia à prendre en charge des contributeurs comme vous. Cette enquête est hébergée par un service tiers et régie par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] (en anglais). Visitez notre [[m:Special:MyLanguage/Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]] pour être supprimé·e de la liste. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 29 mars 2018 à 20:36 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Reminder: Share your feedback in this Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Chaque réponse à cette enquête peut aider la Fondation Wikimédia à améliorer votre expérience sur les projets Wikimédia. Jusqu’à présent, nous n’avons entendu que 29% des contributeurs Wikimédia. Le sondage est disponible dans plusieurs langues et prend entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' Si vous avez déjà répondu à ce sondage, nous sommes désolé que que vous receviez ce rappel. Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. <span class="mw-translate-fuzzy">Si vous souhaitez ne pas recevoir le prochain rappel ou un autre sondage, envpyez un courriel en utilisant la fonction d'envoi à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]</span>. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 13 avril 2018 à 03:35 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Your feedback matters: Final reminder to take the global Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! Voici un dernier message pour vous rappeler que le questionnaire de l’enquête de la Fondation Wikimédia se fermera le '''23 avril 2018 à 07 h (UTC)'''. Le questionnaire est disponible dans différentes langues et demande entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' '''Si vous avez déjà participé à ce sondage, merci ! Nous ne vous dérangerons plus.''' Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. Pour vous désabonner des sondages futurs, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 20 avril 2018 à 02:44 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17952438 --> == Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, La Wikimedia Foundation sollicite votre point de vue dans une enquête sur votre expérience avec {{SITENAME}} et Wikimedia. L’objectif de cette enquête est de savoir à quel niveau la ''Foundation'' soutient correctement (ou non) votre travail sur le wiki, et de quelle manière nous pouvons changer ou améliorer les choses à l’avenir. Les avis que vous émettrez impacteront directement le travail actuel et futur de la Wikimedia Foundation. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 9 septembre 2019 à 16:34 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19352874 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il y a quelques semaines, nous vous avons invité à participer à l’enquête sur les Perspectives de la communauté. Il s’agit de l’enquête annuelle de la Wikimedia Foundation auprès de nos communautés internationales. Nous voulons savoir à quel niveau nous soutenons correctement (ou non) votre travail sur le wiki. Nous avons atteint 10% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! '''Votre voix compte à nos yeux'''. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 20 septembre 2019 à 21:14 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19395141 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il reste quelques semaines seulement pour participer à l’enquête sur les Perspectives de la communauté ! Nous avons atteint 30% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! Avec ce sondage, la Wikimedia Foundation recueille un retour sur le niveau de qualité de notre soutien de votre travail sur le wiki. Seules 15–25 minutes sont nécessaires pour achever de répondre à l’enquête, et cela a un impact direct sur le soutien que nous apportons. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 4 octobre 2019 à 19:04 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19435548 --> == huit gluons au lieu de neuf == Bonjour Mewtow, merci pour votre wikilivre sur le noyau atomique, que je commence juste à lire. Concernant les gluons, compte tenu de leurs attributs : 1 - une couleur parmi trois, 2 - une anti couleur parmi trois, ça devrait faire 3x3 '''neuf''' gluons. Il n'y en a bien que huit mais uniquement pour une raison théorique difficile à piger pour moi, cf [[w:Gluon#Pourquoi huit gluons au lieu de neuf ?]] Çà me semble important de le souligner dans le wikilivre, car le premier pignouf (comme moi) qui fera le calcul trouvera ... 9 et pensera que l'auteur du wikilivre s'est trompé. cordialement --[[Utilisateur:JihemD|JihemD]] ([[Discussion utilisateur:JihemD|discussion]]) 13 août 2020 à 17:20 (CEST) : Effectivement, il y a bien une erreur. Je corrige de suite. Merci d'avoir fait la remarque.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 21:48 (CEST) : Et j'en ai profité pour donner l'explication du pourquoi huit gluons et non neuf. A voir si l'explication que je donnes est facile à comprendre ou pas. A mon avis, la superposition des gluons devrait être difficile à comprendre, mais le reste de l'explication devrait passer.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 22:32 (CEST) == Appel à relecture et création d'hyperliens == Bonjour Mewtow. Je découvre avec plaisir le projet Wikilivres en décidant de publier les trois premiers chapitres de ma thèse de doctorat sous forme de livre. En parcourant le contenu, je suis tombé sur les nombreux ouvrage que tu as déjà produit ici. De là m'est venu une idée. Plutôt que de mettre dans mon texte des wikiliens pointant vers Wikipédia pour aider les lecteurs à trouver un complément d'information, pourquoi pas les rediriger vers des travaux déjà existants sur Wikilivres. Le problème, c'est que je n'ai pas vraiment le temps de parcourir tout ceux-ci. C'est donc la raison pour laquelle je viens poster ce message pour voir si tu ne pourrais pas m'aider dans cette tâche. Toi qui connais bien le contenu de tes livres, tu pourrais effectivement créer toi-même dans livre que je suis en train de terminer les hyperliens qui pourraient pointer vers tes travaux. L'idéal serait même de remplacer tous ceux qui pointent vers Wikipédia pour éviter que le lecteur ne doive surfer sur deux sites différents lors d'une consultation hors ligne notamment. Tu me diras ce que tu en penses. Voici déjà le titre de mon ouvrage : [[Le mouvement Wikimédia]]. N'hésite pas non plus à faire des remarques sur sa page de discussion si jamais lors d'une éventuelle lecture, tu trouverais des informations fausses. Dès que j'en aurai le temps, je passerai aussi du temps sur tes ouvrages qui ont l'air intéressants. Bien à toi, [[User:Lionel Scheepmans|Lionel Scheepmans]] <sup><big>✉</big> [[User talk:Lionel Scheepmans|Contact]]</sup> <sub>Désolé pour ma [[w:dysorthographie|dysorthographie]], [[w:dyslexie|dyslexie]] et [[wikt:distraction|"dys"traction]].</sub> 29 novembre 2021 à 14:48 (CET) == Prise de décision - fin dimanche 2 juin == Bonsoir Mewtow, Tout d'abord un grand merci pour ta contribution très active à Wikilivres. Je t'informe qu'une "prise de décision" (débat) est en cours concernant le retrait automatique des liens rouges lorsqu'une image est supprimée sur Commons. Lien : [[Wikilivres:Prise de décision/Laisser les liens rouges des images]]. '''La phase de discussion se termine le dimanche 2 juin à 23 h 59.''' D'avance, merci pour ta participation ! Cdlt, [[Utilisateur:Fourmidable|Fourmidable]] ([[Discussion utilisateur:Fourmidable|discussion]]) 25 mai 2024 à 23:56 (CEST) == Ouvrages sources des wikibooks sur l'Electricité et l'Electronique == Bonjour Mewtow, Je suis en train de lire les wikibooks sur l'Electricité et l'Electronique dont tu es l'auteur, et je te remercie beaucoup pour l'excellent travail que tu as fait!! :) Quelles sont les ouvrages sources dont tu t'es servi pour les écrire ? En te remerciant par avance. Cdlt, [[Utilisateur:Alex Mtlr|Alex Mtlr]] ([[Discussion utilisateur:Alex Mtlr|discussion]]) 16 juillet 2025 à 13:57 (CEST) :Bonjour Alex. :Pour être franc, les sources principales sont les cours que j'ai eu pendant ma scolarité, lors de mon Bac STI option génie électronique, et mon BTS systèmes électroniques. Pour ce qui est du cours d'électronique, notamment tout ce qui a trait aux transistors, je me souviens avoir utilisé un bouquin nommé "Circuits microélectroniques", par Adel Sedra et Kenneth C. Smith, que j'ai revendu il y a de cela quelques années. J'ai aussi ai lu pas mal de fichiers .pdf disponibles sur le net, accessibles via quelques recherches Google, mais ca fait un moment que j'ai rédigé ces cours et j'ai un peu oublié lesquels. :C'est tout ce dont je me souviens pour le moment. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 16 juillet 2025 à 16:24 (CEST) == Pages orphelines == Bonjour, Il semble que certaines de vos pages se sont perdues dans les pages orphelines. Pourriez-vous les garder ici dans votre page de discussion pour qu'elles ne soient plus orphelines. Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 25 février 2026 à 14:07 (CET) :Pas de problème pour les garder sur ma page de discussion. Par contre, certaines des pages en question sont à supprimer, car leur contenu a été déplacé dans des chapitres existants. Faudra que je regarde cela cette semaine et que je me renseigne sur la procédure pour les faire supprimer. :Dans la liste précédente, les deux chapitres suivants sont dans ce cas : :* [[Les opérations bit à bit/Calculs flottants]] :* [[Les suites et séries/Les suites arithmético-géométriques]] :Il y a aussi ceux identifiés dans "Fontionnement d'un ordinateur", qui ont été identifiés ailleurs. Je n'ai aucun chapitre brouillon pour ce cours. [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 25 février 2026 à 20:04 (CET) ::Bonjour, ::* Voir le Bistro, il semble que cela soit difficile de supprimer une page ::* Il y a une vingtaine de livres dans ta situation. Je les ai regroupés dans ce livre. Voir les derniers chapitres, la présentation des premiers chapitres laisse à désirer ::*. ::* [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] ::*. ::Par exemple pour ton cas : ::*. ::*. ::La page orpheline : ::* [[Les opérations bit à bit/Calculs flottants|Les opérations bit à bit/Calculs flottants]] ::a été copiée ici: ::* [[Les opérations bit à bit/Les opérations arithmétiques sur des flottants|Les opérations bit à bit/Les opérations arithmétiques sur des flottants]] ::*. ::La page orpheline : ::* [[Les suites et séries/Les suites arithmético-géométriques|Les suites et séries/Les suites arithmético-géométriques]] ::a été copiée ici: ::* [[Les suites et séries/Les suites numériques|Les suites et séries/Les suites numériques]] ::*. ::Tu peux naturellement simplement laisser tes pages sur ta page en attendant qu'elles puissent être supprimées ::Où je peux les introduire pour toi dans le livre [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] en attendant qu'une bonne âme se sacrifie pour supprimer les doublons. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 00:02 (CET) :::Pas de problèmes de mon côté pour que tu ajoutes ces pages dans le livre ' feuilles dupliquées orphelines" à ma place, merci beaucoup. Je crois que ce serait la meilleure solution, vu que les chapitres dupliqués orphelins de "Fonctionnement d'un ordinateur" sont déjà dessus [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 26 février 2026 à 01:34 (CET) ::::Merci pour ton aide. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 11:15 (CET) * [[Le noyau atomique/Les diffusions nucléaires]] * [[Électricité/L'étude des signaux quelconques]] * [[Le noyau atomique/Les diffusions nucléaires]] * [[Les opérations bit à bit/Calculs flottants]] * [[Les suites et séries/Les suites arithmético-géométriques]] * [[Mémoire/Habiletés]] * [[Mémoire/Mémoire perceptive]] * [[Mémoire/Mémoire à court terme]] * [[Mémoire/Mémoires sensorielles]] * [[Mémoire/Oubli]] == Demandes de prises de décision == Bonjour, Pour info. J'ai posé deux demandes de prises de décisions concernant le sujet suivant. * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Cr%C3%A9er_un_espace_lecteurs_et_un_espace_auteurs_sur_la_page_d%27accueil Créer un espace lecteurs et un espace Les coulisses de Wikibook]''' * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Modifier_le_contenue_de_l%27espace_Nouveaut%C3%A9s Wikilivres:Prise de décision/Modifier le contenue de l'espace Nouveautés]''' Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 16:53 (CEST) :Bonjour, étant donné que ton livre n'est pas dans la liste des livres terminés même s'il est terminé, je l'ai mis dans la liste des nouveaux livres pour rendre cette liste plus intéressante, je pense que ton livre apparaîtra dans la liste de la vitrine dans quelques jours automatiquement. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 13 septembre 2026 à 10:11 (CEST) gw4yrhnhw0rpku6m5ez9d2f2b4q868q 772107 772106 2026-09-13T08:18:29Z Xhungab 23827 /* Demandes de prises de décision */ Réponse 772107 wikitext text/x-wiki {| width="100%" align="center" style="display:block; float:center; background:#FFF; text-size:100%; margin:.5 .5 .5 .5em; padding:2px; border:1px solid #aaa; background-color:transparent;" |---- | colspan="2" align="center" width="95%" style="height:9px; margin:.2em; padding:5px; border:1px solid #aaa; background-color:#bfbfff; font-size:130%; text-align:center; float:center" | '''Bienvenue sur Wikilivres, {{BASEPAGENAME}}&nbsp;!''' |---- | colspan="2" align="center" width="85%" style="font-size:110%" | <br/>Wikilivres est un projet francophone de rédactions de manuels pédagogiques libres. |---- | valign="middle" align="center" | [[Image:Crystal Clear app Login Manager.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Si vous désirez vous investir dans ce projet passionnant, vous êtes le bienvenu. Tous les contributeurs de Wikilivres vous invitent à corriger et développer les livres existants et à créer le votre !<br /> Prenez avant toute chose connaissance des '''[[Wikilivres:Présentation|principes fondateurs de Wikilivres]]''' à la base du projet. N'ayez aucune crainte d'abîmer la bibliothèque : toutes les modifications sont suivies par des contributeurs plus expérimentés qui pourront corriger vos éventuelles erreurs. Ne vous offensez pas de ces interventions ni des messages destinés à vous aider à comprendre le projet et ses règles. Suivez leurs conseils et n'hésitez pas à demander simplement plus d'explications ! |---- | valign="middle" align="center" | [[Image:ACE.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Lorsque vous contribuez, '''gardez à l'esprit que Wikilivres est une ''bibliothèque universelle''''', il faut donc veiller à '''respecter un point de vue vérifiable'''. De plus, le contenu doit rester conforme à notre licence d'utilisation libre (GFDL).<br> Les utilisateurs travaillent en harmonie et privilégient la discussion aussi courtoise que possible pour régler les oppositions, aussi, prenez le temps de vous y habituer. Pensez à vous présenter également sur votre [[Utilisateur:{{PAGENAME}}|page d'utilisateur]], ce qui permettra à chacun de connaître vos centres d'intérêt et de mieux vous guider vers les divers projets thématiques. Pour cela, vous pouvez employer les [[Wikilivres:Boîtes utilisateur|boîtes utilisateur]].<br /> Bien qu'il s'agisse d'un travail de rédaction complexe résultant de l'action de milliers de contributeurs francophones du monde entier, sa philosophie peut être résumée en quelques mots : '''« N'hésitez pas à l'améliorer ! »''' |---- | valign="middle" align="center" | [[Image:Plume pen w.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Au cours d'une discussion, n'oubliez pas de signer vos messages, à l'aide de quatre tildes (<nowiki>~~~~</nowiki>) ou du bouton [[Image:Bouton Signature.png|25px|lien=]] présent en haut de la fenêtre de modification. En revanche ne signez pas les livres lorsque vous en créez ou que vous les modifiez car l'historique permet de retrouver toutes vos contributions.<br> |---- | valign="middle" align="center" | [[Image:Wikibooks logo.svg|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Vous pouvez trouver des explications détaillées à partir des pages : * '''''[[Aide:Accueil|Tout l'indispensable]]''''', à lire absolument, * '''[[Aide:Syntaxe|Syntaxe]]''', les conventions d'écriture à connaître. * '''[[Aide:Poser une question|Poser une question]]''', si vous vous sentez perdu. * '''[[Aide:Comment modifier une page|Comment modifier une page]]''' Vous pourrez ajouter par la suite d'autres pages d'aide ou les informations dont vous pensez avoir besoin dans votre [[Utilisateur:{{PAGENAME}}|espace utilisateur]]. Si vous souhaitez contribuer mais que vous n'avez pas d'idées, allez faire un tour sur [[Wikilivres:Demande de livre|les demandes de livres et de traductions !]]. Bonne contribution, et n'hésitez pas à me contacter si besoin !<br> <small>PS: If you arn't French, you can consult the [[Wikilivres:Ambassade|embassy]] for help.</small> |} --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 mars 2013 à 20:42 (CET) == Page et sous-pages == Bonjour, Remarque concernant l'organisation d'un livre : il faut que les chapitres ait un titre de la forme <code>titre du livre/titre du chapitre</code> (avec un slash / servant de séparateur). Par exemple la page <code>Motivation</code> ne veut rien dire hors de son contexte : un autre livre peut également avoir un chapitre nommé '''Motivation'''. Il vaut mieux la nommer <code>Pédagogie : psychologie cognitive appliquée à l'enseignement/motivation</code>. [[Wikilivres:Conventions sur les titres]] --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 novembre 2013 à 15:13 (CET) == Share your experience and feedback as a Wikimedian in this global survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir.<ref group=survey>Le principal objectif de l’enquête est d’obtenir des retours sur le travail actuel de la Fondation Wikimédia, sans stratégie à long terme.</ref> Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Afin de vous remercier pour le temps accordé, nous livrons 20 t-shirts Wikimédia à des personnes choisies au hasard parmi celles ayant répondu à l’enquête.<ref group=survey>Questions légales : pas d’achat nécessaire. Vous devez avoir l’âge de la majorité pour participer. Soutenu par la Fondation Wikimédia (Wikimedia Foundation) située au 149 New Montgomery, San Francisco, CA, USA, 94105. Se termine le 31 janvier 2017. Le don est annulé en cas d’infraction. [[m:Community Engagement Insights/2016 contest rules|Cliquez ici pour lire les règles du concours]].</ref> Le questionnaire est disponible dans différents langages et requiert entre 20 et 40 minutes pour être complété. <strong>'''[https://wikimedia.qualtrics.com/SE/?SID=SV_6mTVlPf6O06r3mt&Aud=VAE&Src=57VAEOP Répondez-y maintenant !]'''</strong> Vous pouvez lire davantage d’informations sur [[m:Community_Engagement_Insights/About_CE_Insights|ce projet]]. Cette enquête est hébergée par un service tiers et régie par sa [[:foundation:Community_Engagement_Insights_2016_Survey_Privacy_Statement|déclaration de confidentialité]]. Visitez notre [[m:Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique à surveys@wikimedia.org. Merci ! --[[:m:User:EGalvez (WMF)|EGalvez (WMF)]] ([[:m:User talk:EGalvez (WMF)|talk]]) 13 janvier 2017 à 23:25 (CET) </div> <!-- Message envoyé par User:EGalvez (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2016/57-VAEOP&oldid=16205400 --> <references group=survey /> == Mewtow, vous aussi venez discuter de l'avenir du mouvement == Bonjour, Je viens vous inviter à rejoindre les discussions en cours sur le futur du mouvement Wikimédia. Depuis quelques jours déjà, des contributeurs, à travers divers projets et langues sur wikis, discutent de nos priorités, en tant que mouvement, pour les 15 années à venir : Quelle est la chose la plus importante à faire ? Comment maintenir ou accélérer notre progrès? Qu'est-ce qui pourrait consolider notre unité en tant que mouvement? Voici autant de questions auxquelles tous essaient d’apporter des réponses. Vous aussi, votre point de vue compte énormement. On prend l'avis de tout le monde y compris les correcteurs d'orthographe {{sourire}}. N’hésitez surtout pas à consulter la page des discussions sur [[Wikilivres:Mouvement Wikimedia/Stratégie 2017]] pour y laisser vos propositions ou pour débattre des propositions des autres. Voici quelques liens utiles sur le contexte et le processus de cette consultation : * [[M:Strategy/Wikimedia movement/2017/Process/Briefing/fr|Contexte général]], pour comprendre les objectifs et jeter un coup d'oeil aux études et statistiques connexes * [[M:Strategy/Wikimedia movement/2017/Process/fr|Calendrier et processus]], pour plus de détails sur les dates et consulter le graphique illustrant toutes les étapes * [[M:Strategy/Wikimedia_movement/2017/Frequently_asked_questions/fr|Foire Aux Questions (FAQ)]], pour les questions qui reviennent fréquemment N'hésitez pas à me contacter au besoin. Amicalement, [[Utilisateur:Samuel (WMF)|Samuel (WMF)]] ([[Discussion utilisateur:Samuel (WMF)|discussion]]) 29 mars 2017 à 17:32 (CEST) == Discussion des principes de Fonctionnement de Wikibooks == Bonjour, j'ai modifié des pages d'aide : [[Wikilivres/Introduction]], [[Wikilivres/Démarrer un wikilivre]] et créé [[Wikilivres/Pourquoi écrire sur Wikibooks ?]]. Mes modifications concernent les principes de fonctionnement de Wikibooks, sur le travail coopératif, le respect des auteurs et le droit de signer ses livres. Tous les contributeurs sont concernés. Une discussion est initiée sur [[Discussion:Wikilivres/Démarrer un wikilivre]]. J'aimerais bien avoir votre avis. [[Utilisateur:Thierry Dugnolle|Thierry Dugnolle]] ([[Discussion utilisateur:Thierry Dugnolle|discussion]]) 27 avril 2017 à 16:43 (CEST) == Notes == == Relecture == Bonjour, Afin d'éviter toute « collision » lors d'éditions simultanées, ce serait bien que tu m'indiques directement que tel ou tel chapitre est en état d'être relu ! Amitiés, [[Utilisateur:Jean-Jacques MILAN|Jean-Jacques MILAN]] ([[Discussion utilisateur:Jean-Jacques MILAN|discussion]]) 26 juin 2017 à 10:09 (CEST). :Bonjour, :Pour le moment, à l'exception des trois chapitres sur les satellites et les corps transneptuniens, tous les chapitres sont terminés et en état d'être relus/corrigés. :Cordialement. == [[Architecture des ordinateurs]] == Bonjour Mewtow, Un utilisateur [[Discussion:Architecture des ordinateurs#Fusion|suggère de fusionner]] l'ébauche de livre [[Architecture des ordinateurs]] dans [[Fonctionnement d'un ordinateur]]. Si des éléments te semblent viables, n'hésite pas à t'en servir. Sinon, je déplacerai [[Architecture des ordinateurs]] vers des brouillons afin de ne pas encombrer la wikilibrairie. Bienvenue sur Wikibooks, puisque nous ne sommes pas croisés. Bonne continuation ! Bien cordialement, 10 juillet 2017 à 16:03 (CEST) :Bonjour Savant-fou. :Après lecture du cours en question, je ne pense pas que je pourrais réutiliser quoique ce soit du cours "Architecture des ordinateurs" (que je connaissais depuis longtemps, mais n'avais pas souhaité modifier). La quasi-totalité de ce qui est présent dans ce cours l'est aussi dans le mien, avec cependant quelques exemples ou exercices en plus que je ne penses pas pertinent d'insérer dans mon ouvrage. Je ne m'opposerais pas du tout à ce que vous le déplaciez vers des brouillons, comme vous l'avez mentionné. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 10 juillet 2017 à 19:09 (CEST) ::Merci pour ta réponse. J'ai déplacé Architecture des ordinateurs vers [[Utilisateur:Merrheim/Architecture_des_ordinateurs]]. La page [[Architecture des ordinateurs]] redirige maintenant vers [[Fonctionnement d'un ordinateur]]. Bonne journée ! [[Fichier:P_physics.svg|25px|link=User:Savant-fou]]&nbsp;[[Utilisateur:Savant-fou|Savant-fou]] <small><sup>[[Discussion Utilisateur:Savant-fou|parler]]</sup></small> 11 juillet 2017 à 09:54 (CEST) == Share your experience and feedback as a Wikimedian in this global survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir. Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi·e au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Le questionnaire est disponible dans différentes langues et requiert entre 20 et 40 minutes pour être complété. <big>'''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant !]'''</big> Vous pouvez trouver davantage d’informations concernant cette enquête [[m:Special:MyLanguage/Community_Engagement_Insights/About_CE_Insights|sur la page du projet]] et voir comment vos retours aident la Fondation Wikimédia à prendre en charge des contributeurs comme vous. Cette enquête est hébergée par un service tiers et régie par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] (en anglais). Visitez notre [[m:Special:MyLanguage/Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]] pour être supprimé·e de la liste. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 29 mars 2018 à 20:36 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Reminder: Share your feedback in this Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Chaque réponse à cette enquête peut aider la Fondation Wikimédia à améliorer votre expérience sur les projets Wikimédia. Jusqu’à présent, nous n’avons entendu que 29% des contributeurs Wikimédia. Le sondage est disponible dans plusieurs langues et prend entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' Si vous avez déjà répondu à ce sondage, nous sommes désolé que que vous receviez ce rappel. Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. <span class="mw-translate-fuzzy">Si vous souhaitez ne pas recevoir le prochain rappel ou un autre sondage, envpyez un courriel en utilisant la fonction d'envoi à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]</span>. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 13 avril 2018 à 03:35 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Your feedback matters: Final reminder to take the global Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! Voici un dernier message pour vous rappeler que le questionnaire de l’enquête de la Fondation Wikimédia se fermera le '''23 avril 2018 à 07 h (UTC)'''. Le questionnaire est disponible dans différentes langues et demande entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' '''Si vous avez déjà participé à ce sondage, merci ! Nous ne vous dérangerons plus.''' Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. Pour vous désabonner des sondages futurs, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 20 avril 2018 à 02:44 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17952438 --> == Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, La Wikimedia Foundation sollicite votre point de vue dans une enquête sur votre expérience avec {{SITENAME}} et Wikimedia. L’objectif de cette enquête est de savoir à quel niveau la ''Foundation'' soutient correctement (ou non) votre travail sur le wiki, et de quelle manière nous pouvons changer ou améliorer les choses à l’avenir. Les avis que vous émettrez impacteront directement le travail actuel et futur de la Wikimedia Foundation. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 9 septembre 2019 à 16:34 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19352874 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il y a quelques semaines, nous vous avons invité à participer à l’enquête sur les Perspectives de la communauté. Il s’agit de l’enquête annuelle de la Wikimedia Foundation auprès de nos communautés internationales. Nous voulons savoir à quel niveau nous soutenons correctement (ou non) votre travail sur le wiki. Nous avons atteint 10% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! '''Votre voix compte à nos yeux'''. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 20 septembre 2019 à 21:14 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19395141 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il reste quelques semaines seulement pour participer à l’enquête sur les Perspectives de la communauté ! Nous avons atteint 30% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! Avec ce sondage, la Wikimedia Foundation recueille un retour sur le niveau de qualité de notre soutien de votre travail sur le wiki. Seules 15–25 minutes sont nécessaires pour achever de répondre à l’enquête, et cela a un impact direct sur le soutien que nous apportons. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 4 octobre 2019 à 19:04 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19435548 --> == huit gluons au lieu de neuf == Bonjour Mewtow, merci pour votre wikilivre sur le noyau atomique, que je commence juste à lire. Concernant les gluons, compte tenu de leurs attributs : 1 - une couleur parmi trois, 2 - une anti couleur parmi trois, ça devrait faire 3x3 '''neuf''' gluons. Il n'y en a bien que huit mais uniquement pour une raison théorique difficile à piger pour moi, cf [[w:Gluon#Pourquoi huit gluons au lieu de neuf ?]] Çà me semble important de le souligner dans le wikilivre, car le premier pignouf (comme moi) qui fera le calcul trouvera ... 9 et pensera que l'auteur du wikilivre s'est trompé. cordialement --[[Utilisateur:JihemD|JihemD]] ([[Discussion utilisateur:JihemD|discussion]]) 13 août 2020 à 17:20 (CEST) : Effectivement, il y a bien une erreur. Je corrige de suite. Merci d'avoir fait la remarque.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 21:48 (CEST) : Et j'en ai profité pour donner l'explication du pourquoi huit gluons et non neuf. A voir si l'explication que je donnes est facile à comprendre ou pas. A mon avis, la superposition des gluons devrait être difficile à comprendre, mais le reste de l'explication devrait passer.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 22:32 (CEST) == Appel à relecture et création d'hyperliens == Bonjour Mewtow. Je découvre avec plaisir le projet Wikilivres en décidant de publier les trois premiers chapitres de ma thèse de doctorat sous forme de livre. En parcourant le contenu, je suis tombé sur les nombreux ouvrage que tu as déjà produit ici. De là m'est venu une idée. Plutôt que de mettre dans mon texte des wikiliens pointant vers Wikipédia pour aider les lecteurs à trouver un complément d'information, pourquoi pas les rediriger vers des travaux déjà existants sur Wikilivres. Le problème, c'est que je n'ai pas vraiment le temps de parcourir tout ceux-ci. C'est donc la raison pour laquelle je viens poster ce message pour voir si tu ne pourrais pas m'aider dans cette tâche. Toi qui connais bien le contenu de tes livres, tu pourrais effectivement créer toi-même dans livre que je suis en train de terminer les hyperliens qui pourraient pointer vers tes travaux. L'idéal serait même de remplacer tous ceux qui pointent vers Wikipédia pour éviter que le lecteur ne doive surfer sur deux sites différents lors d'une consultation hors ligne notamment. Tu me diras ce que tu en penses. Voici déjà le titre de mon ouvrage : [[Le mouvement Wikimédia]]. N'hésite pas non plus à faire des remarques sur sa page de discussion si jamais lors d'une éventuelle lecture, tu trouverais des informations fausses. Dès que j'en aurai le temps, je passerai aussi du temps sur tes ouvrages qui ont l'air intéressants. Bien à toi, [[User:Lionel Scheepmans|Lionel Scheepmans]] <sup><big>✉</big> [[User talk:Lionel Scheepmans|Contact]]</sup> <sub>Désolé pour ma [[w:dysorthographie|dysorthographie]], [[w:dyslexie|dyslexie]] et [[wikt:distraction|"dys"traction]].</sub> 29 novembre 2021 à 14:48 (CET) == Prise de décision - fin dimanche 2 juin == Bonsoir Mewtow, Tout d'abord un grand merci pour ta contribution très active à Wikilivres. Je t'informe qu'une "prise de décision" (débat) est en cours concernant le retrait automatique des liens rouges lorsqu'une image est supprimée sur Commons. Lien : [[Wikilivres:Prise de décision/Laisser les liens rouges des images]]. '''La phase de discussion se termine le dimanche 2 juin à 23 h 59.''' D'avance, merci pour ta participation ! Cdlt, [[Utilisateur:Fourmidable|Fourmidable]] ([[Discussion utilisateur:Fourmidable|discussion]]) 25 mai 2024 à 23:56 (CEST) == Ouvrages sources des wikibooks sur l'Electricité et l'Electronique == Bonjour Mewtow, Je suis en train de lire les wikibooks sur l'Electricité et l'Electronique dont tu es l'auteur, et je te remercie beaucoup pour l'excellent travail que tu as fait!! :) Quelles sont les ouvrages sources dont tu t'es servi pour les écrire ? En te remerciant par avance. Cdlt, [[Utilisateur:Alex Mtlr|Alex Mtlr]] ([[Discussion utilisateur:Alex Mtlr|discussion]]) 16 juillet 2025 à 13:57 (CEST) :Bonjour Alex. :Pour être franc, les sources principales sont les cours que j'ai eu pendant ma scolarité, lors de mon Bac STI option génie électronique, et mon BTS systèmes électroniques. Pour ce qui est du cours d'électronique, notamment tout ce qui a trait aux transistors, je me souviens avoir utilisé un bouquin nommé "Circuits microélectroniques", par Adel Sedra et Kenneth C. Smith, que j'ai revendu il y a de cela quelques années. J'ai aussi ai lu pas mal de fichiers .pdf disponibles sur le net, accessibles via quelques recherches Google, mais ca fait un moment que j'ai rédigé ces cours et j'ai un peu oublié lesquels. :C'est tout ce dont je me souviens pour le moment. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 16 juillet 2025 à 16:24 (CEST) == Pages orphelines == Bonjour, Il semble que certaines de vos pages se sont perdues dans les pages orphelines. Pourriez-vous les garder ici dans votre page de discussion pour qu'elles ne soient plus orphelines. Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 25 février 2026 à 14:07 (CET) :Pas de problème pour les garder sur ma page de discussion. Par contre, certaines des pages en question sont à supprimer, car leur contenu a été déplacé dans des chapitres existants. Faudra que je regarde cela cette semaine et que je me renseigne sur la procédure pour les faire supprimer. :Dans la liste précédente, les deux chapitres suivants sont dans ce cas : :* [[Les opérations bit à bit/Calculs flottants]] :* [[Les suites et séries/Les suites arithmético-géométriques]] :Il y a aussi ceux identifiés dans "Fontionnement d'un ordinateur", qui ont été identifiés ailleurs. Je n'ai aucun chapitre brouillon pour ce cours. [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 25 février 2026 à 20:04 (CET) ::Bonjour, ::* Voir le Bistro, il semble que cela soit difficile de supprimer une page ::* Il y a une vingtaine de livres dans ta situation. Je les ai regroupés dans ce livre. Voir les derniers chapitres, la présentation des premiers chapitres laisse à désirer ::*. ::* [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] ::*. ::Par exemple pour ton cas : ::*. ::*. ::La page orpheline : ::* [[Les opérations bit à bit/Calculs flottants|Les opérations bit à bit/Calculs flottants]] ::a été copiée ici: ::* [[Les opérations bit à bit/Les opérations arithmétiques sur des flottants|Les opérations bit à bit/Les opérations arithmétiques sur des flottants]] ::*. ::La page orpheline : ::* [[Les suites et séries/Les suites arithmético-géométriques|Les suites et séries/Les suites arithmético-géométriques]] ::a été copiée ici: ::* [[Les suites et séries/Les suites numériques|Les suites et séries/Les suites numériques]] ::*. ::Tu peux naturellement simplement laisser tes pages sur ta page en attendant qu'elles puissent être supprimées ::Où je peux les introduire pour toi dans le livre [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] en attendant qu'une bonne âme se sacrifie pour supprimer les doublons. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 00:02 (CET) :::Pas de problèmes de mon côté pour que tu ajoutes ces pages dans le livre ' feuilles dupliquées orphelines" à ma place, merci beaucoup. Je crois que ce serait la meilleure solution, vu que les chapitres dupliqués orphelins de "Fonctionnement d'un ordinateur" sont déjà dessus [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 26 février 2026 à 01:34 (CET) ::::Merci pour ton aide. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 11:15 (CET) * [[Le noyau atomique/Les diffusions nucléaires]] * [[Électricité/L'étude des signaux quelconques]] * [[Le noyau atomique/Les diffusions nucléaires]] * [[Les opérations bit à bit/Calculs flottants]] * [[Les suites et séries/Les suites arithmético-géométriques]] * [[Mémoire/Habiletés]] * [[Mémoire/Mémoire perceptive]] * [[Mémoire/Mémoire à court terme]] * [[Mémoire/Mémoires sensorielles]] * [[Mémoire/Oubli]] == Demandes de prises de décision == Bonjour, Pour info. J'ai posé deux demandes de prises de décisions concernant le sujet suivant. * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Cr%C3%A9er_un_espace_lecteurs_et_un_espace_auteurs_sur_la_page_d%27accueil Créer un espace lecteurs et un espace Les coulisses de Wikibook]''' * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Modifier_le_contenue_de_l%27espace_Nouveaut%C3%A9s Wikilivres:Prise de décision/Modifier le contenue de l'espace Nouveautés]''' Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 16:53 (CEST) :Bonjour, étant donné que ton livre n'est pas dans la liste des livres terminés même s'il est terminé, je l'ai mis dans la liste des nouveaux livres pour rendre cette liste plus intéressante, je pense que ton livre apparaîtra dans la liste de la vitrine dans quelques jours automatiquement. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 13 septembre 2026 à 10:11 (CEST) ::Il y a aussi les livres terminés Le noyau atomique, Mémoire qui ne sont pas dans la liste des livres terminés tu pourrais les mettre dans la liste des nouveaux livres pour la completer. Ou les mettre dans la liste des livres terminés. ::Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 13 septembre 2026 à 10:18 (CEST) j7he2ha5a1cyrkvfua4fszrxb6rgyst 772108 772107 2026-09-13T08:19:44Z Xhungab 23827 /* Demandes de prises de décision */ 772108 wikitext text/x-wiki {| width="100%" align="center" style="display:block; float:center; background:#FFF; text-size:100%; margin:.5 .5 .5 .5em; padding:2px; border:1px solid #aaa; background-color:transparent;" |---- | colspan="2" align="center" width="95%" style="height:9px; margin:.2em; padding:5px; border:1px solid #aaa; background-color:#bfbfff; font-size:130%; text-align:center; float:center" | '''Bienvenue sur Wikilivres, {{BASEPAGENAME}}&nbsp;!''' |---- | colspan="2" align="center" width="85%" style="font-size:110%" | <br/>Wikilivres est un projet francophone de rédactions de manuels pédagogiques libres. |---- | valign="middle" align="center" | [[Image:Crystal Clear app Login Manager.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Si vous désirez vous investir dans ce projet passionnant, vous êtes le bienvenu. Tous les contributeurs de Wikilivres vous invitent à corriger et développer les livres existants et à créer le votre !<br /> Prenez avant toute chose connaissance des '''[[Wikilivres:Présentation|principes fondateurs de Wikilivres]]''' à la base du projet. N'ayez aucune crainte d'abîmer la bibliothèque : toutes les modifications sont suivies par des contributeurs plus expérimentés qui pourront corriger vos éventuelles erreurs. Ne vous offensez pas de ces interventions ni des messages destinés à vous aider à comprendre le projet et ses règles. Suivez leurs conseils et n'hésitez pas à demander simplement plus d'explications ! |---- | valign="middle" align="center" | [[Image:ACE.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Lorsque vous contribuez, '''gardez à l'esprit que Wikilivres est une ''bibliothèque universelle''''', il faut donc veiller à '''respecter un point de vue vérifiable'''. De plus, le contenu doit rester conforme à notre licence d'utilisation libre (GFDL).<br> Les utilisateurs travaillent en harmonie et privilégient la discussion aussi courtoise que possible pour régler les oppositions, aussi, prenez le temps de vous y habituer. Pensez à vous présenter également sur votre [[Utilisateur:{{PAGENAME}}|page d'utilisateur]], ce qui permettra à chacun de connaître vos centres d'intérêt et de mieux vous guider vers les divers projets thématiques. Pour cela, vous pouvez employer les [[Wikilivres:Boîtes utilisateur|boîtes utilisateur]].<br /> Bien qu'il s'agisse d'un travail de rédaction complexe résultant de l'action de milliers de contributeurs francophones du monde entier, sa philosophie peut être résumée en quelques mots : '''« N'hésitez pas à l'améliorer ! »''' |---- | valign="middle" align="center" | [[Image:Plume pen w.png|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Au cours d'une discussion, n'oubliez pas de signer vos messages, à l'aide de quatre tildes (<nowiki>~~~~</nowiki>) ou du bouton [[Image:Bouton Signature.png|25px|lien=]] présent en haut de la fenêtre de modification. En revanche ne signez pas les livres lorsque vous en créez ou que vous les modifiez car l'historique permet de retrouver toutes vos contributions.<br> |---- | valign="middle" align="center" | [[Image:Wikibooks logo.svg|55px|lien=]] | align="left" width="90%" style="font-size:100%; margin:.7em; padding:4px;" | Vous pouvez trouver des explications détaillées à partir des pages : * '''''[[Aide:Accueil|Tout l'indispensable]]''''', à lire absolument, * '''[[Aide:Syntaxe|Syntaxe]]''', les conventions d'écriture à connaître. * '''[[Aide:Poser une question|Poser une question]]''', si vous vous sentez perdu. * '''[[Aide:Comment modifier une page|Comment modifier une page]]''' Vous pourrez ajouter par la suite d'autres pages d'aide ou les informations dont vous pensez avoir besoin dans votre [[Utilisateur:{{PAGENAME}}|espace utilisateur]]. Si vous souhaitez contribuer mais que vous n'avez pas d'idées, allez faire un tour sur [[Wikilivres:Demande de livre|les demandes de livres et de traductions !]]. Bonne contribution, et n'hésitez pas à me contacter si besoin !<br> <small>PS: If you arn't French, you can consult the [[Wikilivres:Ambassade|embassy]] for help.</small> |} --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 mars 2013 à 20:42 (CET) == Page et sous-pages == Bonjour, Remarque concernant l'organisation d'un livre : il faut que les chapitres ait un titre de la forme <code>titre du livre/titre du chapitre</code> (avec un slash / servant de séparateur). Par exemple la page <code>Motivation</code> ne veut rien dire hors de son contexte : un autre livre peut également avoir un chapitre nommé '''Motivation'''. Il vaut mieux la nommer <code>Pédagogie : psychologie cognitive appliquée à l'enseignement/motivation</code>. [[Wikilivres:Conventions sur les titres]] --&nbsp;◄&nbsp;[[Utilisateur:DavidL|'''D'''avid&nbsp;'''L''']]&nbsp;•&nbsp;[[Discussion Utilisateur:DavidL|discuter]]&nbsp;► 9 novembre 2013 à 15:13 (CET) == Share your experience and feedback as a Wikimedian in this global survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir.<ref group=survey>Le principal objectif de l’enquête est d’obtenir des retours sur le travail actuel de la Fondation Wikimédia, sans stratégie à long terme.</ref> Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Afin de vous remercier pour le temps accordé, nous livrons 20 t-shirts Wikimédia à des personnes choisies au hasard parmi celles ayant répondu à l’enquête.<ref group=survey>Questions légales : pas d’achat nécessaire. Vous devez avoir l’âge de la majorité pour participer. Soutenu par la Fondation Wikimédia (Wikimedia Foundation) située au 149 New Montgomery, San Francisco, CA, USA, 94105. Se termine le 31 janvier 2017. Le don est annulé en cas d’infraction. [[m:Community Engagement Insights/2016 contest rules|Cliquez ici pour lire les règles du concours]].</ref> Le questionnaire est disponible dans différents langages et requiert entre 20 et 40 minutes pour être complété. <strong>'''[https://wikimedia.qualtrics.com/SE/?SID=SV_6mTVlPf6O06r3mt&Aud=VAE&Src=57VAEOP Répondez-y maintenant !]'''</strong> Vous pouvez lire davantage d’informations sur [[m:Community_Engagement_Insights/About_CE_Insights|ce projet]]. Cette enquête est hébergée par un service tiers et régie par sa [[:foundation:Community_Engagement_Insights_2016_Survey_Privacy_Statement|déclaration de confidentialité]]. Visitez notre [[m:Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique à surveys@wikimedia.org. Merci ! --[[:m:User:EGalvez (WMF)|EGalvez (WMF)]] ([[:m:User talk:EGalvez (WMF)|talk]]) 13 janvier 2017 à 23:25 (CET) </div> <!-- Message envoyé par User:EGalvez (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2016/57-VAEOP&oldid=16205400 --> <references group=survey /> == Mewtow, vous aussi venez discuter de l'avenir du mouvement == Bonjour, Je viens vous inviter à rejoindre les discussions en cours sur le futur du mouvement Wikimédia. Depuis quelques jours déjà, des contributeurs, à travers divers projets et langues sur wikis, discutent de nos priorités, en tant que mouvement, pour les 15 années à venir : Quelle est la chose la plus importante à faire ? Comment maintenir ou accélérer notre progrès? Qu'est-ce qui pourrait consolider notre unité en tant que mouvement? Voici autant de questions auxquelles tous essaient d’apporter des réponses. Vous aussi, votre point de vue compte énormement. On prend l'avis de tout le monde y compris les correcteurs d'orthographe {{sourire}}. N’hésitez surtout pas à consulter la page des discussions sur [[Wikilivres:Mouvement Wikimedia/Stratégie 2017]] pour y laisser vos propositions ou pour débattre des propositions des autres. Voici quelques liens utiles sur le contexte et le processus de cette consultation : * [[M:Strategy/Wikimedia movement/2017/Process/Briefing/fr|Contexte général]], pour comprendre les objectifs et jeter un coup d'oeil aux études et statistiques connexes * [[M:Strategy/Wikimedia movement/2017/Process/fr|Calendrier et processus]], pour plus de détails sur les dates et consulter le graphique illustrant toutes les étapes * [[M:Strategy/Wikimedia_movement/2017/Frequently_asked_questions/fr|Foire Aux Questions (FAQ)]], pour les questions qui reviennent fréquemment N'hésitez pas à me contacter au besoin. Amicalement, [[Utilisateur:Samuel (WMF)|Samuel (WMF)]] ([[Discussion utilisateur:Samuel (WMF)|discussion]]) 29 mars 2017 à 17:32 (CEST) == Discussion des principes de Fonctionnement de Wikibooks == Bonjour, j'ai modifié des pages d'aide : [[Wikilivres/Introduction]], [[Wikilivres/Démarrer un wikilivre]] et créé [[Wikilivres/Pourquoi écrire sur Wikibooks ?]]. Mes modifications concernent les principes de fonctionnement de Wikibooks, sur le travail coopératif, le respect des auteurs et le droit de signer ses livres. Tous les contributeurs sont concernés. Une discussion est initiée sur [[Discussion:Wikilivres/Démarrer un wikilivre]]. J'aimerais bien avoir votre avis. [[Utilisateur:Thierry Dugnolle|Thierry Dugnolle]] ([[Discussion utilisateur:Thierry Dugnolle|discussion]]) 27 avril 2017 à 16:43 (CEST) == Notes == == Relecture == Bonjour, Afin d'éviter toute « collision » lors d'éditions simultanées, ce serait bien que tu m'indiques directement que tel ou tel chapitre est en état d'être relu ! Amitiés, [[Utilisateur:Jean-Jacques MILAN|Jean-Jacques MILAN]] ([[Discussion utilisateur:Jean-Jacques MILAN|discussion]]) 26 juin 2017 à 10:09 (CEST). :Bonjour, :Pour le moment, à l'exception des trois chapitres sur les satellites et les corps transneptuniens, tous les chapitres sont terminés et en état d'être relus/corrigés. :Cordialement. == [[Architecture des ordinateurs]] == Bonjour Mewtow, Un utilisateur [[Discussion:Architecture des ordinateurs#Fusion|suggère de fusionner]] l'ébauche de livre [[Architecture des ordinateurs]] dans [[Fonctionnement d'un ordinateur]]. Si des éléments te semblent viables, n'hésite pas à t'en servir. Sinon, je déplacerai [[Architecture des ordinateurs]] vers des brouillons afin de ne pas encombrer la wikilibrairie. Bienvenue sur Wikibooks, puisque nous ne sommes pas croisés. Bonne continuation ! Bien cordialement, 10 juillet 2017 à 16:03 (CEST) :Bonjour Savant-fou. :Après lecture du cours en question, je ne pense pas que je pourrais réutiliser quoique ce soit du cours "Architecture des ordinateurs" (que je connaissais depuis longtemps, mais n'avais pas souhaité modifier). La quasi-totalité de ce qui est présent dans ce cours l'est aussi dans le mien, avec cependant quelques exemples ou exercices en plus que je ne penses pas pertinent d'insérer dans mon ouvrage. Je ne m'opposerais pas du tout à ce que vous le déplaciez vers des brouillons, comme vous l'avez mentionné. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 10 juillet 2017 à 19:09 (CEST) ::Merci pour ta réponse. J'ai déplacé Architecture des ordinateurs vers [[Utilisateur:Merrheim/Architecture_des_ordinateurs]]. La page [[Architecture des ordinateurs]] redirige maintenant vers [[Fonctionnement d'un ordinateur]]. Bonne journée ! [[Fichier:P_physics.svg|25px|link=User:Savant-fou]]&nbsp;[[Utilisateur:Savant-fou|Savant-fou]] <small><sup>[[Discussion Utilisateur:Savant-fou|parler]]</sup></small> 11 juillet 2017 à 09:54 (CEST) == Share your experience and feedback as a Wikimedian in this global survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! La Fondation Wikimédia vous demande votre avis dans une enquête. Nous souhaitons savoir si nous répondons bien à vos attentes dans votre travail sur les wikis et à l’extérieur, et ce que nous pouvons faire pour améliorer les choses à l’avenir. Les opinions que vous partagez affecteront directement le travail actuel et futur de la Fondation Wikimédia. Vous avez été choisi·e au hasard pour répondre à l’enquête, car nous souhaitons obtenir des informations de la part de votre communauté Wikimédia. Le questionnaire est disponible dans différentes langues et requiert entre 20 et 40 minutes pour être complété. <big>'''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant !]'''</big> Vous pouvez trouver davantage d’informations concernant cette enquête [[m:Special:MyLanguage/Community_Engagement_Insights/About_CE_Insights|sur la page du projet]] et voir comment vos retours aident la Fondation Wikimédia à prendre en charge des contributeurs comme vous. Cette enquête est hébergée par un service tiers et régie par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] (en anglais). Visitez notre [[m:Special:MyLanguage/Community_Engagement_Insights/Frequently_asked_questions|page des questions fréquentes]] pour trouver plus d’informations sur cette enquête. Si vous avez besoin d’aide supplémentaire, ou désirez vous désabonner des communications futures au sujet de cette enquête, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]] pour être supprimé·e de la liste. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 29 mars 2018 à 20:36 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Reminder: Share your feedback in this Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Chaque réponse à cette enquête peut aider la Fondation Wikimédia à améliorer votre expérience sur les projets Wikimédia. Jusqu’à présent, nous n’avons entendu que 29% des contributeurs Wikimédia. Le sondage est disponible dans plusieurs langues et prend entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' Si vous avez déjà répondu à ce sondage, nous sommes désolé que que vous receviez ce rappel. Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. <span class="mw-translate-fuzzy">Si vous souhaitez ne pas recevoir le prochain rappel ou un autre sondage, envpyez un courriel en utilisant la fonction d'envoi à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]</span>. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. Merci ! </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 13 avril 2018 à 03:35 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17881403 --> == Your feedback matters: Final reminder to take the global Wikimedia survey == <div class="mw-parser-output"> <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> Bonjour ! Voici un dernier message pour vous rappeler que le questionnaire de l’enquête de la Fondation Wikimédia se fermera le '''23 avril 2018 à 07 h (UTC)'''. Le questionnaire est disponible dans différentes langues et demande entre 20 et 40 minutes pour être complété. '''[https://wikimedia.qualtrics.com/jfe/form/SV_5ABs6WwrDHzAeLr?aud=VAE&prj=ot&edc=6&prjedc=ot6 Répondez-y maintenant.]''' '''Si vous avez déjà participé à ce sondage, merci ! Nous ne vous dérangerons plus.''' Nous avons conçu le sondage afin qu'il soit impossible de savoir qui a répondu, aussi nous devons envoyer les rappels à tout le monde. Pour vous désabonner des sondages futurs, envoyez un courrier électronique via la fonctionnalité EmailUser à [[:m:Special:EmailUser/WMF Surveys|WMF Surveys]]. Vous pouvez également envoyer toute question que vous auriez à cette adresse d’utilisateur. [[m:Community_Engagement_Insights/About_CE_Insights|Lisez-en plus sur cette enquête sur la page du projet.]] Le sondage est hébergé par un service tiers et régi par cette [[:foundation:Community_Engagement_Insights_2018_Survey_Privacy_Statement|déclaration de confidentialité]] de la Fondation Wikimédia. </div> <span class="mw-content-ltr" dir="ltr">[[m:User:WMF Surveys|WMF Surveys]]</span>, 20 avril 2018 à 02:44 (CEST) </div> <!-- Message envoyé par User:WMF Surveys@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=Community_Engagement_Insights/MassMessages/Lists/2018/ot6&oldid=17952438 --> == Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, La Wikimedia Foundation sollicite votre point de vue dans une enquête sur votre expérience avec {{SITENAME}} et Wikimedia. L’objectif de cette enquête est de savoir à quel niveau la ''Foundation'' soutient correctement (ou non) votre travail sur le wiki, et de quelle manière nous pouvons changer ou améliorer les choses à l’avenir. Les avis que vous émettrez impacteront directement le travail actuel et futur de la Wikimedia Foundation. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 9 septembre 2019 à 16:34 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19352874 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il y a quelques semaines, nous vous avons invité à participer à l’enquête sur les Perspectives de la communauté. Il s’agit de l’enquête annuelle de la Wikimedia Foundation auprès de nos communautés internationales. Nous voulons savoir à quel niveau nous soutenons correctement (ou non) votre travail sur le wiki. Nous avons atteint 10% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! '''Votre voix compte à nos yeux'''. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 20 septembre 2019 à 21:14 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19395141 --> == Reminder: Community Insights Survey == <div class="plainlinks mw-content-ltr" lang="fr" dir="ltr"> '''Faites part de votre expérience dans cette enquête''' Bonjour {{PAGENAME}}, Il reste quelques semaines seulement pour participer à l’enquête sur les Perspectives de la communauté ! Nous avons atteint 30% de notre objectif de participation. Si vous n’avez pas encore participé à l’enquête, vous pouvez nous aider à atteindre notre objectif ! Avec ce sondage, la Wikimedia Foundation recueille un retour sur le niveau de qualité de notre soutien de votre travail sur le wiki. Seules 15–25 minutes sont nécessaires pour achever de répondre à l’enquête, et cela a un impact direct sur le soutien que nous apportons. Merci de prendre 15 à 25 minutes pour '''[https://wikimedia.qualtrics.com/jfe/form/SV_0pSrrkJAKVRXPpj?Target=CI2019List(other,act5) donner votre point de vue à travers cette enquête]'''. Elle est disponible dans plusieurs langues. Cette enquête est hébergée par un tiers et [https://foundation.wikimedia.org/wiki/Community_Insights_2019_Survey_Privacy_Statement régie par cette déclaration de confidentialité] (en anglais). Vous pouvez lire [[m:Community Insights/Frequent questions|plus d’informations sur ce projet]]. [mailto:surveys@wikimedia.org Envoyez-nous un courriel] si vous avez une quelconque question ou si vous ne voulez pas recevoir d’autres messages concernant cette enquête. Cordialement, </div> [[User:RMaung (WMF)|RMaung (WMF)]] 4 octobre 2019 à 19:04 (CEST) <!-- Message envoyé par User:RMaung (WMF)@metawiki en utilisant la liste à https://meta.wikimedia.org/w/index.php?title=CI2019List(other,act5)&oldid=19435548 --> == huit gluons au lieu de neuf == Bonjour Mewtow, merci pour votre wikilivre sur le noyau atomique, que je commence juste à lire. Concernant les gluons, compte tenu de leurs attributs : 1 - une couleur parmi trois, 2 - une anti couleur parmi trois, ça devrait faire 3x3 '''neuf''' gluons. Il n'y en a bien que huit mais uniquement pour une raison théorique difficile à piger pour moi, cf [[w:Gluon#Pourquoi huit gluons au lieu de neuf ?]] Çà me semble important de le souligner dans le wikilivre, car le premier pignouf (comme moi) qui fera le calcul trouvera ... 9 et pensera que l'auteur du wikilivre s'est trompé. cordialement --[[Utilisateur:JihemD|JihemD]] ([[Discussion utilisateur:JihemD|discussion]]) 13 août 2020 à 17:20 (CEST) : Effectivement, il y a bien une erreur. Je corrige de suite. Merci d'avoir fait la remarque.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 21:48 (CEST) : Et j'en ai profité pour donner l'explication du pourquoi huit gluons et non neuf. A voir si l'explication que je donnes est facile à comprendre ou pas. A mon avis, la superposition des gluons devrait être difficile à comprendre, mais le reste de l'explication devrait passer.[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 13 août 2020 à 22:32 (CEST) == Appel à relecture et création d'hyperliens == Bonjour Mewtow. Je découvre avec plaisir le projet Wikilivres en décidant de publier les trois premiers chapitres de ma thèse de doctorat sous forme de livre. En parcourant le contenu, je suis tombé sur les nombreux ouvrage que tu as déjà produit ici. De là m'est venu une idée. Plutôt que de mettre dans mon texte des wikiliens pointant vers Wikipédia pour aider les lecteurs à trouver un complément d'information, pourquoi pas les rediriger vers des travaux déjà existants sur Wikilivres. Le problème, c'est que je n'ai pas vraiment le temps de parcourir tout ceux-ci. C'est donc la raison pour laquelle je viens poster ce message pour voir si tu ne pourrais pas m'aider dans cette tâche. Toi qui connais bien le contenu de tes livres, tu pourrais effectivement créer toi-même dans livre que je suis en train de terminer les hyperliens qui pourraient pointer vers tes travaux. L'idéal serait même de remplacer tous ceux qui pointent vers Wikipédia pour éviter que le lecteur ne doive surfer sur deux sites différents lors d'une consultation hors ligne notamment. Tu me diras ce que tu en penses. Voici déjà le titre de mon ouvrage : [[Le mouvement Wikimédia]]. N'hésite pas non plus à faire des remarques sur sa page de discussion si jamais lors d'une éventuelle lecture, tu trouverais des informations fausses. Dès que j'en aurai le temps, je passerai aussi du temps sur tes ouvrages qui ont l'air intéressants. Bien à toi, [[User:Lionel Scheepmans|Lionel Scheepmans]] <sup><big>✉</big> [[User talk:Lionel Scheepmans|Contact]]</sup> <sub>Désolé pour ma [[w:dysorthographie|dysorthographie]], [[w:dyslexie|dyslexie]] et [[wikt:distraction|"dys"traction]].</sub> 29 novembre 2021 à 14:48 (CET) == Prise de décision - fin dimanche 2 juin == Bonsoir Mewtow, Tout d'abord un grand merci pour ta contribution très active à Wikilivres. Je t'informe qu'une "prise de décision" (débat) est en cours concernant le retrait automatique des liens rouges lorsqu'une image est supprimée sur Commons. Lien : [[Wikilivres:Prise de décision/Laisser les liens rouges des images]]. '''La phase de discussion se termine le dimanche 2 juin à 23 h 59.''' D'avance, merci pour ta participation ! Cdlt, [[Utilisateur:Fourmidable|Fourmidable]] ([[Discussion utilisateur:Fourmidable|discussion]]) 25 mai 2024 à 23:56 (CEST) == Ouvrages sources des wikibooks sur l'Electricité et l'Electronique == Bonjour Mewtow, Je suis en train de lire les wikibooks sur l'Electricité et l'Electronique dont tu es l'auteur, et je te remercie beaucoup pour l'excellent travail que tu as fait!! :) Quelles sont les ouvrages sources dont tu t'es servi pour les écrire ? En te remerciant par avance. Cdlt, [[Utilisateur:Alex Mtlr|Alex Mtlr]] ([[Discussion utilisateur:Alex Mtlr|discussion]]) 16 juillet 2025 à 13:57 (CEST) :Bonjour Alex. :Pour être franc, les sources principales sont les cours que j'ai eu pendant ma scolarité, lors de mon Bac STI option génie électronique, et mon BTS systèmes électroniques. Pour ce qui est du cours d'électronique, notamment tout ce qui a trait aux transistors, je me souviens avoir utilisé un bouquin nommé "Circuits microélectroniques", par Adel Sedra et Kenneth C. Smith, que j'ai revendu il y a de cela quelques années. J'ai aussi ai lu pas mal de fichiers .pdf disponibles sur le net, accessibles via quelques recherches Google, mais ca fait un moment que j'ai rédigé ces cours et j'ai un peu oublié lesquels. :C'est tout ce dont je me souviens pour le moment. :Cordialement. :[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 16 juillet 2025 à 16:24 (CEST) == Pages orphelines == Bonjour, Il semble que certaines de vos pages se sont perdues dans les pages orphelines. Pourriez-vous les garder ici dans votre page de discussion pour qu'elles ne soient plus orphelines. Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 25 février 2026 à 14:07 (CET) :Pas de problème pour les garder sur ma page de discussion. Par contre, certaines des pages en question sont à supprimer, car leur contenu a été déplacé dans des chapitres existants. Faudra que je regarde cela cette semaine et que je me renseigne sur la procédure pour les faire supprimer. :Dans la liste précédente, les deux chapitres suivants sont dans ce cas : :* [[Les opérations bit à bit/Calculs flottants]] :* [[Les suites et séries/Les suites arithmético-géométriques]] :Il y a aussi ceux identifiés dans "Fontionnement d'un ordinateur", qui ont été identifiés ailleurs. Je n'ai aucun chapitre brouillon pour ce cours. [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 25 février 2026 à 20:04 (CET) ::Bonjour, ::* Voir le Bistro, il semble que cela soit difficile de supprimer une page ::* Il y a une vingtaine de livres dans ta situation. Je les ai regroupés dans ce livre. Voir les derniers chapitres, la présentation des premiers chapitres laisse à désirer ::*. ::* [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] ::*. ::Par exemple pour ton cas : ::*. ::*. ::La page orpheline : ::* [[Les opérations bit à bit/Calculs flottants|Les opérations bit à bit/Calculs flottants]] ::a été copiée ici: ::* [[Les opérations bit à bit/Les opérations arithmétiques sur des flottants|Les opérations bit à bit/Les opérations arithmétiques sur des flottants]] ::*. ::La page orpheline : ::* [[Les suites et séries/Les suites arithmético-géométriques|Les suites et séries/Les suites arithmético-géométriques]] ::a été copiée ici: ::* [[Les suites et séries/Les suites numériques|Les suites et séries/Les suites numériques]] ::*. ::Tu peux naturellement simplement laisser tes pages sur ta page en attendant qu'elles puissent être supprimées ::Où je peux les introduire pour toi dans le livre [[feuilles dupliquées orphelines|feuilles dupliquées orphelines]] en attendant qu'une bonne âme se sacrifie pour supprimer les doublons. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 00:02 (CET) :::Pas de problèmes de mon côté pour que tu ajoutes ces pages dans le livre ' feuilles dupliquées orphelines" à ma place, merci beaucoup. Je crois que ce serait la meilleure solution, vu que les chapitres dupliqués orphelins de "Fonctionnement d'un ordinateur" sont déjà dessus [[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 26 février 2026 à 01:34 (CET) ::::Merci pour ton aide. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 26 février 2026 à 11:15 (CET) * [[Le noyau atomique/Les diffusions nucléaires]] * [[Électricité/L'étude des signaux quelconques]] * [[Le noyau atomique/Les diffusions nucléaires]] * [[Les opérations bit à bit/Calculs flottants]] * [[Les suites et séries/Les suites arithmético-géométriques]] * [[Mémoire/Habiletés]] * [[Mémoire/Mémoire perceptive]] * [[Mémoire/Mémoire à court terme]] * [[Mémoire/Mémoires sensorielles]] * [[Mémoire/Oubli]] == Demandes de prises de décision == Bonjour, Pour info. J'ai posé deux demandes de prises de décisions concernant le sujet suivant. * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Cr%C3%A9er_un_espace_lecteurs_et_un_espace_auteurs_sur_la_page_d%27accueil Créer un espace lecteurs et un espace Les coulisses de Wikibook]''' * '''[https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Modifier_le_contenue_de_l%27espace_Nouveaut%C3%A9s Wikilivres:Prise de décision/Modifier le contenue de l'espace Nouveautés]''' Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 16:53 (CEST) :Bonjour, étant donné que ton livre Fonctionnement d'un ordinateur n'est pas dans la liste des livres terminés même s'il est terminé, je l'ai mis dans la liste des nouveaux livres pour rendre cette liste plus intéressante, je pense que ton livre apparaîtra dans la liste de la vitrine dans quelques jours automatiquement. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 13 septembre 2026 à 10:11 (CEST) ::Il y a aussi les livres terminés Le noyau atomique, Mémoire qui ne sont pas dans la liste des livres terminés tu pourrais les mettre dans la liste des nouveaux livres pour la completer. Ou les mettre dans la liste des livres terminés. ::Merci [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 13 septembre 2026 à 10:18 (CEST) qxp76fzq4v78vlfz4oj994gox3disci Goélette Cardabela/Équipements/Autres équipements 0 57166 772109 757641 2026-09-13T08:40:25Z Regimminius 7153 /* Cuisine */ Ortho 772109 wikitext text/x-wiki <!--{{en cours}}--> <div class="noprint">{{Relecture}}</div> <div class="noprint">{{Orange|[[Goélette_Cardabela/Équipements/Autres_équipements/Version imprimable|'''Version imprimable''']] ''de cet article.''}}</div> <!--{{PAGENAME}}--> {{#ifeq:{{PAGENAME}}|Goélette Cardabela/Équipements/Autres équipements| __FORCETOC__| __NOTOC__ }} <strong>Cette page est destinée à une lecture rapide. Le gros équipement de ''La goélette Cardabela'' est déjà bien commenté dans les autres articles. <br />Le contenu des sections de cet article sont des commentaires sur les équipements, plus ou moins importants, que l'on trouve sur la plupart des bateaux de plaisance. <br />De nombreux sujets pourraient être ajoutés, la question est : « Ont-ils de l'intérêt à être commentés ? »</strong> {{Nouvelle page imprimée}} == Mouillages == * '''Guindeau, chaîne :''' <br />Le guindeau doit être capable de remonter le poids total de la chaîne et de l'ancre la plus lourde du bord (40 kg) + 55 mètres de chaîne de 12 mm à 3,24 kg/m, soit au total : 218 kg. On peut parfois aider le guindeau avec le manche de remontée manuelle.<br />La charge de rupture de la chaine de 12 mm est de {{formatnum:7000}} kg. À défaut d'un bon frein sur le guindeau il faut utiliser une ''main de fer'' pour chaîne de 12 mm. <br />Les ''coups de boutoir'' peuvent rompre ou casser le mouillage. Afin d'éviter le pire on peut utiliser des matériaux élastiques, le plus classique est le pneu d'automobile encombrant et pas facile à conserver à bord. On peut aussi alourdir le mouillage avec des gueuses de plomb ou d'autres matériaux lourds. == Anti-roulis, chaînes et cordages, ancres == : Lien https://fr.wikibooks.org/wiki/Goélette_Cardabela/Après/La_navigation#Mouillages * '''Ancre flottante :''' <br />Elle sert surtout à maintenir le bateau face aux ''vagues du vent''. <br />Lorsque l'ancre flottante passe au sommet d'une vague elle perd son efficacité car le sommet de la vague est soufflé par le vent.<br/>Il faut que l'ancre flottante ait suffisamment de surface pour que la force de retenue empêche le bateau de ''virer par l'étrave'' lorsque le bateau est soumis à de fortes vagues qui le font [[wikt:culer|''culer'']]. <br />On peut aussi ''frapper le cordage'' de l'ancre flottante à l'arrière du bateau. La poupe est moins ''soumise'' au fardage latéral mais attention aux vagues déferlantes qui remplissent le cockpit d'eau de mer alourdissant ainsi dangereusement l'arrière du bateau. ''Voir [[wikt:culer|virer à culer'']] == Voilerie == * '''Enrouleur : '''<br />C'est vraiment ''un plus''. Le génois monté sur enrouleur remplace avec succès le foc yankee difficile à affaler sans risque de chute à la mer en bout de beaupré. L'enroulement du génois fait remonter le point d'écoute et le risque de prendre une vague dans le foc est minimisé. On retrouve là l'avantage du foc Yankee en navigation hauturière. * '''Emmagasineur :'''<br />Il est utile pour installer des voiles légères sur le bout-dehors. * '''Tangons :'''<br />Les tangons sont encombrants. Il est préférable d'installer des tangons rétractables, plus faciles à loger sur le pont. * '''Lazy-jack fixe ou escamotable ? :'''<br />Le lazy-jack fixe est gênant lorsque l'on hisse la voile avec les lattes qui se prennent dedans, d'où l'idée de concevoir un système escamotable. Avec le système escamotable il devient difficile de prendre des ris.<br />''Pourquoi un enrouleur de la grand voile dans le mât ne ferait-il pas l'affaire ?'' * '''Les voiles :'''<br />Les voiles triangulaires prennent peu le vent en hauteur or c'est à environ dix mètres au dessus du niveau de l'eau que le vent est libéré du frottement avec la terre et la mer ''(Voir [[w:Vent_géostrophique|vent géostrophique]])''.<br />Sur la goélette Cardabela on pourrait hisser une grand voile de misaine à [[w:Voile_(navire)#Voile_à_livarde|livarde]] où un wishbone remplacerait la livarde. Un coulisseau spécial avait été fabriqué dès réception des mâts en 1979 pour cet usage. Pour éviter le vrillage l'extrémité du wishbone devait être relié à la tête du mât d'artimon. == Équipement des mâts == * '''Haubans, galhaubans, étais :'''<br />Les câbles inox doivent être surveillés. On désoxyde avec des acides, on neutralise avec des bases (du savon), et on protège avec du suif. * '''Hale-bas et freins de bôme :'''<br />Frein de bôme ou retenue de bôme ? Le frein de bôme est un inconvénient lors d'un empannage et n'est pas à préconiser en course, en revanche il est bien utile avec un équipage inexpérimenté en croisière. Cela évite les coups de bôme sur la tête ou le corps. * '''Drisses et écoutes :'''<br />Il n'y a rien à dire sinon qu'il faut les vérifier régulièrement. Il n'y a rien de plus terrible qu'une voile qui s'affale toute seule sans pouvoir remplacer sa drisse en mer. Pour ce qui est des écoutes, il n'y a rien de grave on peut facilement les remplacer. === Antennes de communication (émission-réception) === Pour réaliser une installation correcte il faut vérifier que le retour d'onde est faible. On utilise un TOS mètre. ''(TOS : Taux d'onde stationnaire)''<ref>https://www.hisse-et-oh.com/system/assets/000/088/170/original/guide-d-installation-d-une-antenne-vhf-marine.pdf)</ref> * '''Vhf :'''<br/>En VHF on peut utiliser une antenne ''quart d'onde'' verticale avec un plan de réflexion. La surface de la mer peut servir de réflecteur mais si la mer est mauvaise ça ne marche pas, il est préférable d'utiliser une antenne de conception radio-amateur<ref name="RAL">http://www.f1hwg.fr/articles.php?lng=fr&pg=17&tconfig=3</ref> placée le plus haut possible. À défaut on peut placer une antenne de fabrication commerciale en tête de mât. * '''Antennes HF Radio amateur'''<ref name="RAL" />''' :''' <br />Une antenne HF avait été installée sur Cardabela, à une époque où on suivait les bateau sur la bande des 20 mètres, à une fréquence de 14 Mhz. Le marocain et une partie de pataras équipé d'un isolateur servaient d'antenne dipôle. Pour adapter et équilibrer les pôles il avait été nécessaire de créer un transformateur, une boucle de 10 spires en câble coaxial placée en haut du mât d'artimon. Entre l'émetteur et le câble d'antenne qui montait en haut du mât j'avais placé le TOS-mètre et la boîte de couplage de fabrication personnelle avec une self à roulette et des condensateurs variables.<br />Ce système n'a jamais été entièrement optimisé, il a été abandonné avec l'arrivée de nouvelles technologies de communication dont la téléphonie par satellite. * '''Antennes et capteurs de radars :''' (de l'anglais radio detection and ranging)<br />La terre est ronde et les ondes de fréquence RADAR ne suivent pas la surface de la mer. Pour être efficace l'antenne RADAR doit être placée le plus haut possible compatible dans notre cas avec la navigation à voile.<br />Les réflecteurs sont moins lourds et moins encombrants que l'antenne RADAR. On essaie toujours de placer ce réflecteur au voisinage de la tête de mât.<br/>Avec une antenne RADAR fixée à 9 mètres au dessus du niveau de la mer on ne peut guère voir au delà de 12 miles nautiques pour les plus grosses masses comme les cargos. Pour les petits navires dotés de toutes petites antennes, parfois même inclinées, on ne les voit ni de loin car la réflexion est trop faible, ni de près car les ondes passent ''par dessus''. === Antennes de réception === * '''Antenne de réception météo HF et Antenne de réception des avis urgents aux navigateurs :'''<br >La diffusion météo était autrefois largement assurée en clair, par radio télétype et fac-similé.<br />En 2018 l'émission météo est encore assurée par des stations allemandes<ref>https://radiopedia.nl/wiki/Pinneberg_(zendlocatie)</ref><ref>http://f1agw.free.fr/Synop/Synop.htm</ref><br />Un récepteur HF NASA-MARINE et son antenne sont très utiles au large. {| class="wikitable" |+ Tableau des émissions internationales en RTTY des stations allemandes |- ! scope="col"|Repère ! scope="col"|Indicatif de la station ! scope="col"|Pays ! scope="col"|Fréquence(KHz) ! scope="col"|Shift(Hz) |- |A |DDK2 (Pinneberg) |Allemagne |4583 |425 |- |B |DDH7 (Offenbach) |Allemagne |7647 |425 |- |C |DDK9 (Pinneberg) |Allemagne |10100.8 |425 |- |D |DDH47 (Offenbach) |Allemagne |147.3 |85 |- |E |DDH9 (Offenbach) |Allemagne |11039 |425 |- |F |DDH8 (Offenbach) |Allemagne |14467.3 |425 |} <div style="font-size:85%;"> * Bulletin météorologique (prévisions à 2 jours) pour l’Océan Atlantique . A, B, C : 0930, 2130. D, E, F : 0700, 1300, 1900. * Bulletin météorologique (prévisions à 2 jours) pour les eaux européennes de l’Atlantique. A, B, C : 0955, 2155. D, E, F : 0820, 1420, 2020. 3 - Bulletins pour la Mer Méditerranée. En anglais sur A, B, C. En allemand sur D, E, F. * Bulletin météorologique (prévisions à 5 jours) pour la Mer Méditerranée. A, B, C : 0415, 1610. D, E, F : 0535, 1120, 1735. * Bulletin météorologique (prévisions à 2 jours) pour la Mer Méditerranée occidentale. A, B, C : 1015, 2215. D, E, F : 0840, 1440, 2040. * Bulletin météorologique (prévisions à 2 jours) pour la Mer Méditerranée orientale. A, B, C : 1115, 2315. D, E, F : 0930, 1530, 2130. * Bulletin météorologique (prévisions 24 h) pour la Mer Méditerranée. A, B, C : 1550. D, E, F : 1610. * Observations de stations météorologiques de la Mer Méditerranée. D, E, F : 0730, 1030, 1330, 1630, 1930. </div> '''Références :''' <references /> == Électronique == Il n'y a pas grand chose à dire sur ce matériel courant j'ai juste quelques remarques à faire sur certains appareils. === Les appareils traditionnels === * '''Pilotes automatiques, Compas électronique, Girouette-anémomètre, Loch-speed-mètre :'''<br /> C'est '''tout en un''', ils communiquent entre-eux grâce à un réseau NMEA interne. Ils peuvent se connecter à un GPS et aux écrans externes et des commandes déportées.<br />'''Il faut se méfier du pilote automatique'''. Il est souvent source de problèmes par la perte vigilance. L'homme de quart ne doit à aucun moment quitter son poste d'observation. * '''Radar :'''<br /> Très utile en cas de brume de brouillard et la nuit. Il se trouve que pour économiser l'énergie de la batterie certains navigateurs de l'été évitent d'allumer leurs feux ! * '''Sondeur :'''<br /> Ces petits sondeurs permettent maintenant, non seulement d'évaluer la profondeur des fonds marins, ils permettent aussi de ''voir'' sur l'avant avec un angle de l'ordre de 30 degrés. ''Il ne faut tout de même pas trop en demander ...'' * '''Micro-ordinateur de navigation :'''<br /> Ils sont remplacés par une tablette ou un téléphone portable. Lorsqu'il ''peuvent'' être équipés d'une carte SIM le système GPS est installé dans l'appareil, il peut alors enregistrer la route. <br />''Il faut éviter d'acheter une tablette qui ne peut pas intégrer une carte SIM, mais cela peut changer ...'' === Les appareils connectés === * '''Le téléphone portable :'''<br /> Ce merveilleux petit appareil est souvent un concentré de capteurs et peut servir pour partager les communications de quelques appareil fonctionnant sous Wifi ou Bluetooth. Les capteurs sont de qualités suffisantes pour avoir une positon GPS, le cap compas, la vitesse de déplacement, le degré de gîte, la pression atmosphérique, les accélérations longitudinales et latérales, etc ... * '''Le Watching Man :'''<br /> Il est indépendant du réseau Wifi du bord, il dispose de sa propre carte SIM. <br />Il est très utile pour un contrôle à distance : Position du bateau, niveau de batterie, température du moteur, eau dans la cale, repère une présence (mouvement), la position de la porte de descente. Certains appareils peuvent être équipés d'autres capteurs. En général ils ne permettent pas de commander une action à distance. * '''Le routeur de connexions 3G, 4G, 5G avec une carte SIM :'''<br /> Il est très utile au voisinage des côtes et inutile au large !<br />À défaut on peut partager la connexion du smartphone ! * ''Alerte fumée et monoxyde de carbone :'' L'appareil fonctionne avec le Wi-Fi du bord. <br />Le capteur alerte localement par la voix et à distance sur le smartphone. il peut déclencher une caméra pour comprendre l'origine de l'alerte. * '''Confort à bord :'''<br /> Le système fonctionne avec le Wi-Fi du bord. <br />Certains appareils permettent d'évaluer le degré de confort avec des capteurs de température, humidité, bruit, CO<sub>2</sub>. L'application envoie tous les renseignements au smartphone sur demande et donne l'alerte en cas de mauvais résultat en provenance de chaque capteur. * '''Commutateurs et interrupteurs :'''<br /> Les systèmes fonctionnent avec le Wi-Fi du bord.<br />Sur le serteur 230 Volts ils permettent, par exemple, de mettre en marche l'appareil de chauffage<ref>Qivivo Thermostat connecté sans fil (contact sec) + 5-12 V 30a Haute Puissance Relais D'entree Isolement Module Optocoupleur pour radiateurs 230 V, jusqu'à 30 Ampères</ref>. <br />En basse tension (12 / 24 V) il est possible de déclencher une pompe de cale<ref>Owsoo Sonoff CC 5 V 12 V 24 V 32 V Interrupteur Wifi sans fil module de relais Smart Home Automation</ref>. <references /> {{Nouvelle page imprimée}} == Sécurité == * '''[[Goélette_Cardabela/Équipements/Installation_électrique#Tableau_des_feux_de_navigation|Feux de navigation]] :'''<br />Le tableau des feux de navigation est décrit dans les pages de l'installation électrique de la goélette Cardabela. * '''Pompes de cale :'''<br />Le commutateur de niveau peut se bloquer, la pompe peut ne plus fonctionner. Il faut donc vérifier ce fonctionnement très régulièrement.<br />Préférer les pompes de cales à membranes. * '''Vhf + gps dédié :'''<br /> Le GPS dédié permet de donner l'alerte avec la position exacte du bateau en cas de grave danger mettant la vie de l'équipage en danger. <br />Si la vie de l'équipage n'est pas en danger, appeler le CROSS. * '''Aération :'''<br /> Il est indispensable même en hivernage. Vérifier régulièrement le niveau de CO<sub>2</sub> et le niveau d'humidité. * '''Extincteurs :''' Le lobby des fabricants et exploitants des extincteurs veulent nous faire contrôler les extincteurs chaque année, tout comme le lobby des canots de survie il n'y a pas si longtemps. La durée de vie d'un extincteur à poudre est de 20 ans. <br />Pour contrôler soi-même un extincteur à poudre ABC il faut contrôler le niveau de pression affiché au manomètre, il doit être sur le vert. Renverser (retourner) l'extincteur et écouter la poudre circuler à l'intérieur, si on n'entend rien, la poudre peut s'être compactée. Vu le prix peu élevé des extincteurs à poudre neufs il est préférable de le changer.<br />L'état du bateau après avoir utilisé un extincteurs à poudre peut devenir un problème pour le nettoyage. Un extincteur à mousse (Eau et additif) pour les ''petits feux'', c'est plus facile à nettoyer mais ils sont beaucoup plus chers. == Cuisine == * '''Gaz butane :'''<br /> On peut utiliser le gaz butane avec des température légèrement positives, il se gazéifie à 2 degrés centigrades. Le gaz propane est interdit sur les bateaux de plaisance. <br />Il ne faut pas oublier de changer le tuyau d'alimentation souple. La date de péremption est obligatoirement indiquée sur le tuyau. On le change entre 5 et 10 ans, 8 ans en moyenne. * '''Brûleurs :'''<br /> Ils doivent être munis de thermocouples qui coupent l'arrivée du gaz en cas d'extinction de la flamme. ** '''Détecteurs de gaz butane dans les fonds :'''<br /> Il faut déjà en trouver. Au radio club des constructeurs amateurs de bateaux on avait conçu un détecteur de gaz butane très efficace avec les ''allume-gaz'' d'autrefois en fil de platine. En présence de gaz butane le fil chauffe au rouge et sa résistance change. Ce phénomène est mis à profit pour déclencher un alarme. Il faut bien entourer la cellule de détection avec un grillage très fin, faute de quoi le détecteur se transforme en ... allume-gaz ! * '''Four :'''<br /> Le four à gaz est déconseillé sur un petit bateau ! * '''Microndes+grill et chaleur tournante pour les escales :'''<br /> C'est mieux que le four à gaz. En navigation on utilise peu les fours ... * '''Réfrigérateur et congélateur :'''<br /> Ce sont de gros consommateurs d'énergie, il faut compenser cette dépense d'énergie avec des panneaux solaires + éolienne et il sera encore certainement utile de mettre le moteur en marche de temps en temps pour ''regonfler'' (Recharger) les batteries. * '''Désalinisateur d'eau de mer :'''<br /> Cela peut être utile pour les grandes croisières ou pour les longs séjours dans les mouillages isolés. [[Catégorie:Goélette Cardabela (livre)|{{SUBPAGENAME}}]] lelv2mz33h25s8oq98zmi499566q6se Fonctionnement d'un ordinateur 0 65764 772105 744155 2026-09-13T08:04:08Z Xhungab 23827 772105 wikitext text/x-wiki {{Page de garde|image=Personal computer, exploded 6.svg|description= Dans ce cours, vous allez apprendre quels sont les composants d'un ordinateur et comment ceux-ci fonctionnent. Ce cours commencera par des choses simples, comme le binaire, pour arriver progressivement jusqu'au fonctionnement des derniers processeurs, en passant par plein de choses passionnantes comme l'assembleur, les mémoires caches, etc. Ce cours est accessible à n'importe qui, sans prérequis, mais se veut cependant assez complet et riche en informations. |avancement=Terminé |cdu= * {{CDU item|6/68/681|681.3/681.31}} |versions= {{version imprimable|page=Fonctionnement d'un ordinateur/Version imprimable 2}} {{version PDF}} }} __NOTOC__ : '''L'auteur du livre tient à remercier vivement Dominus Carnufex et Vayel, qui se sont chargés de la relecture et de la correction orthographique d'une ancienne version de ce cours. Merci à eux pour le travail titanesque qui a été fourni.''' {{/Sommaire}} ==Liens vers ressources externes== ===Sur wikilivres=== * [[Les cartes graphiques|Les cartes graphiques]], un livre du même auteur qui aborde spécifiquement l'architecture des cartes vidéo. * [[Monter_un_PC|Monter un PC]], pour une approche bien plus pratique et utile. * [[Les systèmes d'exploitation|Les systèmes d'exploitation]], un cours qui explique l'interaction entre systèmes d'exploitation et matériel. Le sujet (les systèmes d'exploitation) est si lié au matériel informatique qu'il peut être vu comme un prolongement du présent cours, ou tout du moins comme un très bon complément. * [[Électronique numérique : logique|Électronique numérique : logique]], un cours d'électronique numérique, disponible sur Wikilivre. Un excellent complément pour les premiers chapitres du cours. ===Liens divers=== * [http://users.ece.cmu.edu/~koopman/stack_computers/index.html Stack Computers: the new wave] : un livre sur les architectures à pile. * [https://homes.cs.washington.edu/~levy/capabook/ Capability-Based Computer Systems] : un livre sur les architectures à capacités. * [http://www.analogmuseum.org/english/ Museum of analog computing]. Ce site en anglais parle d'un sujet qui n'a pas été abordé dans ce livre : les calculateurs analogiques. * [https://www.icsa.inf.ed.ac.uk/research/groups/hase/models/ Des simulateurs pour des architectures réelles ou fictives.] {{AutoCat}} [[Catégorie:Informatique]] [[Catégorie:Électronique]] {{Nouveau livre|}} ifakykcm4683tw35soil0f6y7b4ukad Fonctionnement d'un ordinateur/Les processeurs de traitement du signal 0 65767 772100 766753 2026-09-12T18:22:07Z Mewtow 31375 /* L'optimisation des boucles sur un DSP */ 772100 wikitext text/x-wiki Les '''processeurs de traitement du signal''', sont des jeux d'instructions spécialement conçus pour travailler sur du son, de la vidéo, des images, ou toute autre forme de signal. Ils sont aussi appelés des DSP, abréviation de ''Digital Signal Processor''. Le jeu d'instruction d'un DSP est assez spécial, car il est conçu pour des applications très spécifiques. Et la conséquence est que leur jeu d'instruction est complétement à part du reste, au point où leur donner un chapitre à part est une nécessité. ==Contexte : le traitement temps réel d'un signal== Le traitement du signal regroupe tout ce qui traite de l'audio, de la vidéo, mais aussi d'autres formes de signaux plus difficiles à conceptualiser. Les cas d'utilisations les plus courant sont le traitement d'image (appareils photos), la compression et le filtrage vidéo, les cartes sons d'un ordinateur ou d'une console de jeu, les communications sans fil avec des périphériques, la téléphonie, et autres usages moins familiers (radars, imagerie médicale). Le traitement de signal était autrefois réalisé par des composants purement analogiques. Les circuits analogiques de ce type étaient utilisés dans les anciennes radios, les chaines HI-FI, les télévisions, les magnétoscopes, et bien d'autres composants électroniques moins familiers. De nos jours, le signal est traité par des processeurs numériques. Un système audio/vidéo/autres fonctionne cependant encore avec des signaux analogiques. Simplement, il y a une conversion analogique vers numérique, un traitement par un DSP, puis une conversion numérique vers analogique. [[File:DSP block diagram.svg|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP.]] [[File:Dsp bloc fr.png|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP, en français.]] ===Un flux de données échantillonné=== Le signal sonore/vidéo/autre qui est capté est un signal analogique : il change en permanence, il n'a pas de fréquence définie. Mais ce signal est échantillonné, à savoir que l'on mesure sa valeur à une fréquence prédéterminée, appelée la '''fréquence d’échantillonnage'''. Par exemple, pour un signal sonore, la fréquence d’échantillonnage est de 44,1 kHz, 48 kHz, 96 kHz ou 192 kHz. Soit une mesure approximativement toutes les 22,6 µs, 20,83 µs, 10,4 µs, 5,2 µs. L'intensité sonore mesurée à un instant est appelée un échantillon sonore. Il existe un équivalent pour la vidéo : les échantillons sont les images à afficher à l'écran, il y en a une toutes les 1/24ème de secondes pour une vidéo à 24 FPS. [[File:Sampled.signal.svg|centre|vignette|upright=1.5|Signal échantillonné.]] Les échantillons sont généralement accumulés dans une structure de donnée en mémoire RAM, appelée une '''file'''. Il s'agit d'un paquet d'échantillon classés par ordre d'arrivée (une structure de donnée de type FIFO). Elle a une taille finie, ce qui fait que le nombre d'échantillons est prédéfini à l'avance. Quand un échantillon est ajouté dans une FIFO pleine, la donnée la plus ancienne est éliminée (elle a déjà été traitée de toute façon). Les FIFOs de ce type sont conçues à partir d'un tableau, auquel on a ajouté deux pointeurs : un pour la donnée la plus ancienne, un pour la plus récente. Pour le dire autrement, ces deux pointeurs correspondent au début de la file et à sa fin. Le début de la file correspond à l'endroit où l'on insère les nouvelles données. La fin de la file correspond à la donnée la plus ancienne en mémoire. À chaque ajout de donnée, on doit mettre à jour l'adresse de début de file. Lors d'une suppression, c'est l'adresse de fin de file qui doit être mise à jour. Ce tableau a une taille fixe. Si jamais celui-ci se remplit jusqu'à la dernière case, (ici la cinquième), il se peut malgré tout qu'il reste de la place au début du tableau : des retraits de données ont libéré de la place. L'insertion continue alors au tout début du tableau. Cela demande de vérifier si l'on a atteint la fin du tableau à chaque insertion. De plus, en cas de débordement, si l'on arrive à la fin du tableau, l'adresse de la donnée la plus récemment ajoutée doit être remise à la bonne valeur : celle pointant sur le début du tableau. Tout cela fait pas mal de travail. Les DSPs ont des modes d'adressages spécialisés pour accéder à des données dans de telles files, comme on le verra plus bas. ===Les algorithmes exécutés par un DSP=== Un DSP exécute des algorithmes très précis : un algorithme de filtrage, un algorithme de transformée de Fourier rapide, un algorithme de '''''Finite Impulse Response''''', des algorithmes de convolution, ou tout autre algorithme de traitement de signal. L'algorithme travaille sur un nombre fini d'échantillons, qui sont lus depuis la file décrite plus haut. Le jeu d'instruction d'un DSP est optimisé pour les algorithmes de traitement de signal les plus courants. Aussi, pour comprendre le jeu d'instruction d'un DSP, nous n'avons pas le choix : il faut étudier quelques algorithmes de traitement de signal. Mais rassurez-vous, pas besoin d'aller dans le détail. Nous allons voir quelques algorithmes simples, et encore : nous allons les survoler, sans expliquer pourquoi et comment ils marchent. L'exemple le plus utile pour l'étude des DSP est celui du filtre FIR (''Finite Impulse Response''). Celui-ci est assez simple sur le principe : on prend les N échantillons les plus récents, on les multiplie chacun par un coefficient, et on additionne le tout. La formule exacte ressemble à ceci : : <math>y(t) = {\sum_{n=0}^{N-1}} b_n \cdot x[t - n]</math>, avec <math>b_n</math> le coefficient de l'échantillon à l'instant t-n. [[File:FIRdrekteForm.png|centre|vignette|upright=2|Représentation graphique d'un filtre FIR. Les échantillons à l'instant n sont notés u(n), T représente le délai entre deux échantillons.]] Vous remarquerez que cet algorithme s'implémente avec une boucle, chaque itération faisant une multiplication suivie d'une addition. Si on suppose que les N échantillons sont mémorisés dans un tableau, et que les N coefficients sont dans un second tableau, alors le code devrait être le suivant : <syntaxhighlight lang="c"> int resultat = 0 ; for (i=0 ; i < N ; ++i) { resultat += coefficient[i] * echantillons[i] ; } </syntaxhighlight> Et c'est une règle pour de nombreux algorithmes de traitement de signal : ils s'implémentent avec une boucle, qui parcourt un ou plusieurs tableaux/files, l'intérieur de la boucle faisant des calculs du type a * b + c. Il est intéressant de regarder ce que donne le codé précédent, une fois compilé sur une architecture RISC. Un point important est que ce code manipule quatre variables par itération de boucle : les deux opérandes de la multiplication, le résultat de la multiplication, et la variable d'accumulation resultat. On va placer les deux opérandes dans les registres R0 et R1, le résultat de la multiplication dans le registre R2, et la variable resultat dans le registre R3. Le compteur de la boucle est mémorisé dans le registre R7. Voici une sorte de pseudo-code ASM qui ressemble pas mal à ce que sortirait un compilateur, avec pas mal de simplifications de notations pour faire passer la pilule. Les commentaires indiquent qu'une étape de calcul d'adresse est réalisée, en utilisant plusieurs instructions. <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> En clair, on charge les deux opérandes dans un registre, on multiplie, on additionne, puis on effectue de quoi gérer la boucle. La '''transformée de Fourier rapide''' est un algorithme un peu plus complexe que le précédent, mais particulièrement utile en traitement de signal. Sans rentrer dans les détails d'implémentation, il agit sur des nombres complexes, qui sont composés d'une partie réelle et la partie imaginaire. Les parties entières et imaginaires sont encodés avec deux nombres entiers ou flottants. L'algorithme utilise un tableau de nombres complexes, qui est en pratique séparé en deux tableaux séparées, avec un tableau pour les parties réelles et un autre pour les parties imaginaires. La transformée de Fourier rapide est composée d'une boucle qui applique à chaque itération une opération dite ''butterfly''. Elle prend en entrée un nombre complexe, et fournit un autre nombre complexe en sortie. Elle applique des multiplications/additions sur deux variables qu'on appellera A et B. À chaque itération de boucle, l'opération ''butterfly'' exécute le calcul suivant : : <math>A = A + B \times \text{coefficient A}</math> : <math>B = B + A \times \text{coefficient B}</math> Retenez bien que cette opération s'appelle l'opération ''butterfly'', car les DSPs intègrent des optimisations dédiées pour cette opération. ===Les contraintes dites ''temps réel''=== Le DSP exécute l'algorithme de traitement de signal entre deux arrivées d'échantillon. Précisément, le DSP est commandé par une interruption. Lorsqu'un nouvel échantillon est disponible, le CAN envoie une interruption au DSP pour le prévenir. Le DSP lit alors l'entrée correspondant au CAN et récupère cet échantillon dans un registre. Il met alors à jour la file des échantillons, met à jour le pointeur qui indique le début de la file. Puis il exécute l'algorithme de traitement de signal. Une fois terminé, il envoie le résultat au CNA. Il y a donc un délai temporel très strict à respecter : le traitement doit être fini avant l'arrivée du prochain échantillon. Cette contrainte dite ''temps réel'' font qu'il est préférable de ne pas utiliser de mémoire virtuelle, d'interruptions, ou beaucoup d'autres fonctionnalités courantes sur les processeurs modernes. Par exemple, les branchements sont une source de problèmes pour le ''temps réel''. Le temps d'exécution du code change selon que le branchement est pris ou non, les deux codes exécutés suivant que la condition est valide ou non ne faisaient pas forcément le même temps. En conséquence, les DSP incorporent des instructions à prédicats pour remplacer les branchements hors-boucles, et ajoutent des techniques pour accélérer les boucles. La présence de caches est une autre source de problèmes dans les systèmes ''temps réel'', car le temps d'exécution dépend de si les accès mémoire font des succès ou des défauts de cache. En conséquence, les premiers DSP commercialisés n'utilisaient pas de mémoire cache pour les données, et se limitent à des caches d'instructions. L'absence de cache est compensée l'usage de ''local store'', dans lesquels des échantillons sont accumulés. Les ''local store'' sont souvent alimentés par des transferts DMA, qui font des copies ''local store'' vers mémoire RAM ou inversement. Les ''local store'' ne posent pas de problèmes pour le temps réel, car le programmeur sait à tout moment quelles sont les données présentes dans un ''local store'', ce qui n'est pas le cas dans un cache. De même, beaucoup d'optimisations posent problème avec le temps réel, parce qu'elles rendent le temps d'exécution plus variable. L'usage d'un pipeline est parfaitement possible, mais sous certaines conditions. La plus importante est qu'il faut utiliser l'émission dans l'ordre. Pas question d'utiliser d'exécution dans le désordre, de prédiction de branchement ou toute autre optimisation du genre. Dans les faits, presque tous les DSP commercialisés après les années 90 utilisent un pipeline. L'usage de l'émission multiple est parfaitement possible, et de nombreux DSP récents sont soit superscalaires, soit des CPU VLIW. La seconde solution est plus souvent utilisée, la compatibilité matérielle n'étant pas importante sur les DSPs. ==Le jeu d'instruction d'un DSP== Les DSPs incorporent de nombreuses optimisations spécifiques, pour optimiser les algorithmes de traitement de signal. Et ces optimisations peuvent se comprendre assez facilement quand on analyse le code d'un filtre FIR. Pour rappel, il s'agit du code assembleur vu plus haut, que je reproduis ici : <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> Il est intéressant d'étudier comment la boucle précédente peut être optimisée, avec un jeu d'instruction adapté, car ces optimisations se généralisent à tous les algorithmes de traitement de signal. Optimiser la boucle précédente demande d'optimiser plusieurs points : optimiser les calculs d'adresse, optimiser les lectures, optimiser les calculs arithmétiques, optimiser la boucle elle-même (les trois instructions de fin). Les DSPs incorporent des optimisations pour chaque point, voyons lesquelles. ===L'optimisation des boucles sur un DSP=== Premièrement, on doit réduire le temps passé dans les tests et branchements au minimum. Sans optimisations particulières, il faut incrémenter l'indice, faire la comparaison, et le branchement conditionnel. L'intérieur de la boucle consiste en deux lectures, une addition et une multiplication, soit quatre instructions. Si on fait les comptes, un peu moins de la moitié des instructions est passé à gérer la boucle FOR. Et de nombreuses optimisations visent à réduire grandement les couts liés à la boucle FOR. En premier lieu, le nombre de répétitions restantes est mémorisé dans un '''registre compteur de boucle'''. Il est initialisé avant de la boucle FOR, et il est décrémenté à chaque itération. La boucle se termine quand ce registre atteint zéro. En soit, le registre compteur de boucle n'est pas une optimisation, il ne permet pas de gagner des cycles d'horloge. Par contre, sa présence permet d'implémenter des optimisations, qu'on va détailler dans ce qui suit. Première optimisation : les DSP ont des instructions qui effectuent un test, un branchement et une décrémentation du registre compteur de boucles. L'instruction fusionne donc un test et un branchement, comme c'est le cas sur certains processeurs RISC ou CISC, mais avec une petite subtilité. Le test et le branchement sont adaptés pour tenir compte du registre compteur de boucle. Le test en question vérifie si ce compteur de boucle vaut zéro et effectue un branchement si ce n'est pas le cas. De plus, la mise à jour du registre compteur de boucle est elle aussi réalisée automatiquement. On économise donc une décrémentation. Ils incorporent aussi des techniques de '''''zero overhead looping''''', qui permet d'exécuter des boucles sans avoir à utiliser de branchements, ou presque. Pour rappel, celles-ci utilisent une instruction REPEAT, qui précise que les N instructions suivantes doivent s'exécuter en boucle, M fois. Typiquement, elles permettent d'implémenter des boucles FOR dont le nombre d’exécution est connu à l'avance. L'instruction REPAET/LOOP utilise le registre compteur de boucle pour savoir combie d'itérations il lui reste. Une variante précise deux adresses, qui délimitent les instructions de la boucle : une adresse pour le début de la boucle, une adresse pour la fin. L'implémentation hardware est alors assez simple : quand le ''program counter'' atteint l'adresse de fin, il est réinitialisé à l'adresse de début. Avec ces techniques, le code ASM d'un filtre FIR devient ceci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 </syntaxhighlight> Autre fonctionnalité : les '''instructions autorépétées''', des instructions qui se répètent automatiquement tant qu'une certaine condition n'est pas remplie. L'instruction effectue le test, le branchement, et l’exécution de l'instruction proprement dite en un cycle d'horloge. Cela permet de gérer des boucles dont le corps se limite à une seule instruction. Cette fonctionnalité a parfois été améliorée en permettant d'effectuer cette répétition sur des suites d'instructions. Les DSPs incorporent aussi des caches d'instructions, afin de gagner de précieux cycles d'horloge. En général, les caches d'instructions en question sont spécialisés dans l'exécution de petites boucles, qui tiennent entièrement dans le cache. ===Les opérations arithmétiques d'un DSP=== Voyons maintenant quelles optimisations peuvent être réalisées pour les opérations arithmétiques. Le calcul à faire est en soi très simple : une multiplication suivie d'une addition. Aussi, vous ne serez pas étonnés d'apprendre que tous les DSP supportent les instructions ''Multiply and Add'' (MAD), qui effectuent une multiplication suivie d'une addition. Pour rappel, la première travaille sur des opérandes entiers, la seconde des opérandes flottants. Utiliser une instruction MAD simplifie donc la boucle, sans compter que cela fait économiser un registre, vu qu'on n'a pas besoin de stocker le résultat de la multiplication. Et non seulement les DSPs intègrent une instruction MAD, mais ils ont aussi une unité de calcul dédiée à cette opération. Un autre point important est que l'addition sert juste à ajouter le produit à une variable temporaire. A chaque itération de la boucle, la variable est incrémentée avec le produit a*b. Il s'agit d'un calcul d'accumulation, qui se marie très bien avec la présence d'un registre accumulateur. Les DSPs incorporent donc un registre accumulateur dans l'unité de calcul MAD, ce qui en fait des architectures à accumulateur. Les instructions MAD lisent un opérande depuis l'accumulateur et mémorisent leur résultat dedans. Il s'agit donc d'instructions MAD un peu spéciales, appelées ''multiply and accumulate'' (MAC) ou ''fused multiply and accumulate'' (FMAC). Nous parlerons d'instructions MAC dans ce qui suit. [[File:Instruction MAD avec accumulateur d'un DSP 01.png|centre|vignette|upright=2|Instruction MAD avec accumulateur d'un DSP]] Avec l'usage d'une instruction MAC, le code d'un filtre FIR devient celui-ci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MAC RO , R1 </syntaxhighlight> De nombreux DSPs utilisent deux accumulateurs, pour accélérer l'opération ''butterfly'' des transformées de Fourier rapides. Mieux que ça : ils intègrent une instruction de multiplication complexe qui effectuent deux opérations MAC, sur les deux accumulateurs, en une seule instruction. Les instructions MAC n'ont besoin d'adresser que deux opérandes : celles de la multiplication. L'opérande de l'addition est dans un accumulateur adressé implicitement. Du moins, s'il y a un seul accumulateur. De nombreux DSPs ont entre 2 et 8 accumulateurs, même si la norme est à 2 accumulateurs. Dans ce cas, les accumulateurs étant séparés des autres registres, son adressage est un peu particulier. Les accumulateurs ont des numéros séparés des autres numéros/noms de registres. {|class="wikitable" |+ Encodage d'une instruction MAC |- ! Opcode !! Premier opérande !! Second opérande !! Opérande addition/résultat |- | Opcode || Numéro de registre ou adresse mémoire || Numéro de registre ou adresse mémoire || Numéro d'accumulateur |- | Un octet, environ || Variable || Variable || 1 à 3 bits, selon le nombre d'accumulateurs |} ===Les modes d'adressage d'un DSP=== Une autre source d'optimisation est liée aux calculs d'adresse. Les échantillons ne sont pas stockés dans un tableau, mais dans une file. La différence n'est pas énorme, car les files sont souvent implémentées par des tableaux, associés à deux pointeurs : un qui donne la position de la donnée la plus ancienne, un autre pour la donnée la plus récente. [[File:Fonctionnement d'une file - 1.png|centre|vignette|upright=2|Fonctionnement d'une file.]] Le tableau commence à être rempli à partir de sa première case, d'indice 0. Les données accumulées ensuite sont ajoutées dans la case d'indice 12, puis 2, puis 3, etc. Les données devenues inutiles sont retirées de la FIFO, ce qui laisse des vides, qui peuvent être réutilisées par la suite. Quand on arrive à la fin du tableau, le remplissage recommence à partir du début du tableau, si des espaces vides ont été libérés. Voici un exemple : {| |- |[[File:Circular buffer - XX123XX with pointers.svg|vignette|upright=1.5|Circular buffer - XX123XX with pointers]] |- |[[File:Circular buffer - XX1234X with pointers.svg|vignette|upright=1.5|Circular buffer - XX1234X with pointers]] |- |[[File:Circular buffer - XXX234X with pointers.svg|vignette|upright=1.5|Circular buffer - XXX234X with pointers]] |- |[[File:Circular buffer - XXX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - XXX2345 with pointers]] |- |[[File:Circular buffer - 6XX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6XX2345 with pointers]] |- |[[File:Circular buffer - 67X2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 67X2345 with pointers]] |- |[[File:Circular buffer - 6782345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6782345 with pointers]] |} Les DSP tendent à utiliser des files de taille fixe, ce qui fait que le remplissage ne s'arrête pas quand la file est pleine. À la place, le nouvel échantillon remplace l'échantillon le plus ancien. Il n'y a donc pas vraiment besoin d'utiliser deux pointeurs, car on est certain que la file sera pleine en permanence et que ce remplacement se fera sans douleur. Une file sur un DSP s'implémente donc en utilisant trois pointeurs : un pour l'adresse de départ du tableau en mémoire, un autre pour l'adresse de fin du tableau, et un pointeur qui pointe vers la donnée la plus ancienne/récente. [[File:Circular buffer - 6789AB5 full.svg|centre|vignette|upright=2|File telle qu'utilisée sur un DSP.]] En clair, les files sont des tableaux dans lesquels la position des échantillons est décalée. La différence est mineure, mais elle fait que des calculs d'adresse sont requis pour déterminer à quel indice lire dans le tableau. Pour éviter cela, les DSPs intègrent des modes d'adressage spécialisés, conçus pour fonctionner au mieux avec les files mentionnées plus haut. Déjà, les files sont implémentées avec des tableaux, ce qui fait que les modes d'adressages indicés sont une nécessité absolue. Déjà, les DSP supportent l'adressage "Base + Indice", qui permet de grandement simplifier les calculs d'adresse pour une file. L'adresse de base utilisée n'est pas l'adresse de base du tableau, mais celle de la donnée la plus récente ou la plus ancienne. L'idée est que l'échantillon le plus récent est celui d'indice zéro, le précédent celui d'indice 1, celui encore précédent est d'indice 2, etc. Les DSPs anciens/basiques étant des architectures à accumulateur, ils incorporent pour cela des '''registres d'indice''', et éventuellement des '''registres d'adresse''' pour mémoriser l'adresse de base. Une autre optimisation est l'usage de modes d'adressage avec post- ou pré-incrément/décrément. L'idée est que la lecture met à jour automatiquement l'indice utilisé, afin d'économiser une instruction d'incrémentation ou une addition. La lecture qui lit un opérande en mémoire RAM incrémente alors automatiquement l'indice utilisé dans l'adressage "Base + Indice". Cependant, faire ainsi pose un petit problème : que faire quand on atteint la fin du tableau ? En théorie, on devrait reprendre au tout début du tableau. Mais l'adressage "Base + Indice" ne permet pas de faire cela automatiquement. Sans optimisations, on devrait faire un test et un branchement avant chaque lecture, pour gérer ce cas. Mais les DSPs incorporent un mode d'adressage spécialisé, qui permet de gérer automatiquement ce cas problématique, directement dans la lecture elle-même ! Il s'agit du '''mode d'adressage « modulo »'''. Si lors d'une incrémentation, on dépasse l'adresse de fin du tableau, l'adresse est réinitialisée pour pointer sur l'adresse de début du tableau. Il garantit que l'adresse reste dans la file et n'en déborde pas. Suivant les DSP, le mode d'adressage modulo est géré différemment. La méthode la plus évidente utilise deux registres : un pour stocker l'adresse de début du tableau et un autre pour l'adresse de fin. Une solution alternative n'utilise pas l'adresse de fin, mais la taille/longueur du tableau. Cette dernière se marie bien avec des registres d'indices : la longueur du tableau est comparée avec l'indice courant, pour vérifier si l'adresse dépasse la fin du tableau. Une seconde méthode utilise un registre « modulo », qui stocke la taille du tableau. Il est associé à un registre d'adresse pour l'adresse/indice de l’élément en cours. Vu que seule la taille du tableau est mémorisée, le processeur ne sait pas quelle est l'adresse de début du tableau, et doit donc ruser. La ruse ne fonctionne que pour des files/tableaux de petite taille. L'adresse est alors alignée sur un multiple de 64, 128, ou 256 octets. Cela permet ainsi de déduire l'adresse de début de la file : c'est le multiple de 64, 128, 256 strictement inférieur le plus proche de l'adresse manipulée. Un DSP a souvent plusieurs copies de chaque registre d'adresse/indice. La raison est que cela permet de gérer plusieurs files. Il faut dire qu'un DSP exécute souvent plusieurs algorithmes de traitement de signal à la suite. Par exemple, il est possible d'avoir un filtre FIR suivi d'un filtre d'antialiasing, suivi d'un algorithme de ''Fast Fourier Transform'', et ainsi de suite. Certains de ces algorithmes, comme la ''Fast Fourier Transform'', se font en plusieurs étapes enchainées les unes à la suite des autres. Et chaque étape a son propre ensemble d'échantillons, donc sa propre file. Et le DSP peut gérer ces différentes files nativement. Le mode d'adressage modulo semble assez spécialisé, mais sachez que les DSPs supportent des modes d'adressages encore plus spécialisés, utilisables seulement par un ou deux algorithmes triés sur le volet ! L''''adressage à bits inversés''' (''bit-reverse'') a été inventé pour accélérer les algorithmes de calcul de transformée de Fourier rapide, un « calcul » très courant en traitement du signal. Cet algorithme lit des échantillons dans un tableau, et fournit des résultats dans un autre tableau. Seul problème, l'ordre des résultats dans le tableau d'arrivée est assez spécial. Par exemple, pour un tableau de 8 cases, les données arrivent dans cet ordre : 0, 4, 2, 6, 1, 5, 3, 7. L'ordre semble être totalement aléatoire. Mais il n'en est rien : regardons ces nombres une fois écrits en binaire, et comparons-les à l'ordre normal : 0, 1, 2, 3, 4, 5, 6, 7. {|class="wikitable" |- !Ordre normal!!Ordre Fourier |- ||000||000 |- ||001||100 |- ||010||010 |- ||011||110 |- ||100||001 |- ||101||101 |- ||110||011 |- ||111||111 |} Comme vous le voyez, les bits de l'adresse Fourier sont inversés comparés aux bits de l'adresse normale. Inverser les bits d'une adresse peut être fait avec des opérations bit à bit, des décalages et rotations, mais cela prendrait beaucoup d'instructions. Il est possible d'imaginer une instruction REVERSE qui inverse les bits d'une adresse. Ce serait là une solution fort intéressante, que certains DSPs doivent sans doute implémenter. Mais beaucoup de DSPs préfèrent utiliser un mode d’adressage qui inverse tout ou partie des bits d'une adresse mémoire : l'adressage ''bit-reverse'' mentionné plus haut. Une autre solution utilise un adressage indicé, mais qui calcule les adresses différemment. Il suffit, lorsqu'on ajoute un indice à l'adresse, de renverser la direction de propagation de la retenue lors de l'addition. Certains DSP disposent d'instructions pour faire ce genre de calculs. ==L'architecture mémoire d'un DSP== Les DSPs ont une architecture mémoire particulière. Par architecture mémoire, je veux dire par là que leur hiérarchie mémoire est particulière. Déjà, ils n'ont généralement pas de caches de données, car celui-ci n'est pas compatible avec le temps réel. Par contre, ils tendent à compenser en utilisant des ''local store''. Si un DSP ne possède généralement pas de cache pour les données, il a parfois un cache d'instructions pour accélérer l'exécution des boucles. ===L'usage de registres spécialisés=== Les DSPs se passent de registres généraux, car les algorithmes de traitement de signal n'en ont pas besoin. Vous remarquerez que le code d'un filtre FIR n'utilise pas beaucoup de registres, et ce d'autant plus si on utilise des instructions MAD et un registre accumulateur. Et cela se généralise aux autres algorithmes de traitement de signal. Mais surtout, les conditions pour utiliser des registres ne sont pas réunies. Pour rappel, les registres servent dans deux situations. La première est quand un opérande est lu par plusieurs instructions différentes. Dans ce cas, mieux vaut copier l'opérande dans un registre, au lieu de la relire plusieurs fois en mémoire RAM. La première utilisation a un cout, mais les suivantes sont amorties. Mais les algorithmes de traitement de signal ne réutilisent pas leurs opérandes. Quand un opérande est chargé depuis la mémoire RAM, elle sera utilisée une seule fois. Un autre usage des registres est lié aux résultats des instructions. En général, le résultat d'une instruction est utilisé comme opérande par d'autres instructions, au moins une. Ainsi, il vaut mieux enregistrer ce résultat dans un registre, histoire que sa lecture en tant qu'opérande se fasse rapidement. Mais sur les DSPs, ce transfert à l'instruction suivante est le fait du registre accumulateur ! A lui seul, il prend en charge cette réutilisation des résultats. A la rigueur, pour certains algorithmes, un seul accumulateur n'est pas suffisant. Mais en utiliser 2 ou 3 accumulateurs suffit généralement à résoudre totalement ce problème. Cependant, il y a plusieurs situations qui mériteraient d'utiliser des registres : les calculs d'adresse, ainsi que les compteurs de boucle. Mais pour ces deux cas, les DSPs préfèrent utiliser des registres spécialisés. Ils intègrent ainsi des registres pour les adresses, reliés à une unité de calcul d'adresse dédiée. Idem pour les compteurs de boucle, qui ont des registres dédiés, afin de simplifier l'implémentation du ''zero-overhead looping''. Les registres d'un DSP ne correspondent donc à rien de familier à ce stade du cours, ils sont vraiment à part du reste. Cette spécialisation des registres a de nombreuses conséquences. Certaines instructions ne sont utilisables que sur certains types de registres, et il en est de même pour les modes d'adressage. Certaines instructions d'accès mémoire peuvent prendre comme destination ou comme opérande un nombre limité de registres, les autres leur étant interdits. Cela permet de diminuer le nombre de bits nécessaire pour encoder l'instruction en binaire. Mais cette spécialisation des registres pose de nombreux problèmes pour les compilateurs, qui ont du mal à utiliser correctement les modes d'adressages spécialisés, ainsi qu'à utiliser correctement les registres. Il n'est pas étonnant que les DSP aient longtemps été programmés en assembleur, et il n'est pas rare qu'ils le soient toujours. Par contre, l'usage de registres spécialisés permet des optimisations très importantes. Les DSPs modernes sont capables de faire deux calculs d'adresse, une opération MAC, et un branchement de boucle en un seul cycle d'horloge. Le branchement est réalisé via ''zero overhead looping'', les calculs d'adresse le sont via les modes d'adressage adéquats. Si l'indice de boucle, les adresses et opérandes étaient dans un banc de registre unique, alors celui-ci devrait avoir entre 5 et 10 de ports de lecture. En utilisant des bancs registres séparés, on peut se débrouiller avec seulement deux ports de lecture par banc de registre, voire moins : deux ports de lecture pour les registres d'opérandes, un registre d'indice de boucle séparé, deux-trois ports de lecture pour le banc de registre pour les adresses, etc. ===La lecture des opérandes pour l'instruction MAC=== Le reste de l'architecture mémoire d'un DSP est assez bizarre : ils utilisent des architectures Harvard, sont reliés à des mémoires multiports, n'ont pas de registres généraux, et j'en passe. Ces particularités visent à exécuter des instructions MAC rapidement. En théorie, les instructions utilisant un accumulateur sont de type ''load-op'' : un opérande est lu depuis l'accumulateur, l'autre depuis la mémoire RAM. Mais autant cela marche bien pour des instructions à deux opérandes, autant il y a un problème pour les instructions MAC. Vu que ce sont des instructions triadiques, il faut lire les deux opérandes de la multiplication depuis la mémoire RAM. Et ce n'est pas possible avec une architecture classique. La solution la plus simple lit les deux opérandes un par un, depuis la mémoire RAM. Il s'agit d'une solution assez générale, qui marche aussi pour d'autres algorithmes que les filtres FIR. Et cela demande d'adapter le processeur pour gérer la situation. La première solution ajoute un registre pour mémoriser un des opérandes de la multiplication, situé juste avant l'unité de calcul MAC, que nous nommerons le '''registre T'''. Le registre T est adressé implicitement, tout comme l'accumulateur. Une instruction MAC a juste besoin de connaitre l'adresse de la seconde opérande. Cette solution a beaucoup été utilisée sur les tout premiers DSP, notamment ceux de la marque Texas Instrument. Elle est de moins en moins utilisée de nos jours. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois LOAD RA0 ; // copie dans le registre T, instruction avec mode d'adressage en post-incrément MAC RA1 // instruction avec mode d'adressage en post-incrément </syntaxhighlight> [[File:Implémentation de l'instruction MAC avec un registre d'opérande.png|centre|vignette|upright=2|Implémentation de l'instruction MAC avec un registre d'opérande]] Une solution plus élaborée ne se contente pas d'ajouter un seul registre T, mais plusieurs registres pour les opérandes. Quelques DSPs utilisent cette solution, même s'ils sont assez minoritaires. Les DSPs avec des registres pour les opérandes se débrouillent donc avec moins d'une dizaine de registres, généralement 2 ou 4. La raison à cela est que les algorithmes de traitement de signal n'ont pas besoin de plus, comme on l'a dit plus haut. Il est possible de transférer les données de l'accumulateur vers ces registres d'opérandes, mais cela ne sert pas très souvent. De plus, cela demande de faire un arrondi, car les registres sont plus petits que l'accumulateur. La majorité des DSPs n'utilise pas les deux solutions précédentes. A la place, ils préfèrent se passer de registres pour les opérandes. Les deux opérandes sont lus directement dans la mémoire RAM, en même temps ! En clair, les instructions des DSPs peuvent faire plusieurs accès mémoire simultanés. L'instruction MAC est alors une pure instruction ''load-op'', mais adaptée à l'usage de trois opérandes. En utilisant les modes d'adressage adéquats, l'instruction MAC fait tout : elle calcule les adresses modulo, lit des opérandes depuis la mémoire RAM/ROM, puis fait l'opération MAC. Avec cette solution, le code d'un filtre FIR devient le suivant. Vous remarquerez qu'il se résume à une instruction MAC et une instruction de ''zero overhead looping''. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAD RA0 , RA1 </syntaxhighlight> La mémoire RAM doit être adaptée pour faire plusieurs accès mémoire par cycle, ce qui implique d'utiliser une mémoire multiport, pour gérer nativement plusieurs accès par cycle. Cette solution a l'avantage de fonctionner pour d'autres algorithmes que les filtres FIR, et est en quelque sorte plus générale. Les deux solutions peuvent être utilisées en même temps. Par exemple, le DSP TMS320-C54x incorpore deux ''local store'' : un ''local store'' double port pour les opérandes, un deuxième pour écrire les résultats. [[File:Architecture mémoire des DSP.png|centre|vignette|upright=2|Architecture mémoire des DSP.]] Une autre solution, qui marche parfaitement pour les filtres FIR, utilise deux mémoires séparées : une qui contient les échantillons, une autre pour les coefficients. Les deux RAMs peuvent être accédées en parallèle, ce qui permet de charger les deux opérandes d'une multiplication en même temps. La mémoire pour les coefficients peut-être une mémoire ROM dédiée, et pas une mémoire RAM. Utiliser une RAM pour les coefficients est utile si le filtre change au cours du temps, mais une ROM suffit si elle peut mémoriser tous les coefficients nécessaires. [[File:Architecture mémoire des DSP avec deux mémoires séparées.png|centre|vignette|upright=2|Architecture mémoire des DSP avec deux mémoires séparées]] ===L'usage d'une architecture Harvard modifiée=== Les solutions précédentes peuvent être améliorées, voire combinées, en utilisant une architecture Harvard modifiée. Pour rappel, une architecture Harvard permet de lire des constantes depuis la mémoire ROM. L'idée est que les coefficients d'un filtre FIR sont chargées depuis la mémoire ROM, et non la mémoire RAM. Et quand je dis la ROM, c'est sous-entendu : celle qui contient aussi le programme à exécuter. La solution est praticable, car les algorithmes de traitement de signal sont assez courts et utilisent assez peu de coefficients (moins d'un millier), ce qui fait que le programme et les coefficients rentrent tous deux dans la mémoire ROM. Elle est utilisée sur les DSPs sans pipeline, ou avec. Elle donne cependant des gains en performance immédiats sur les DSPs sans pipeline. Mais surtout, elle permet d'éliminer le besoin d'avoir une mémoire multiport. Ainsi, pour une instruction MAC d'un filtre FIR, un opérande est lu depuis la ROM, la seconde opérande est lue depuis la mémoire RAM, la troisième est lue depuis l'accumulateur, et le résultat est mémorisé dans l'accumulateur. Au final, on fait bien un seul accès en mémoire RAM par instruction MAC. Le chargement des deux opérandes est intégré dans l'instruction MAC, avec les modes d'adressage adéquats. Typiquement, le DSP incorpore des registres d'adresse séparés pour la ROM et pour la RAM, avec des unités de calcul d'adresse séparées. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAC RA-ROM , RA-RAM // RA-ROM est le registre d'adresse pour la ROM, RA-RAM celui pour la RAM </syntaxhighlight> Utiliser une architecture Harvard modifiée fonctionne bien pour implémenter des filtres FIR et de nombreux algorithmes de traitement de signal, mais elle est peu flexible. Avec cette solution, un des opérandes doit être constant et placé en ROM. Si jamais on souhaite utiliser une donnée variable, cette solution ne marche plus. Mais cela ne signifie pas que l'implémentation est impossible. Il suffit de rajouter le registre T ou les registres d'opérande vus plus haut, pour compenser. [[File:Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.png|centre|vignette|upright=2|Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.]] ===Le contrôleur DMA intégré à un DSP=== Un point important est que les écritures dans le ''local store'' ou la RAM ne passe pas par le DSP, histoire de lui économiser du travail. Les échantillons sont écrits dans le ''local store'' ou la RAM en utilisant le ''Direct Memory Access''. Le DSP contient pour cela un contrôleur DMA, qui transfère les échantillons nécessaires du convertisseur analogique-numérique, vers la mémoire RAM et/ou le ''local store''. Il faut absolument éviter que le DSP et le contrôleur DMA se marchent sur les pieds. Pas question qu'ils accèdent en même temps à la mémoire RAM ou au ''local store''. Et il faut éviter absolument que le contrôleur DMA monopolise la RAM et laisse le DSP patienter trop longtemps, idem pour le cas inverse. La majorité des DSPs intègre des techniques d'arbitrage du bus mémoire assez complexes. Une solution alternative, elle aussi très utilisée, dédie un port mémoire au contrôleur DMA. Le contrôleur DMA accède à la RAM via son propre port mémoire dédié, en même temps que le processeur, les deux peuvent faire un accès mémoire en même temps. Plus besoin d'arbitrer le bus mémoire. [[File:DSP avec controleur DMA.png|centre|vignette|upright=2.5|DSP avec contrôleur DMA.]] ==L'instruction MAC et l'unité de calcul associée== Les DSP intègrent une unité de calcul dédiée pour l'instruction MAC. Elle contient un multiplieur, un additionneur, et un accumulateur, ainsi que d'autres circuits. Cette unité de calcul devrait en théorie être abordée dans une section sur la microarchitecture d'un DSP. Cependant, de nombreux détails de cette unité de calcul sont exposés au programmeur. Notamment, l'accumulateur a quelques particularités qui sont spécifiques au traitement de signal, que le programmeur voit. Voyons lesquelles. ===Les accumulateurs larges et leurs ''Guard Bits''=== Les DSPs ont des besoins en termes de précision plus importants que sur un ordinateur classique. Il n'est pas acceptable de perdre en qualité d'image ou sonore, parce que le processeur a fait un arrondi un peu trop visible. Et ces arrondis ou troncatures sont très fréquents avec des registres généraux, alors qu'on peut les éviter avec des accumulateurs. Voyons comment. Pour rappel, les multiplications donnent un résultat deux fois plus grand que leurs opérandes. Multipliez deux opérandes de 16 bits, le résultat en fera 32. Sur un ordinateur normal, les résultats sont tronqués pour rentrer dans les registres généraux. Par exemple, sur un processeur 32 bits, le résultat d'une multiplication est tronqué, on ne garde que les 32 bits de poids faible, en espérant qu'aucun débordement n'aura lieu. A la rigueur, certains processeurs permettent d'utiliser deux registres de 32 bits : un pour les 32 bits de poids faible du résultat, un autre pour les 32 bits de poids fort. Mais c'est assez rare. À l'opposé, les DSPs utilisent des accumulateurs de grande taille capables de mémoriser le résultat complet d'une multiplication. Il faut noter que le problème a aussi lieu pour l'addition, après la multiplication. Pour une addition, le résultat fera un bit de plus que les opérandes : additionnez deux opérandes de 32 bits, le résultat en fera 33. Vu que le DSP effectue une série d'additions consécutives, le résultat final aura facilement une dizaine de bits en plus, parfois plus, le nombre exact dépendant des opérandes et du nombre d'itérations de la boucle. Pour éviter les débordements d'entiers liés à l'addition, les accumulateurs contiennent souvent 4 à 8 bits de plus que le résultat de la multiplication. Les bits supplémentaires sont appelés des '''''guard bits'''''. Pour donner un exemple, les DSPs de 24 bits ont souvent des accumulateurs de 56 bits : 48 bits pour le résultat de la multiplication, plus 8 ''guard bits''. [[File:Instruction MAD avec accumulateur d'un DSP, avec guard bits.png|centre|vignette|upright=2|Chemin de données d'un DSP, avec guard bits et produit long]] La présence de ''Guard bits'' fait que la gestion des débordements d'entier est fort différente sur les DSPs, comparé aux autres processeurs. De fait, les DSP utilisent souvent l'arithmétique saturée, car c'est assez naturel quand on manipule un signal qui peut... saturer ! Quand un signal sonore sature, cela veut dire que l'intensité sonore dépasse le maximum représentable. En clair, l'intensité sonore dépasse le maximum encodable avec un entier/flottant, il y a un débordement entier/flottant. Si on traitait ce débordement en ne conservant que les bits de poids faible du résultat, un son qui sature donnerait un son très faible, ce qui n'est pas le comportement attendu. Il est plus naturel de mettre le son à la valeur maximale représentable. Les DSP les plus simples n'utilisent que l'arithmétique saturé, mais d'autres plus complexes permettent de configurer si on utilise l'arithmétique saturée ou non. Certains permettent d'activer et de désactiver l'arithmétique saturée, en modifiant un registre de configuration du processeur. D'autres fournissent chaque instruction de calcul en double : une en arithmétique modulaire, l'autre en arithmétique saturée. ===Le décaleur pour les arrondis=== L'accumulateur a donc une taille bien plus grande de celle des opérandes. Typiquement, les opérandes sont soit lues depuis la mémoire RAM, soit depuis des registres pour les opérandes. Dans les deux cas, l'accumulateur est plus large que les registres ou le bus de données. Lorsque les données quittent l'accumulateur, elles doivent donc être tronquées pour rentrer dans l'adresse/registre de destination. Pour cela, l'accumulateur est suivi par un ''barrel shifter'', qui décale le résultat pour éliminer les bits en trop. [[File:Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.png|centre|vignette|upright=2|Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.]] Le décaleur peut aussi prendre en charge d'arithmétique saturée. L'idée est que les circuits qui s'occupent de saturer les résultats sont intégrés avec le décaleur. Ces circuits regardent les ''guard bit'' sortant de l'accumulateur et modifient le résultat en fonction de ceux-ci. Si aucun ''guard bit'' n'est à zéro, alors il n'y a pas eu débordement d'entier et le décaleur fait son travail normalement. Mais si un seul ''guard bit'' est à 1, c'est signe qu'un débordement d'entier a eu lieu. Le résultat est alors remplacé par la valeur maximale supportée par le DSP (en dehors de l'accumulateur). Un DSP contient souvent une unité MAC, une ALU entière, et un décaleur séparé. Un DSP doit en effet implémenter les instructions usuelles, sur des opérandes entiers. Et cela ne concerne pas que les additions/soustractions ou les opérations logiques : les décalages/rotations sont aussi de la partie. Les DSPs intègrent donc un ''barrel shifter'', qui est séparé de l'unité MAC. Et c'est une source d'optimisation : le décaleur pour les arrondis est parfois fusionné avec le ''bareel shifter'', pour économiser des circuits. En clair, le décaleur des arrondis est sorti de l'unité MAC et est une unité de calcul comme une autre. Mais ce n'est pas systématique et de nombreux DSPs préfèrent utiliser un mini-décaleur séparé du ''barel shifter'', pour des raisons de performance. ===L'implémentation matérielle de l'unité de calcul MAC=== [[File:Chemin de données d'un DSP.png|vignette|upright=1|Chemin de données d'un DSP, avec multiplieur et additionneur séparé.]] L'implémentation d'un circuit MAC pour opérandes entiers est très simple, car on peut fusionner l'additionneur et le multiplieur en un seul circuit. Rien de surprenant, nous savons qu'un multiplieur contient un additionneur multiopérande, on peut lui ajouter de quoi faire une addition entière en plus. Cependant, la plupart des DSPs préfèrent utiliser un multiplieur séparé de l'additionneur, avec un registre entre les deux. Le registre en sortie du multiplieur a une taille deux fois plus grande que les opérandes, pour mémoriser le résultat complet de la multiplication. Pour un DSP qui manipule des opérandes de 24 bits, le registre pour les multiplications fera 48 bits, soit le double. Pour donner un exemple, les DSP Blackfin+ géraient des opérandes de 32 bits, avaient un registre de 64 bits pour le résultat de la multiplication, et utilisaient des accumulateurs de 72 bits. [[File:Chemin de données d'un DSP, avec guard bits et produit long.png|centre|vignette|upright=1.5|Chemin de données d'un DSP, avec guard bits et produit long]] Faire ainsi a plusieurs avantages. Le premier est que cela permet de pipeliner l'unité de calcul MAC. Pendant que l'additionneur traite une instruction MAC, le multiplieur s'occupe de l'instruction MAC suivante. Les DSPs avec un pipeline peuvent ainsi profiter d'une hausse de performance assez conséquente. Mais au-delà de l'usage d'un pipeline, d'autres optimisations sont rendues possibles. La première est que cela permet d'implémenter l'addition de manière assez simple. En effet, l'unité MAC peut parfois être modifiée de manière à supporter d'autres instructions que l’instruction MAC. Elles peuvent être utilisées pour faire des additions ou des multiplications seules. L'addition seule court-circuite le multiplieur, et envoie un opérande en entrée de l'additionneur. Pour cela, il faut intercaler un multiplexeur entre le multiplieur et l'additionneur. L'additionneur peut aussi être remplacé par une vraie unité de calcul entière, capable de faire des opérations bit à bit. [[File:Unité MAC modifiée de manière à supporter l'addition.png|centre|vignette|upright=2|Unité MAC modifiée de manière à supporter l'addition]] L'opérande de l'addition peut provenir de plusieurs endroits : soit d'un autre accumulateur, soit des registres d'opérandes, soit de la mémoire RAM. Si les deux opérandes sont dans deux accumulateurs, alors elles ont la même taille et sont envoyées en entrée de l'additionneur sans autre forme de procès. Mais si elles viennent des registres d'opérandes ou de la RAM, elles sont plus courtes que ce que prend en entrée l'accumulateur. Par exemple, prenons un DSP avec des opérandes 16 bits et un additionneur 40 bits. L'additionneur a une entrée reliée à l'accumulateur de 40 bits, l'autre entrée provient du multiplexeur et fait 32 bits. Un opérande de l'addition provient de l'accumulateur et fait 40 bits, l'autre est un opérande de 16 bits et doit être convertie en 32 bits. Pour cela, il y a plusieurs solutions. * La première utilise l'extension de signe, à savoir que l'opérande de 16 bits est étendue sur 32 de manière à conserver son signe. * La seconde envoie l'opérande dans les 16 bits de poids fort en entrée de l'additionneur, les 16 bits de poids faible sont mis à zéro. * Il est possible de concaténer deux registres d'opérande de 16 bits pour obtenir un opérande de 32 bits, soit la taille adéquate. ===Les unités MAC flottantes=== Précisons que tout ce qui vient d'être dit précédemment ne fonctionne que pour des opérandes entiers, pas pour des opérandes flottants. Pour les opérandes flottants, la question des arrondis est un peu différente. L'opération MAC est composée d'une multiplication flottante, suivie d'une addition flottante. La question est alors la suivante : est-ce qu'il y a un arrondi entre les deux, avec la normalisation et autres subtilités propres aux nombres flottants ? Pour gérer ce cas, il existe deux types d'instructions MAC : l'instruction MAC classique et l'instruction '''''Fused MAC''''' (FMAC). L'instruction MAC classique fait un arrondi entre les deux, l'instruction FMAC n'en fait pas. L'instruction donne des résultats plus précis, mais demande de travailler avec un résultat de multiplication plus grand de quelques bits, ce qui fait des circuits en plus. Les DSP se classent en deux sous-types : ceux qui utilisent des nombres flottants et ceux qui utilisent des nombres à virgule fixe. Les premiers DSPs utilisaient la virgule fixe. Le cas classique était des DSP utilisant des opérandes de 24 bits : 16 pour la partie entière, 8 pour la partie fractionnaire. Notons que 24 bits était la norme pour encoder de l'audio sur des CD audio, ce qui fait que les DSPs de l'époque utilisaient cette précision. Par la suite, des DSP 16 et 32 bits sont apparus, puis des DSP flottants. Les DSPs à virgule fixe disposent de mécanismes pour émuler des nombres flottants en utilisant des calculs entiers. Pour être plus précis, ils émulent des nombres flottants spéciaux, appelés '''nombres flottants par blocs''' (traduction du terme anglais ''block-floating point''). L'idée est de manipuler des nombres flottants qui ont tous le même exposant, afin de simplifier les calculs. Si plusieurs nombres flottants ont le même exposant, alors les additionner demande de simplement additionner les mantisses, les multiplier demande de multiplier les mantisses. Du moins, c'est le cas en absence de débordement d'entier, mais les DSPs ont des protections pour ça, comme les ''guard bits'' et les accumulateurs larges. Les DSPs émulent les calculs sur les flottants par blocs de la manière suivante. Les DSPs disposent d'une instruction EXP, qui calcule l'exposant et le mémorise dans un registre. Une fois l'exposant connu, ils normalisent les mantisses avec des décalages, de manière à ce que tous les opérandes aient le même exposant. Puis, ils additionnent ou multiplient les mantisses ensemble, avec des instructions MAC, MUL, ADD, SUB, DIV, etc. Une fois les calculs terminés, la mantisse du résultat est dans l'accumulateur. Elle est normalisée avec un décalage, réalisé par le ''barrel shifter'', en fonction de l'exposant calculé. La gestion des flottants par blocs peut être réalisée avec le décaleur vu plus haut, dans la section précédente. Les décalages nécessaires pour normaliser et décaler les mantisses sont réalisés par de décaleur. ===Des exemples d'unités MAC=== Le DSP TMS32010 de marque Texas Instrument disposait d'un additionneur et d'un multiplieur, couplés à trois registres : un registre accumulateur, le registre T pour un opérande, et le registre P entre le multiplieur et l'additionneur. [[File:Unité de calcul du DSP TMS32010 de marque Texas Instrument.png|centre|vignette|upright=2|Unité de calcul du DSP TMS32010 de marque Texas Instrument]] Le Motorola DSP 5600x avait deux accumulateurs, ainsi que 4 registres d'opérandes appelés X1, X2, Y1 et Y2. Les deux accumulateurs faisaient 56 bits. Les registres d'opérandes, quant à eux, pouvaient être utilisés de deux manières : soit comme 4 registres de 24 bits, soit comme 2 registres de 48 bits. L'unité MAC était capable de faire une opération MAC, une addition, ou une opération bit à bit. Pour cela, l'additionneur est précédé par une unité de calcul bit à bit, qui n'est pas utilisée quand le multiplieur l'est. En clair, l'unité bit à bit sert uniquement quand on charge les opérandes depuis les registres d'opérandes. L'additionneur est suivi par un circuit capable de faire des opérations de normalisation et d'arrondis. Le circuit intègre deux décaleurs. Le premier est situé en sortie de l'accumulateur, et permet de traduire un résultat de 56 bits en un résultat de 24 bits. Il sert aussi pour des arrondis, des opérations de normalisation et bien d'autres. L'autre décaleur est lui entre l'accumulateur et l'additionneur. Il est beaucoup plus limité et ne peut que faire quatre opérations : ne rien faire, un décalage à gauche de 1 rang, un décalage à droite de 1 rang, mettre à zéro sa sortie. L'unité MAC n'était pas pipelinée, elle faisait un calcul en un cycle. Par contre, il était possible de modifier les registres d'opérandes pendant qu'un calcul MAC était en cours. En entrée du multiplieur, il y avait deux registres non-adressabbles, qui mémorisaient les opérandes pendant un cycle d'horloge complet. Ainsi, il était possible d'écrire dans les registres d'entrée, sans pour autant que cela impacte le calcul en cours. [[File:Unité de calcul du Motorola DSP 5600x.png|centre|vignette|upright=2|Unité de calcul du Motorola DSP 5600x]] ==La microarchitecture d'un DSP== Il est intéressant de regarder comment la microarchitecture des DSPs a évoluée. Et c'est en lien avec l'évolution de leur jeu d'instruction. Les DSPs sont souvent classés en trois à cinq générations, mais les frontières entre générations varient beaucoup d'un livre à l'autre, d'un auteur à l'autre. Dans ce chapitre, nous allons juste séparer les DSPs en deux : les DSPs classiques, qu'on a détaillé plus haut, et les DSP récents qui intègrent des jeux d'instructions SIMD, VLIW ou superscalaires. Sur les anciens DSP, les instructions s'exécutaient toutes en un seul cycle d'horloge et tendaient à faire pas mal de traitements assez complexes. De nos jours, les DSPs tendent à utiliser un pipeline, ce qui fait que la contrainte "1 cycle = une instruction" est battue en brèche. ===La microarchitecture d'un DSP classique=== Un DSP contient au minimum une unité de calcul MAC avec un ''barrel shifter''. De nombreux DSPs incorporent aussi une ALU entière séparée du circuit MAC, qui est utilisée pour des additions/soustractions, opérations logiques et bit à bit. Le ''barrel shifter'' est lui utilisé pour tronquer le résultat en sortie de l'accumulateur, et pour gérer les nombres flottants par blocs, avec l'aide d'une unité dédiée aux exposants. Les DSPs intègrent des unités de calcul spécialisées dans les calculs d'adresse, qui sont regroupées avec les registres d'adresse et d'indice. Elles implémentent l'adressage modulo et bit-''reverse'', ainsi que les modes d'adressages à post- ou pré-incrément/décrément, et les modes d'adressage usuels. Il y a un banc de registre pour les registres d'adresse, un autre pour les registres d'indice, ainsi qu'une unité de calcul d'adresse spécialisée. Il y a en général deux unités de calcul d'adresse, une par opérande. [[File:Unité d'accès mémoire avec registres d'adresse ou d'indice.png|centre|vignette|upright=2|Unité d'accès mémoire avec registres d'adresse ou d'indice]] Un DSP avec un registre T est forcément connecté à une mémoire simple port. Sa microarchitecture est des plus simples. De tels DSP n'ont généralement pas d'ALU entière séparée de l'unité MAC, car ces opérations sont réalisées dans l'unité MAC elle-même. L'additionneur est remplacé par une ALU entière, un MUX permet de court-circuiter le multiplieur. Ses interconnexions sont particulièrement simples. : Nous omettrons les liaisons entre séquenceur et ALUs, utilisées pour les modes d'adressage immédiat (constantes immédiates). [[File:Microarchitecture d'un DSP avec un registre T.png|centre|vignette|upright=2|Microarchitecture d'un DSP avec un registre T]] Si on suppose au contraire que le DSP utilise une mémoire RAM multiport, on devrait avoir ceci : [[File:Microarchitecture d'un DSP avec mémoire multiport.png|centre|vignette|upright=3|Microarchitecture d'un DSP avec mémoire multiport.]] Si on suppose que le DSP utilise une architecture Harvard modifiée, et que les coefficients sont en mémoire ROM, l'intérieur du DSP devrait ressembler à ceci : [[File:Microarchitecture d'un DSP.png|centre|vignette|upright=3|Microarchitecture d'un DSP.]] ===Les DSPs avec optimisations pour l'opération ''butterfly''=== Les DSPs précédents n'incorporent pas d'optimisations pour l'opération ''butterfly''. En effet, celles-ci n'ont qu'un seul accumulateur, pas plus. Mais l'opération ''butterfly'' marche bien mieux avec deux accumulateurs. Aussi, de nombreux DSPs incorporent deux accumulateurs et quoi les utiliser au mieux. Dans le cas le plus simple, l'unité MAC est reliée à deux accumulateurs. Mais sur les '''DSPs ''Dual MAC''''', les deux accumulateurs sont couplés à deux unités MAC, avec une unité MAC par accumulateur. De tels DSPs peuvent faire deux opérations MAC par cycle d'horloge, souvent avec l'aide d'une instruction machine de multiplication/addition complexe. Pour donner un exemple, prenons le DSP TMS320-C54x, qui dispose de deux accumulateur, mais n'est pas un DSP ''dual MAC''. Il dispose de 6 unités de calcul : une unité MAC non-pipelinées, une ALU entière, un ''barrel shifter'', deux unités de calcul d'adresse, et une unité de comparaison spécialisée pour l'algorithme de Viterbi qu'on ne détaillera pas ici. L'ALU entière et le ''barrel shifter'' gèrent des opérandes de 40 bits, l'unité MAC gère des opérandes de 17 bits (16 bits, plus un bit de signe) et un résultat de 40 bits. Pour supporter des calculs flottants, le processeur incorpore un circuit dédié à la gestion des exposants, qui s'occupe des opérations de normalisation, d'arrondis et autres. Un détail important est que l'unité de calcul peut soit fonctionner comme une ALU unique de 40 bits, soit comme une ALU SIMD de 16 bits. Elle est capable de faire deux opérations sur deux opérandes de 16 bits en même temps. Pour le reste, les interconnexions entre ces unités de calcul sont très complexes. C'est presque comme si tout était connecté à avec tout le reste. Le DSP TMS320-C54x a deux accumulateurs, qui peuvent recevoir le résultat de l'unité MAC ou de l'ALU entière. Les deux accumulateurs envoient leur contenu en entrée de toutes les ALU, sauf les AGU. Le ''barrel shifter'' envoie son résultat soit en mémoire RAM, soit en entrée de l'ALU entière. Le TMS320-C54x dispose de trois bus de données, pour lire deux opérandes et écrire un résultat en un seul cycle d'horloge. Ils sont appelés CB, DB et EB, les deux bus CB et DB sont en lecture, le bus EB est un bus d'écriture. Les deux bus CB et DB envoient des opérandes à l'unité MAC, l'ALU entière et le ''barrel shifter''. Pour le bus EB des écritures, il n'est accesible qu'à travers le ''barrel shifter''. Ce qui est logique : lors de l'enregistrement en mémoire, un résultat de 40 bits doit être converti en donnée de 16 ou 32 bits, ce qui demande de faire un décalage pour éliminer les bits de poids faible. [[File:Chemin de données du TMS320C54x.png|centre|vignette|upright=2|Chemin de données du TMS320C54x]] ===Les DSPs VLIW, SIMD et superscalaires=== Les DSPs de seconde génération et au-delà, incorporent plusieurs unités de calcul MAC. De plus, celles-ci sont pipelinées pour augmenter le nombre d'opérations exécutées par cycle d'horloge. Pour les alimenter, le processeur dispose de trois méthodes : soit utiliser un jeu d'instruction VLIW, soit être un processeur superscalaire, soit utiliser des instructions SIMD. Les trois solutions sont utilisées, suivant le DSP. Et il n'est pas rare que l'on ait des DSPs qui mélangent SIMD et VLIW, ou encore SIMD et superscalarité. Les DSP les plus simples sont les '''DSP ''dual MAC''''', au nom assez parlent. Ils incorporent deux multiplieurs, voire deux unités de calcul FMAC, qui peuvent fonctionner en même temps. Des exemples de DSPs de ce type sont le Lucent DSP 16xxx ou le TMS C55x de Texas Instrument. Le Lucent DSP 16xxx contenait deux multiplieurs de 16 bits, couplés à une ALU entière et un additionneur trois-opérandes. Cela parait bizarre de ne pas avoir utilisé deux ALU entières, mais cela permet d'économiser un peu de circuit de remplacer une seconde ALU par un additionneur. L'ensemble permettait de faire deux opérations MAC par cycle. Il y avait aussi une unité de manipulation de bit, sans compter de nombreux circuits décaleurs intercalés en entrée et sortie des multiplieurs. [[File:Lucent DSP16xxx.png|centre|vignette|upright=2|Lucent DSP16xxx]] Mais les unités MAC ne sont pas seules au monde, il faut aussi tenir compte des ALU entières et du ''barrel shifter''. Les DSP ''dual MAC'' basiques ne les dupliquent pas, mais d'autre le font. Pour donner un exemple, le Texas Instruments TMS320 C62x incorpore deux multiplieurs, deux ALU entières, deux unités de calcul qui regroupent une ALU entière avec un ''barrel shifter'', et deux unités de calcul d'adresse. Le tout est associé à deux bancs de registres contenant 32 registres de 32 bits chacun. Pour les exploiter, le processeur utilisait un jeu d'instruction VLIW, où chaque faisceau VLIW regroupait 8 instructions, chacune allant sur une des 8 unité. L'ADI TigerSHARC est un processeur qui mélange SIMD et VLIW. L'idée est qu'il peut exécuter un même faisceau VLIW sur deux paquets de données. Pour cela, le processeur contient deux chemins de données identiques, qui exécutent le même instruction VLIW, mais sur des données différentes. Chaque chemin de données contient 32 registres, une unité mémoire (avec calcul d'adresse), un ''barrel shifter'', une ALU entière et un circuit MAC. Un faisceau VLIW encode 4 instructions : une instruction LOAD/STORE, une opération MAC, une opération de calcul entière et un décalage. Les DSP incorporent aussi ce que j'ai appelé du SWAR (''SIMD Within A Register'') dans le chapitre sur le parallélisme de données. L'idée est de configurer un additionneur 32 bits pour faire deux additions 16 bits à la fois. Les ALU entières des DSPs incorporent cette optimisation. Les DSPs ayant souvent des ALU entières de 40 bits, cela permet d'implémenter deux additions de 16 bits, avec des ''guard bit'' pour chaque addition. Les ''guard bits'' sont répartis équitablement entre les deux additions 16 bits. Concrètement, le résultat de 40 bits est composé de deux résultats de 20 bits, avec 4 ''guard bits'', les deux résultats étant concaténés. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les ISA optimisés pour la compilation/interprétation | prevText=Les ISA optimisés pour la compilation/interprétation | next=Les architectures actionnées par déplacement | nextText=Les architectures actionnées par déplacement }} </noinclude> 0w2s6njpnhw12xu8yciqqo64q63vd4v 772101 772100 2026-09-12T18:22:56Z Mewtow 31375 /* L'optimisation des boucles sur un DSP */ 772101 wikitext text/x-wiki Les '''processeurs de traitement du signal''', sont des jeux d'instructions spécialement conçus pour travailler sur du son, de la vidéo, des images, ou toute autre forme de signal. Ils sont aussi appelés des DSP, abréviation de ''Digital Signal Processor''. Le jeu d'instruction d'un DSP est assez spécial, car il est conçu pour des applications très spécifiques. Et la conséquence est que leur jeu d'instruction est complétement à part du reste, au point où leur donner un chapitre à part est une nécessité. ==Contexte : le traitement temps réel d'un signal== Le traitement du signal regroupe tout ce qui traite de l'audio, de la vidéo, mais aussi d'autres formes de signaux plus difficiles à conceptualiser. Les cas d'utilisations les plus courant sont le traitement d'image (appareils photos), la compression et le filtrage vidéo, les cartes sons d'un ordinateur ou d'une console de jeu, les communications sans fil avec des périphériques, la téléphonie, et autres usages moins familiers (radars, imagerie médicale). Le traitement de signal était autrefois réalisé par des composants purement analogiques. Les circuits analogiques de ce type étaient utilisés dans les anciennes radios, les chaines HI-FI, les télévisions, les magnétoscopes, et bien d'autres composants électroniques moins familiers. De nos jours, le signal est traité par des processeurs numériques. Un système audio/vidéo/autres fonctionne cependant encore avec des signaux analogiques. Simplement, il y a une conversion analogique vers numérique, un traitement par un DSP, puis une conversion numérique vers analogique. [[File:DSP block diagram.svg|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP.]] [[File:Dsp bloc fr.png|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP, en français.]] ===Un flux de données échantillonné=== Le signal sonore/vidéo/autre qui est capté est un signal analogique : il change en permanence, il n'a pas de fréquence définie. Mais ce signal est échantillonné, à savoir que l'on mesure sa valeur à une fréquence prédéterminée, appelée la '''fréquence d’échantillonnage'''. Par exemple, pour un signal sonore, la fréquence d’échantillonnage est de 44,1 kHz, 48 kHz, 96 kHz ou 192 kHz. Soit une mesure approximativement toutes les 22,6 µs, 20,83 µs, 10,4 µs, 5,2 µs. L'intensité sonore mesurée à un instant est appelée un échantillon sonore. Il existe un équivalent pour la vidéo : les échantillons sont les images à afficher à l'écran, il y en a une toutes les 1/24ème de secondes pour une vidéo à 24 FPS. [[File:Sampled.signal.svg|centre|vignette|upright=1.5|Signal échantillonné.]] Les échantillons sont généralement accumulés dans une structure de donnée en mémoire RAM, appelée une '''file'''. Il s'agit d'un paquet d'échantillon classés par ordre d'arrivée (une structure de donnée de type FIFO). Elle a une taille finie, ce qui fait que le nombre d'échantillons est prédéfini à l'avance. Quand un échantillon est ajouté dans une FIFO pleine, la donnée la plus ancienne est éliminée (elle a déjà été traitée de toute façon). Les FIFOs de ce type sont conçues à partir d'un tableau, auquel on a ajouté deux pointeurs : un pour la donnée la plus ancienne, un pour la plus récente. Pour le dire autrement, ces deux pointeurs correspondent au début de la file et à sa fin. Le début de la file correspond à l'endroit où l'on insère les nouvelles données. La fin de la file correspond à la donnée la plus ancienne en mémoire. À chaque ajout de donnée, on doit mettre à jour l'adresse de début de file. Lors d'une suppression, c'est l'adresse de fin de file qui doit être mise à jour. Ce tableau a une taille fixe. Si jamais celui-ci se remplit jusqu'à la dernière case, (ici la cinquième), il se peut malgré tout qu'il reste de la place au début du tableau : des retraits de données ont libéré de la place. L'insertion continue alors au tout début du tableau. Cela demande de vérifier si l'on a atteint la fin du tableau à chaque insertion. De plus, en cas de débordement, si l'on arrive à la fin du tableau, l'adresse de la donnée la plus récemment ajoutée doit être remise à la bonne valeur : celle pointant sur le début du tableau. Tout cela fait pas mal de travail. Les DSPs ont des modes d'adressages spécialisés pour accéder à des données dans de telles files, comme on le verra plus bas. ===Les algorithmes exécutés par un DSP=== Un DSP exécute des algorithmes très précis : un algorithme de filtrage, un algorithme de transformée de Fourier rapide, un algorithme de '''''Finite Impulse Response''''', des algorithmes de convolution, ou tout autre algorithme de traitement de signal. L'algorithme travaille sur un nombre fini d'échantillons, qui sont lus depuis la file décrite plus haut. Le jeu d'instruction d'un DSP est optimisé pour les algorithmes de traitement de signal les plus courants. Aussi, pour comprendre le jeu d'instruction d'un DSP, nous n'avons pas le choix : il faut étudier quelques algorithmes de traitement de signal. Mais rassurez-vous, pas besoin d'aller dans le détail. Nous allons voir quelques algorithmes simples, et encore : nous allons les survoler, sans expliquer pourquoi et comment ils marchent. L'exemple le plus utile pour l'étude des DSP est celui du filtre FIR (''Finite Impulse Response''). Celui-ci est assez simple sur le principe : on prend les N échantillons les plus récents, on les multiplie chacun par un coefficient, et on additionne le tout. La formule exacte ressemble à ceci : : <math>y(t) = {\sum_{n=0}^{N-1}} b_n \cdot x[t - n]</math>, avec <math>b_n</math> le coefficient de l'échantillon à l'instant t-n. [[File:FIRdrekteForm.png|centre|vignette|upright=2|Représentation graphique d'un filtre FIR. Les échantillons à l'instant n sont notés u(n), T représente le délai entre deux échantillons.]] Vous remarquerez que cet algorithme s'implémente avec une boucle, chaque itération faisant une multiplication suivie d'une addition. Si on suppose que les N échantillons sont mémorisés dans un tableau, et que les N coefficients sont dans un second tableau, alors le code devrait être le suivant : <syntaxhighlight lang="c"> int resultat = 0 ; for (i=0 ; i < N ; ++i) { resultat += coefficient[i] * echantillons[i] ; } </syntaxhighlight> Et c'est une règle pour de nombreux algorithmes de traitement de signal : ils s'implémentent avec une boucle, qui parcourt un ou plusieurs tableaux/files, l'intérieur de la boucle faisant des calculs du type a * b + c. Il est intéressant de regarder ce que donne le codé précédent, une fois compilé sur une architecture RISC. Un point important est que ce code manipule quatre variables par itération de boucle : les deux opérandes de la multiplication, le résultat de la multiplication, et la variable d'accumulation resultat. On va placer les deux opérandes dans les registres R0 et R1, le résultat de la multiplication dans le registre R2, et la variable resultat dans le registre R3. Le compteur de la boucle est mémorisé dans le registre R7. Voici une sorte de pseudo-code ASM qui ressemble pas mal à ce que sortirait un compilateur, avec pas mal de simplifications de notations pour faire passer la pilule. Les commentaires indiquent qu'une étape de calcul d'adresse est réalisée, en utilisant plusieurs instructions. <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> En clair, on charge les deux opérandes dans un registre, on multiplie, on additionne, puis on effectue de quoi gérer la boucle. La '''transformée de Fourier rapide''' est un algorithme un peu plus complexe que le précédent, mais particulièrement utile en traitement de signal. Sans rentrer dans les détails d'implémentation, il agit sur des nombres complexes, qui sont composés d'une partie réelle et la partie imaginaire. Les parties entières et imaginaires sont encodés avec deux nombres entiers ou flottants. L'algorithme utilise un tableau de nombres complexes, qui est en pratique séparé en deux tableaux séparées, avec un tableau pour les parties réelles et un autre pour les parties imaginaires. La transformée de Fourier rapide est composée d'une boucle qui applique à chaque itération une opération dite ''butterfly''. Elle prend en entrée un nombre complexe, et fournit un autre nombre complexe en sortie. Elle applique des multiplications/additions sur deux variables qu'on appellera A et B. À chaque itération de boucle, l'opération ''butterfly'' exécute le calcul suivant : : <math>A = A + B \times \text{coefficient A}</math> : <math>B = B + A \times \text{coefficient B}</math> Retenez bien que cette opération s'appelle l'opération ''butterfly'', car les DSPs intègrent des optimisations dédiées pour cette opération. ===Les contraintes dites ''temps réel''=== Le DSP exécute l'algorithme de traitement de signal entre deux arrivées d'échantillon. Précisément, le DSP est commandé par une interruption. Lorsqu'un nouvel échantillon est disponible, le CAN envoie une interruption au DSP pour le prévenir. Le DSP lit alors l'entrée correspondant au CAN et récupère cet échantillon dans un registre. Il met alors à jour la file des échantillons, met à jour le pointeur qui indique le début de la file. Puis il exécute l'algorithme de traitement de signal. Une fois terminé, il envoie le résultat au CNA. Il y a donc un délai temporel très strict à respecter : le traitement doit être fini avant l'arrivée du prochain échantillon. Cette contrainte dite ''temps réel'' font qu'il est préférable de ne pas utiliser de mémoire virtuelle, d'interruptions, ou beaucoup d'autres fonctionnalités courantes sur les processeurs modernes. Par exemple, les branchements sont une source de problèmes pour le ''temps réel''. Le temps d'exécution du code change selon que le branchement est pris ou non, les deux codes exécutés suivant que la condition est valide ou non ne faisaient pas forcément le même temps. En conséquence, les DSP incorporent des instructions à prédicats pour remplacer les branchements hors-boucles, et ajoutent des techniques pour accélérer les boucles. La présence de caches est une autre source de problèmes dans les systèmes ''temps réel'', car le temps d'exécution dépend de si les accès mémoire font des succès ou des défauts de cache. En conséquence, les premiers DSP commercialisés n'utilisaient pas de mémoire cache pour les données, et se limitent à des caches d'instructions. L'absence de cache est compensée l'usage de ''local store'', dans lesquels des échantillons sont accumulés. Les ''local store'' sont souvent alimentés par des transferts DMA, qui font des copies ''local store'' vers mémoire RAM ou inversement. Les ''local store'' ne posent pas de problèmes pour le temps réel, car le programmeur sait à tout moment quelles sont les données présentes dans un ''local store'', ce qui n'est pas le cas dans un cache. De même, beaucoup d'optimisations posent problème avec le temps réel, parce qu'elles rendent le temps d'exécution plus variable. L'usage d'un pipeline est parfaitement possible, mais sous certaines conditions. La plus importante est qu'il faut utiliser l'émission dans l'ordre. Pas question d'utiliser d'exécution dans le désordre, de prédiction de branchement ou toute autre optimisation du genre. Dans les faits, presque tous les DSP commercialisés après les années 90 utilisent un pipeline. L'usage de l'émission multiple est parfaitement possible, et de nombreux DSP récents sont soit superscalaires, soit des CPU VLIW. La seconde solution est plus souvent utilisée, la compatibilité matérielle n'étant pas importante sur les DSPs. ==Le jeu d'instruction d'un DSP== Les DSPs incorporent de nombreuses optimisations spécifiques, pour optimiser les algorithmes de traitement de signal. Et ces optimisations peuvent se comprendre assez facilement quand on analyse le code d'un filtre FIR. Pour rappel, il s'agit du code assembleur vu plus haut, que je reproduis ici : <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> Il est intéressant d'étudier comment la boucle précédente peut être optimisée, avec un jeu d'instruction adapté, car ces optimisations se généralisent à tous les algorithmes de traitement de signal. Optimiser la boucle précédente demande d'optimiser plusieurs points : optimiser les calculs d'adresse, optimiser les lectures, optimiser les calculs arithmétiques, optimiser la boucle elle-même (les trois instructions de fin). Les DSPs incorporent des optimisations pour chaque point, voyons lesquelles. ===L'optimisation des boucles sur un DSP=== Premièrement, on doit réduire le temps passé dans les tests et branchements au minimum. Sans optimisations particulières, il faut incrémenter l'indice, faire la comparaison, et le branchement conditionnel. L'intérieur de la boucle consiste en deux lectures, une addition et une multiplication, soit quatre instructions. Si on fait les comptes, un peu moins de la moitié des instructions est passé à gérer la boucle FOR. Et de nombreuses optimisations visent à réduire grandement les couts liés à la boucle FOR. En premier lieu, le nombre de répétitions restantes est mémorisé dans un '''registre compteur de boucle'''. Il est initialisé avant de la boucle FOR, et il est décrémenté à chaque itération. La boucle se termine quand ce registre atteint zéro. En soit, le registre compteur de boucle n'est pas une optimisation, il ne permet pas de gagner des cycles d'horloge. Par contre, sa présence permet d'implémenter des optimisations, qu'on va détailler dans ce qui suit. Première optimisation : les DSP ont des instructions qui effectuent un test, un branchement et une décrémentation du registre compteur de boucles. L'instruction fusionne donc un test et un branchement, comme c'est le cas sur certains processeurs RISC ou CISC, mais avec une petite subtilité. Le test et le branchement sont adaptés pour tenir compte du registre compteur de boucle. Le test en question vérifie si ce compteur de boucle vaut zéro et effectue un branchement si ce n'est pas le cas. De plus, la mise à jour du registre compteur de boucle est elle aussi réalisée automatiquement. On économise donc une décrémentation. La seconde optimisation est un peu différente. Il s'agit des techniques de '''''zero overhead looping''''', qui permettent d'exécuter des boucles sans avoir à utiliser de branchements, ou presque. Pour rappel, celles-ci utilisent une instruction REPEAT, qui précise que les N instructions suivantes doivent s'exécuter en boucle, M fois. Typiquement, elles permettent d'implémenter des boucles FOR dont le nombre d’exécution est connu à l'avance. L'instruction REPAET/LOOP utilise le registre compteur de boucle pour savoir combie d'itérations il lui reste. Une variante précise deux adresses, qui délimitent les instructions de la boucle : une adresse pour le début de la boucle, une adresse pour la fin. L'implémentation hardware est alors assez simple : quand le ''program counter'' atteint l'adresse de fin, il est réinitialisé à l'adresse de début. Avec ces techniques, le code ASM d'un filtre FIR devient ceci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 </syntaxhighlight> Autre fonctionnalité : les '''instructions autorépétées''', des instructions qui se répètent automatiquement tant qu'une certaine condition n'est pas remplie. L'instruction effectue le test, le branchement, et l’exécution de l'instruction proprement dite en un cycle d'horloge. Cela permet de gérer des boucles dont le corps se limite à une seule instruction. Cette fonctionnalité a parfois été améliorée en permettant d'effectuer cette répétition sur des suites d'instructions. Les DSPs incorporent aussi des caches d'instructions, afin de gagner de précieux cycles d'horloge. En général, les caches d'instructions en question sont spécialisés dans l'exécution de petites boucles, qui tiennent entièrement dans le cache. ===Les opérations arithmétiques d'un DSP=== Voyons maintenant quelles optimisations peuvent être réalisées pour les opérations arithmétiques. Le calcul à faire est en soi très simple : une multiplication suivie d'une addition. Aussi, vous ne serez pas étonnés d'apprendre que tous les DSP supportent les instructions ''Multiply and Add'' (MAD), qui effectuent une multiplication suivie d'une addition. Pour rappel, la première travaille sur des opérandes entiers, la seconde des opérandes flottants. Utiliser une instruction MAD simplifie donc la boucle, sans compter que cela fait économiser un registre, vu qu'on n'a pas besoin de stocker le résultat de la multiplication. Et non seulement les DSPs intègrent une instruction MAD, mais ils ont aussi une unité de calcul dédiée à cette opération. Un autre point important est que l'addition sert juste à ajouter le produit à une variable temporaire. A chaque itération de la boucle, la variable est incrémentée avec le produit a*b. Il s'agit d'un calcul d'accumulation, qui se marie très bien avec la présence d'un registre accumulateur. Les DSPs incorporent donc un registre accumulateur dans l'unité de calcul MAD, ce qui en fait des architectures à accumulateur. Les instructions MAD lisent un opérande depuis l'accumulateur et mémorisent leur résultat dedans. Il s'agit donc d'instructions MAD un peu spéciales, appelées ''multiply and accumulate'' (MAC) ou ''fused multiply and accumulate'' (FMAC). Nous parlerons d'instructions MAC dans ce qui suit. [[File:Instruction MAD avec accumulateur d'un DSP 01.png|centre|vignette|upright=2|Instruction MAD avec accumulateur d'un DSP]] Avec l'usage d'une instruction MAC, le code d'un filtre FIR devient celui-ci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MAC RO , R1 </syntaxhighlight> De nombreux DSPs utilisent deux accumulateurs, pour accélérer l'opération ''butterfly'' des transformées de Fourier rapides. Mieux que ça : ils intègrent une instruction de multiplication complexe qui effectuent deux opérations MAC, sur les deux accumulateurs, en une seule instruction. Les instructions MAC n'ont besoin d'adresser que deux opérandes : celles de la multiplication. L'opérande de l'addition est dans un accumulateur adressé implicitement. Du moins, s'il y a un seul accumulateur. De nombreux DSPs ont entre 2 et 8 accumulateurs, même si la norme est à 2 accumulateurs. Dans ce cas, les accumulateurs étant séparés des autres registres, son adressage est un peu particulier. Les accumulateurs ont des numéros séparés des autres numéros/noms de registres. {|class="wikitable" |+ Encodage d'une instruction MAC |- ! Opcode !! Premier opérande !! Second opérande !! Opérande addition/résultat |- | Opcode || Numéro de registre ou adresse mémoire || Numéro de registre ou adresse mémoire || Numéro d'accumulateur |- | Un octet, environ || Variable || Variable || 1 à 3 bits, selon le nombre d'accumulateurs |} ===Les modes d'adressage d'un DSP=== Une autre source d'optimisation est liée aux calculs d'adresse. Les échantillons ne sont pas stockés dans un tableau, mais dans une file. La différence n'est pas énorme, car les files sont souvent implémentées par des tableaux, associés à deux pointeurs : un qui donne la position de la donnée la plus ancienne, un autre pour la donnée la plus récente. [[File:Fonctionnement d'une file - 1.png|centre|vignette|upright=2|Fonctionnement d'une file.]] Le tableau commence à être rempli à partir de sa première case, d'indice 0. Les données accumulées ensuite sont ajoutées dans la case d'indice 12, puis 2, puis 3, etc. Les données devenues inutiles sont retirées de la FIFO, ce qui laisse des vides, qui peuvent être réutilisées par la suite. Quand on arrive à la fin du tableau, le remplissage recommence à partir du début du tableau, si des espaces vides ont été libérés. Voici un exemple : {| |- |[[File:Circular buffer - XX123XX with pointers.svg|vignette|upright=1.5|Circular buffer - XX123XX with pointers]] |- |[[File:Circular buffer - XX1234X with pointers.svg|vignette|upright=1.5|Circular buffer - XX1234X with pointers]] |- |[[File:Circular buffer - XXX234X with pointers.svg|vignette|upright=1.5|Circular buffer - XXX234X with pointers]] |- |[[File:Circular buffer - XXX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - XXX2345 with pointers]] |- |[[File:Circular buffer - 6XX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6XX2345 with pointers]] |- |[[File:Circular buffer - 67X2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 67X2345 with pointers]] |- |[[File:Circular buffer - 6782345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6782345 with pointers]] |} Les DSP tendent à utiliser des files de taille fixe, ce qui fait que le remplissage ne s'arrête pas quand la file est pleine. À la place, le nouvel échantillon remplace l'échantillon le plus ancien. Il n'y a donc pas vraiment besoin d'utiliser deux pointeurs, car on est certain que la file sera pleine en permanence et que ce remplacement se fera sans douleur. Une file sur un DSP s'implémente donc en utilisant trois pointeurs : un pour l'adresse de départ du tableau en mémoire, un autre pour l'adresse de fin du tableau, et un pointeur qui pointe vers la donnée la plus ancienne/récente. [[File:Circular buffer - 6789AB5 full.svg|centre|vignette|upright=2|File telle qu'utilisée sur un DSP.]] En clair, les files sont des tableaux dans lesquels la position des échantillons est décalée. La différence est mineure, mais elle fait que des calculs d'adresse sont requis pour déterminer à quel indice lire dans le tableau. Pour éviter cela, les DSPs intègrent des modes d'adressage spécialisés, conçus pour fonctionner au mieux avec les files mentionnées plus haut. Déjà, les files sont implémentées avec des tableaux, ce qui fait que les modes d'adressages indicés sont une nécessité absolue. Déjà, les DSP supportent l'adressage "Base + Indice", qui permet de grandement simplifier les calculs d'adresse pour une file. L'adresse de base utilisée n'est pas l'adresse de base du tableau, mais celle de la donnée la plus récente ou la plus ancienne. L'idée est que l'échantillon le plus récent est celui d'indice zéro, le précédent celui d'indice 1, celui encore précédent est d'indice 2, etc. Les DSPs anciens/basiques étant des architectures à accumulateur, ils incorporent pour cela des '''registres d'indice''', et éventuellement des '''registres d'adresse''' pour mémoriser l'adresse de base. Une autre optimisation est l'usage de modes d'adressage avec post- ou pré-incrément/décrément. L'idée est que la lecture met à jour automatiquement l'indice utilisé, afin d'économiser une instruction d'incrémentation ou une addition. La lecture qui lit un opérande en mémoire RAM incrémente alors automatiquement l'indice utilisé dans l'adressage "Base + Indice". Cependant, faire ainsi pose un petit problème : que faire quand on atteint la fin du tableau ? En théorie, on devrait reprendre au tout début du tableau. Mais l'adressage "Base + Indice" ne permet pas de faire cela automatiquement. Sans optimisations, on devrait faire un test et un branchement avant chaque lecture, pour gérer ce cas. Mais les DSPs incorporent un mode d'adressage spécialisé, qui permet de gérer automatiquement ce cas problématique, directement dans la lecture elle-même ! Il s'agit du '''mode d'adressage « modulo »'''. Si lors d'une incrémentation, on dépasse l'adresse de fin du tableau, l'adresse est réinitialisée pour pointer sur l'adresse de début du tableau. Il garantit que l'adresse reste dans la file et n'en déborde pas. Suivant les DSP, le mode d'adressage modulo est géré différemment. La méthode la plus évidente utilise deux registres : un pour stocker l'adresse de début du tableau et un autre pour l'adresse de fin. Une solution alternative n'utilise pas l'adresse de fin, mais la taille/longueur du tableau. Cette dernière se marie bien avec des registres d'indices : la longueur du tableau est comparée avec l'indice courant, pour vérifier si l'adresse dépasse la fin du tableau. Une seconde méthode utilise un registre « modulo », qui stocke la taille du tableau. Il est associé à un registre d'adresse pour l'adresse/indice de l’élément en cours. Vu que seule la taille du tableau est mémorisée, le processeur ne sait pas quelle est l'adresse de début du tableau, et doit donc ruser. La ruse ne fonctionne que pour des files/tableaux de petite taille. L'adresse est alors alignée sur un multiple de 64, 128, ou 256 octets. Cela permet ainsi de déduire l'adresse de début de la file : c'est le multiple de 64, 128, 256 strictement inférieur le plus proche de l'adresse manipulée. Un DSP a souvent plusieurs copies de chaque registre d'adresse/indice. La raison est que cela permet de gérer plusieurs files. Il faut dire qu'un DSP exécute souvent plusieurs algorithmes de traitement de signal à la suite. Par exemple, il est possible d'avoir un filtre FIR suivi d'un filtre d'antialiasing, suivi d'un algorithme de ''Fast Fourier Transform'', et ainsi de suite. Certains de ces algorithmes, comme la ''Fast Fourier Transform'', se font en plusieurs étapes enchainées les unes à la suite des autres. Et chaque étape a son propre ensemble d'échantillons, donc sa propre file. Et le DSP peut gérer ces différentes files nativement. Le mode d'adressage modulo semble assez spécialisé, mais sachez que les DSPs supportent des modes d'adressages encore plus spécialisés, utilisables seulement par un ou deux algorithmes triés sur le volet ! L''''adressage à bits inversés''' (''bit-reverse'') a été inventé pour accélérer les algorithmes de calcul de transformée de Fourier rapide, un « calcul » très courant en traitement du signal. Cet algorithme lit des échantillons dans un tableau, et fournit des résultats dans un autre tableau. Seul problème, l'ordre des résultats dans le tableau d'arrivée est assez spécial. Par exemple, pour un tableau de 8 cases, les données arrivent dans cet ordre : 0, 4, 2, 6, 1, 5, 3, 7. L'ordre semble être totalement aléatoire. Mais il n'en est rien : regardons ces nombres une fois écrits en binaire, et comparons-les à l'ordre normal : 0, 1, 2, 3, 4, 5, 6, 7. {|class="wikitable" |- !Ordre normal!!Ordre Fourier |- ||000||000 |- ||001||100 |- ||010||010 |- ||011||110 |- ||100||001 |- ||101||101 |- ||110||011 |- ||111||111 |} Comme vous le voyez, les bits de l'adresse Fourier sont inversés comparés aux bits de l'adresse normale. Inverser les bits d'une adresse peut être fait avec des opérations bit à bit, des décalages et rotations, mais cela prendrait beaucoup d'instructions. Il est possible d'imaginer une instruction REVERSE qui inverse les bits d'une adresse. Ce serait là une solution fort intéressante, que certains DSPs doivent sans doute implémenter. Mais beaucoup de DSPs préfèrent utiliser un mode d’adressage qui inverse tout ou partie des bits d'une adresse mémoire : l'adressage ''bit-reverse'' mentionné plus haut. Une autre solution utilise un adressage indicé, mais qui calcule les adresses différemment. Il suffit, lorsqu'on ajoute un indice à l'adresse, de renverser la direction de propagation de la retenue lors de l'addition. Certains DSP disposent d'instructions pour faire ce genre de calculs. ==L'architecture mémoire d'un DSP== Les DSPs ont une architecture mémoire particulière. Par architecture mémoire, je veux dire par là que leur hiérarchie mémoire est particulière. Déjà, ils n'ont généralement pas de caches de données, car celui-ci n'est pas compatible avec le temps réel. Par contre, ils tendent à compenser en utilisant des ''local store''. Si un DSP ne possède généralement pas de cache pour les données, il a parfois un cache d'instructions pour accélérer l'exécution des boucles. ===L'usage de registres spécialisés=== Les DSPs se passent de registres généraux, car les algorithmes de traitement de signal n'en ont pas besoin. Vous remarquerez que le code d'un filtre FIR n'utilise pas beaucoup de registres, et ce d'autant plus si on utilise des instructions MAD et un registre accumulateur. Et cela se généralise aux autres algorithmes de traitement de signal. Mais surtout, les conditions pour utiliser des registres ne sont pas réunies. Pour rappel, les registres servent dans deux situations. La première est quand un opérande est lu par plusieurs instructions différentes. Dans ce cas, mieux vaut copier l'opérande dans un registre, au lieu de la relire plusieurs fois en mémoire RAM. La première utilisation a un cout, mais les suivantes sont amorties. Mais les algorithmes de traitement de signal ne réutilisent pas leurs opérandes. Quand un opérande est chargé depuis la mémoire RAM, elle sera utilisée une seule fois. Un autre usage des registres est lié aux résultats des instructions. En général, le résultat d'une instruction est utilisé comme opérande par d'autres instructions, au moins une. Ainsi, il vaut mieux enregistrer ce résultat dans un registre, histoire que sa lecture en tant qu'opérande se fasse rapidement. Mais sur les DSPs, ce transfert à l'instruction suivante est le fait du registre accumulateur ! A lui seul, il prend en charge cette réutilisation des résultats. A la rigueur, pour certains algorithmes, un seul accumulateur n'est pas suffisant. Mais en utiliser 2 ou 3 accumulateurs suffit généralement à résoudre totalement ce problème. Cependant, il y a plusieurs situations qui mériteraient d'utiliser des registres : les calculs d'adresse, ainsi que les compteurs de boucle. Mais pour ces deux cas, les DSPs préfèrent utiliser des registres spécialisés. Ils intègrent ainsi des registres pour les adresses, reliés à une unité de calcul d'adresse dédiée. Idem pour les compteurs de boucle, qui ont des registres dédiés, afin de simplifier l'implémentation du ''zero-overhead looping''. Les registres d'un DSP ne correspondent donc à rien de familier à ce stade du cours, ils sont vraiment à part du reste. Cette spécialisation des registres a de nombreuses conséquences. Certaines instructions ne sont utilisables que sur certains types de registres, et il en est de même pour les modes d'adressage. Certaines instructions d'accès mémoire peuvent prendre comme destination ou comme opérande un nombre limité de registres, les autres leur étant interdits. Cela permet de diminuer le nombre de bits nécessaire pour encoder l'instruction en binaire. Mais cette spécialisation des registres pose de nombreux problèmes pour les compilateurs, qui ont du mal à utiliser correctement les modes d'adressages spécialisés, ainsi qu'à utiliser correctement les registres. Il n'est pas étonnant que les DSP aient longtemps été programmés en assembleur, et il n'est pas rare qu'ils le soient toujours. Par contre, l'usage de registres spécialisés permet des optimisations très importantes. Les DSPs modernes sont capables de faire deux calculs d'adresse, une opération MAC, et un branchement de boucle en un seul cycle d'horloge. Le branchement est réalisé via ''zero overhead looping'', les calculs d'adresse le sont via les modes d'adressage adéquats. Si l'indice de boucle, les adresses et opérandes étaient dans un banc de registre unique, alors celui-ci devrait avoir entre 5 et 10 de ports de lecture. En utilisant des bancs registres séparés, on peut se débrouiller avec seulement deux ports de lecture par banc de registre, voire moins : deux ports de lecture pour les registres d'opérandes, un registre d'indice de boucle séparé, deux-trois ports de lecture pour le banc de registre pour les adresses, etc. ===La lecture des opérandes pour l'instruction MAC=== Le reste de l'architecture mémoire d'un DSP est assez bizarre : ils utilisent des architectures Harvard, sont reliés à des mémoires multiports, n'ont pas de registres généraux, et j'en passe. Ces particularités visent à exécuter des instructions MAC rapidement. En théorie, les instructions utilisant un accumulateur sont de type ''load-op'' : un opérande est lu depuis l'accumulateur, l'autre depuis la mémoire RAM. Mais autant cela marche bien pour des instructions à deux opérandes, autant il y a un problème pour les instructions MAC. Vu que ce sont des instructions triadiques, il faut lire les deux opérandes de la multiplication depuis la mémoire RAM. Et ce n'est pas possible avec une architecture classique. La solution la plus simple lit les deux opérandes un par un, depuis la mémoire RAM. Il s'agit d'une solution assez générale, qui marche aussi pour d'autres algorithmes que les filtres FIR. Et cela demande d'adapter le processeur pour gérer la situation. La première solution ajoute un registre pour mémoriser un des opérandes de la multiplication, situé juste avant l'unité de calcul MAC, que nous nommerons le '''registre T'''. Le registre T est adressé implicitement, tout comme l'accumulateur. Une instruction MAC a juste besoin de connaitre l'adresse de la seconde opérande. Cette solution a beaucoup été utilisée sur les tout premiers DSP, notamment ceux de la marque Texas Instrument. Elle est de moins en moins utilisée de nos jours. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois LOAD RA0 ; // copie dans le registre T, instruction avec mode d'adressage en post-incrément MAC RA1 // instruction avec mode d'adressage en post-incrément </syntaxhighlight> [[File:Implémentation de l'instruction MAC avec un registre d'opérande.png|centre|vignette|upright=2|Implémentation de l'instruction MAC avec un registre d'opérande]] Une solution plus élaborée ne se contente pas d'ajouter un seul registre T, mais plusieurs registres pour les opérandes. Quelques DSPs utilisent cette solution, même s'ils sont assez minoritaires. Les DSPs avec des registres pour les opérandes se débrouillent donc avec moins d'une dizaine de registres, généralement 2 ou 4. La raison à cela est que les algorithmes de traitement de signal n'ont pas besoin de plus, comme on l'a dit plus haut. Il est possible de transférer les données de l'accumulateur vers ces registres d'opérandes, mais cela ne sert pas très souvent. De plus, cela demande de faire un arrondi, car les registres sont plus petits que l'accumulateur. La majorité des DSPs n'utilise pas les deux solutions précédentes. A la place, ils préfèrent se passer de registres pour les opérandes. Les deux opérandes sont lus directement dans la mémoire RAM, en même temps ! En clair, les instructions des DSPs peuvent faire plusieurs accès mémoire simultanés. L'instruction MAC est alors une pure instruction ''load-op'', mais adaptée à l'usage de trois opérandes. En utilisant les modes d'adressage adéquats, l'instruction MAC fait tout : elle calcule les adresses modulo, lit des opérandes depuis la mémoire RAM/ROM, puis fait l'opération MAC. Avec cette solution, le code d'un filtre FIR devient le suivant. Vous remarquerez qu'il se résume à une instruction MAC et une instruction de ''zero overhead looping''. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAD RA0 , RA1 </syntaxhighlight> La mémoire RAM doit être adaptée pour faire plusieurs accès mémoire par cycle, ce qui implique d'utiliser une mémoire multiport, pour gérer nativement plusieurs accès par cycle. Cette solution a l'avantage de fonctionner pour d'autres algorithmes que les filtres FIR, et est en quelque sorte plus générale. Les deux solutions peuvent être utilisées en même temps. Par exemple, le DSP TMS320-C54x incorpore deux ''local store'' : un ''local store'' double port pour les opérandes, un deuxième pour écrire les résultats. [[File:Architecture mémoire des DSP.png|centre|vignette|upright=2|Architecture mémoire des DSP.]] Une autre solution, qui marche parfaitement pour les filtres FIR, utilise deux mémoires séparées : une qui contient les échantillons, une autre pour les coefficients. Les deux RAMs peuvent être accédées en parallèle, ce qui permet de charger les deux opérandes d'une multiplication en même temps. La mémoire pour les coefficients peut-être une mémoire ROM dédiée, et pas une mémoire RAM. Utiliser une RAM pour les coefficients est utile si le filtre change au cours du temps, mais une ROM suffit si elle peut mémoriser tous les coefficients nécessaires. [[File:Architecture mémoire des DSP avec deux mémoires séparées.png|centre|vignette|upright=2|Architecture mémoire des DSP avec deux mémoires séparées]] ===L'usage d'une architecture Harvard modifiée=== Les solutions précédentes peuvent être améliorées, voire combinées, en utilisant une architecture Harvard modifiée. Pour rappel, une architecture Harvard permet de lire des constantes depuis la mémoire ROM. L'idée est que les coefficients d'un filtre FIR sont chargées depuis la mémoire ROM, et non la mémoire RAM. Et quand je dis la ROM, c'est sous-entendu : celle qui contient aussi le programme à exécuter. La solution est praticable, car les algorithmes de traitement de signal sont assez courts et utilisent assez peu de coefficients (moins d'un millier), ce qui fait que le programme et les coefficients rentrent tous deux dans la mémoire ROM. Elle est utilisée sur les DSPs sans pipeline, ou avec. Elle donne cependant des gains en performance immédiats sur les DSPs sans pipeline. Mais surtout, elle permet d'éliminer le besoin d'avoir une mémoire multiport. Ainsi, pour une instruction MAC d'un filtre FIR, un opérande est lu depuis la ROM, la seconde opérande est lue depuis la mémoire RAM, la troisième est lue depuis l'accumulateur, et le résultat est mémorisé dans l'accumulateur. Au final, on fait bien un seul accès en mémoire RAM par instruction MAC. Le chargement des deux opérandes est intégré dans l'instruction MAC, avec les modes d'adressage adéquats. Typiquement, le DSP incorpore des registres d'adresse séparés pour la ROM et pour la RAM, avec des unités de calcul d'adresse séparées. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAC RA-ROM , RA-RAM // RA-ROM est le registre d'adresse pour la ROM, RA-RAM celui pour la RAM </syntaxhighlight> Utiliser une architecture Harvard modifiée fonctionne bien pour implémenter des filtres FIR et de nombreux algorithmes de traitement de signal, mais elle est peu flexible. Avec cette solution, un des opérandes doit être constant et placé en ROM. Si jamais on souhaite utiliser une donnée variable, cette solution ne marche plus. Mais cela ne signifie pas que l'implémentation est impossible. Il suffit de rajouter le registre T ou les registres d'opérande vus plus haut, pour compenser. [[File:Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.png|centre|vignette|upright=2|Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.]] ===Le contrôleur DMA intégré à un DSP=== Un point important est que les écritures dans le ''local store'' ou la RAM ne passe pas par le DSP, histoire de lui économiser du travail. Les échantillons sont écrits dans le ''local store'' ou la RAM en utilisant le ''Direct Memory Access''. Le DSP contient pour cela un contrôleur DMA, qui transfère les échantillons nécessaires du convertisseur analogique-numérique, vers la mémoire RAM et/ou le ''local store''. Il faut absolument éviter que le DSP et le contrôleur DMA se marchent sur les pieds. Pas question qu'ils accèdent en même temps à la mémoire RAM ou au ''local store''. Et il faut éviter absolument que le contrôleur DMA monopolise la RAM et laisse le DSP patienter trop longtemps, idem pour le cas inverse. La majorité des DSPs intègre des techniques d'arbitrage du bus mémoire assez complexes. Une solution alternative, elle aussi très utilisée, dédie un port mémoire au contrôleur DMA. Le contrôleur DMA accède à la RAM via son propre port mémoire dédié, en même temps que le processeur, les deux peuvent faire un accès mémoire en même temps. Plus besoin d'arbitrer le bus mémoire. [[File:DSP avec controleur DMA.png|centre|vignette|upright=2.5|DSP avec contrôleur DMA.]] ==L'instruction MAC et l'unité de calcul associée== Les DSP intègrent une unité de calcul dédiée pour l'instruction MAC. Elle contient un multiplieur, un additionneur, et un accumulateur, ainsi que d'autres circuits. Cette unité de calcul devrait en théorie être abordée dans une section sur la microarchitecture d'un DSP. Cependant, de nombreux détails de cette unité de calcul sont exposés au programmeur. Notamment, l'accumulateur a quelques particularités qui sont spécifiques au traitement de signal, que le programmeur voit. Voyons lesquelles. ===Les accumulateurs larges et leurs ''Guard Bits''=== Les DSPs ont des besoins en termes de précision plus importants que sur un ordinateur classique. Il n'est pas acceptable de perdre en qualité d'image ou sonore, parce que le processeur a fait un arrondi un peu trop visible. Et ces arrondis ou troncatures sont très fréquents avec des registres généraux, alors qu'on peut les éviter avec des accumulateurs. Voyons comment. Pour rappel, les multiplications donnent un résultat deux fois plus grand que leurs opérandes. Multipliez deux opérandes de 16 bits, le résultat en fera 32. Sur un ordinateur normal, les résultats sont tronqués pour rentrer dans les registres généraux. Par exemple, sur un processeur 32 bits, le résultat d'une multiplication est tronqué, on ne garde que les 32 bits de poids faible, en espérant qu'aucun débordement n'aura lieu. A la rigueur, certains processeurs permettent d'utiliser deux registres de 32 bits : un pour les 32 bits de poids faible du résultat, un autre pour les 32 bits de poids fort. Mais c'est assez rare. À l'opposé, les DSPs utilisent des accumulateurs de grande taille capables de mémoriser le résultat complet d'une multiplication. Il faut noter que le problème a aussi lieu pour l'addition, après la multiplication. Pour une addition, le résultat fera un bit de plus que les opérandes : additionnez deux opérandes de 32 bits, le résultat en fera 33. Vu que le DSP effectue une série d'additions consécutives, le résultat final aura facilement une dizaine de bits en plus, parfois plus, le nombre exact dépendant des opérandes et du nombre d'itérations de la boucle. Pour éviter les débordements d'entiers liés à l'addition, les accumulateurs contiennent souvent 4 à 8 bits de plus que le résultat de la multiplication. Les bits supplémentaires sont appelés des '''''guard bits'''''. Pour donner un exemple, les DSPs de 24 bits ont souvent des accumulateurs de 56 bits : 48 bits pour le résultat de la multiplication, plus 8 ''guard bits''. [[File:Instruction MAD avec accumulateur d'un DSP, avec guard bits.png|centre|vignette|upright=2|Chemin de données d'un DSP, avec guard bits et produit long]] La présence de ''Guard bits'' fait que la gestion des débordements d'entier est fort différente sur les DSPs, comparé aux autres processeurs. De fait, les DSP utilisent souvent l'arithmétique saturée, car c'est assez naturel quand on manipule un signal qui peut... saturer ! Quand un signal sonore sature, cela veut dire que l'intensité sonore dépasse le maximum représentable. En clair, l'intensité sonore dépasse le maximum encodable avec un entier/flottant, il y a un débordement entier/flottant. Si on traitait ce débordement en ne conservant que les bits de poids faible du résultat, un son qui sature donnerait un son très faible, ce qui n'est pas le comportement attendu. Il est plus naturel de mettre le son à la valeur maximale représentable. Les DSP les plus simples n'utilisent que l'arithmétique saturé, mais d'autres plus complexes permettent de configurer si on utilise l'arithmétique saturée ou non. Certains permettent d'activer et de désactiver l'arithmétique saturée, en modifiant un registre de configuration du processeur. D'autres fournissent chaque instruction de calcul en double : une en arithmétique modulaire, l'autre en arithmétique saturée. ===Le décaleur pour les arrondis=== L'accumulateur a donc une taille bien plus grande de celle des opérandes. Typiquement, les opérandes sont soit lues depuis la mémoire RAM, soit depuis des registres pour les opérandes. Dans les deux cas, l'accumulateur est plus large que les registres ou le bus de données. Lorsque les données quittent l'accumulateur, elles doivent donc être tronquées pour rentrer dans l'adresse/registre de destination. Pour cela, l'accumulateur est suivi par un ''barrel shifter'', qui décale le résultat pour éliminer les bits en trop. [[File:Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.png|centre|vignette|upright=2|Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.]] Le décaleur peut aussi prendre en charge d'arithmétique saturée. L'idée est que les circuits qui s'occupent de saturer les résultats sont intégrés avec le décaleur. Ces circuits regardent les ''guard bit'' sortant de l'accumulateur et modifient le résultat en fonction de ceux-ci. Si aucun ''guard bit'' n'est à zéro, alors il n'y a pas eu débordement d'entier et le décaleur fait son travail normalement. Mais si un seul ''guard bit'' est à 1, c'est signe qu'un débordement d'entier a eu lieu. Le résultat est alors remplacé par la valeur maximale supportée par le DSP (en dehors de l'accumulateur). Un DSP contient souvent une unité MAC, une ALU entière, et un décaleur séparé. Un DSP doit en effet implémenter les instructions usuelles, sur des opérandes entiers. Et cela ne concerne pas que les additions/soustractions ou les opérations logiques : les décalages/rotations sont aussi de la partie. Les DSPs intègrent donc un ''barrel shifter'', qui est séparé de l'unité MAC. Et c'est une source d'optimisation : le décaleur pour les arrondis est parfois fusionné avec le ''bareel shifter'', pour économiser des circuits. En clair, le décaleur des arrondis est sorti de l'unité MAC et est une unité de calcul comme une autre. Mais ce n'est pas systématique et de nombreux DSPs préfèrent utiliser un mini-décaleur séparé du ''barel shifter'', pour des raisons de performance. ===L'implémentation matérielle de l'unité de calcul MAC=== [[File:Chemin de données d'un DSP.png|vignette|upright=1|Chemin de données d'un DSP, avec multiplieur et additionneur séparé.]] L'implémentation d'un circuit MAC pour opérandes entiers est très simple, car on peut fusionner l'additionneur et le multiplieur en un seul circuit. Rien de surprenant, nous savons qu'un multiplieur contient un additionneur multiopérande, on peut lui ajouter de quoi faire une addition entière en plus. Cependant, la plupart des DSPs préfèrent utiliser un multiplieur séparé de l'additionneur, avec un registre entre les deux. Le registre en sortie du multiplieur a une taille deux fois plus grande que les opérandes, pour mémoriser le résultat complet de la multiplication. Pour un DSP qui manipule des opérandes de 24 bits, le registre pour les multiplications fera 48 bits, soit le double. Pour donner un exemple, les DSP Blackfin+ géraient des opérandes de 32 bits, avaient un registre de 64 bits pour le résultat de la multiplication, et utilisaient des accumulateurs de 72 bits. [[File:Chemin de données d'un DSP, avec guard bits et produit long.png|centre|vignette|upright=1.5|Chemin de données d'un DSP, avec guard bits et produit long]] Faire ainsi a plusieurs avantages. Le premier est que cela permet de pipeliner l'unité de calcul MAC. Pendant que l'additionneur traite une instruction MAC, le multiplieur s'occupe de l'instruction MAC suivante. Les DSPs avec un pipeline peuvent ainsi profiter d'une hausse de performance assez conséquente. Mais au-delà de l'usage d'un pipeline, d'autres optimisations sont rendues possibles. La première est que cela permet d'implémenter l'addition de manière assez simple. En effet, l'unité MAC peut parfois être modifiée de manière à supporter d'autres instructions que l’instruction MAC. Elles peuvent être utilisées pour faire des additions ou des multiplications seules. L'addition seule court-circuite le multiplieur, et envoie un opérande en entrée de l'additionneur. Pour cela, il faut intercaler un multiplexeur entre le multiplieur et l'additionneur. L'additionneur peut aussi être remplacé par une vraie unité de calcul entière, capable de faire des opérations bit à bit. [[File:Unité MAC modifiée de manière à supporter l'addition.png|centre|vignette|upright=2|Unité MAC modifiée de manière à supporter l'addition]] L'opérande de l'addition peut provenir de plusieurs endroits : soit d'un autre accumulateur, soit des registres d'opérandes, soit de la mémoire RAM. Si les deux opérandes sont dans deux accumulateurs, alors elles ont la même taille et sont envoyées en entrée de l'additionneur sans autre forme de procès. Mais si elles viennent des registres d'opérandes ou de la RAM, elles sont plus courtes que ce que prend en entrée l'accumulateur. Par exemple, prenons un DSP avec des opérandes 16 bits et un additionneur 40 bits. L'additionneur a une entrée reliée à l'accumulateur de 40 bits, l'autre entrée provient du multiplexeur et fait 32 bits. Un opérande de l'addition provient de l'accumulateur et fait 40 bits, l'autre est un opérande de 16 bits et doit être convertie en 32 bits. Pour cela, il y a plusieurs solutions. * La première utilise l'extension de signe, à savoir que l'opérande de 16 bits est étendue sur 32 de manière à conserver son signe. * La seconde envoie l'opérande dans les 16 bits de poids fort en entrée de l'additionneur, les 16 bits de poids faible sont mis à zéro. * Il est possible de concaténer deux registres d'opérande de 16 bits pour obtenir un opérande de 32 bits, soit la taille adéquate. ===Les unités MAC flottantes=== Précisons que tout ce qui vient d'être dit précédemment ne fonctionne que pour des opérandes entiers, pas pour des opérandes flottants. Pour les opérandes flottants, la question des arrondis est un peu différente. L'opération MAC est composée d'une multiplication flottante, suivie d'une addition flottante. La question est alors la suivante : est-ce qu'il y a un arrondi entre les deux, avec la normalisation et autres subtilités propres aux nombres flottants ? Pour gérer ce cas, il existe deux types d'instructions MAC : l'instruction MAC classique et l'instruction '''''Fused MAC''''' (FMAC). L'instruction MAC classique fait un arrondi entre les deux, l'instruction FMAC n'en fait pas. L'instruction donne des résultats plus précis, mais demande de travailler avec un résultat de multiplication plus grand de quelques bits, ce qui fait des circuits en plus. Les DSP se classent en deux sous-types : ceux qui utilisent des nombres flottants et ceux qui utilisent des nombres à virgule fixe. Les premiers DSPs utilisaient la virgule fixe. Le cas classique était des DSP utilisant des opérandes de 24 bits : 16 pour la partie entière, 8 pour la partie fractionnaire. Notons que 24 bits était la norme pour encoder de l'audio sur des CD audio, ce qui fait que les DSPs de l'époque utilisaient cette précision. Par la suite, des DSP 16 et 32 bits sont apparus, puis des DSP flottants. Les DSPs à virgule fixe disposent de mécanismes pour émuler des nombres flottants en utilisant des calculs entiers. Pour être plus précis, ils émulent des nombres flottants spéciaux, appelés '''nombres flottants par blocs''' (traduction du terme anglais ''block-floating point''). L'idée est de manipuler des nombres flottants qui ont tous le même exposant, afin de simplifier les calculs. Si plusieurs nombres flottants ont le même exposant, alors les additionner demande de simplement additionner les mantisses, les multiplier demande de multiplier les mantisses. Du moins, c'est le cas en absence de débordement d'entier, mais les DSPs ont des protections pour ça, comme les ''guard bits'' et les accumulateurs larges. Les DSPs émulent les calculs sur les flottants par blocs de la manière suivante. Les DSPs disposent d'une instruction EXP, qui calcule l'exposant et le mémorise dans un registre. Une fois l'exposant connu, ils normalisent les mantisses avec des décalages, de manière à ce que tous les opérandes aient le même exposant. Puis, ils additionnent ou multiplient les mantisses ensemble, avec des instructions MAC, MUL, ADD, SUB, DIV, etc. Une fois les calculs terminés, la mantisse du résultat est dans l'accumulateur. Elle est normalisée avec un décalage, réalisé par le ''barrel shifter'', en fonction de l'exposant calculé. La gestion des flottants par blocs peut être réalisée avec le décaleur vu plus haut, dans la section précédente. Les décalages nécessaires pour normaliser et décaler les mantisses sont réalisés par de décaleur. ===Des exemples d'unités MAC=== Le DSP TMS32010 de marque Texas Instrument disposait d'un additionneur et d'un multiplieur, couplés à trois registres : un registre accumulateur, le registre T pour un opérande, et le registre P entre le multiplieur et l'additionneur. [[File:Unité de calcul du DSP TMS32010 de marque Texas Instrument.png|centre|vignette|upright=2|Unité de calcul du DSP TMS32010 de marque Texas Instrument]] Le Motorola DSP 5600x avait deux accumulateurs, ainsi que 4 registres d'opérandes appelés X1, X2, Y1 et Y2. Les deux accumulateurs faisaient 56 bits. Les registres d'opérandes, quant à eux, pouvaient être utilisés de deux manières : soit comme 4 registres de 24 bits, soit comme 2 registres de 48 bits. L'unité MAC était capable de faire une opération MAC, une addition, ou une opération bit à bit. Pour cela, l'additionneur est précédé par une unité de calcul bit à bit, qui n'est pas utilisée quand le multiplieur l'est. En clair, l'unité bit à bit sert uniquement quand on charge les opérandes depuis les registres d'opérandes. L'additionneur est suivi par un circuit capable de faire des opérations de normalisation et d'arrondis. Le circuit intègre deux décaleurs. Le premier est situé en sortie de l'accumulateur, et permet de traduire un résultat de 56 bits en un résultat de 24 bits. Il sert aussi pour des arrondis, des opérations de normalisation et bien d'autres. L'autre décaleur est lui entre l'accumulateur et l'additionneur. Il est beaucoup plus limité et ne peut que faire quatre opérations : ne rien faire, un décalage à gauche de 1 rang, un décalage à droite de 1 rang, mettre à zéro sa sortie. L'unité MAC n'était pas pipelinée, elle faisait un calcul en un cycle. Par contre, il était possible de modifier les registres d'opérandes pendant qu'un calcul MAC était en cours. En entrée du multiplieur, il y avait deux registres non-adressabbles, qui mémorisaient les opérandes pendant un cycle d'horloge complet. Ainsi, il était possible d'écrire dans les registres d'entrée, sans pour autant que cela impacte le calcul en cours. [[File:Unité de calcul du Motorola DSP 5600x.png|centre|vignette|upright=2|Unité de calcul du Motorola DSP 5600x]] ==La microarchitecture d'un DSP== Il est intéressant de regarder comment la microarchitecture des DSPs a évoluée. Et c'est en lien avec l'évolution de leur jeu d'instruction. Les DSPs sont souvent classés en trois à cinq générations, mais les frontières entre générations varient beaucoup d'un livre à l'autre, d'un auteur à l'autre. Dans ce chapitre, nous allons juste séparer les DSPs en deux : les DSPs classiques, qu'on a détaillé plus haut, et les DSP récents qui intègrent des jeux d'instructions SIMD, VLIW ou superscalaires. Sur les anciens DSP, les instructions s'exécutaient toutes en un seul cycle d'horloge et tendaient à faire pas mal de traitements assez complexes. De nos jours, les DSPs tendent à utiliser un pipeline, ce qui fait que la contrainte "1 cycle = une instruction" est battue en brèche. ===La microarchitecture d'un DSP classique=== Un DSP contient au minimum une unité de calcul MAC avec un ''barrel shifter''. De nombreux DSPs incorporent aussi une ALU entière séparée du circuit MAC, qui est utilisée pour des additions/soustractions, opérations logiques et bit à bit. Le ''barrel shifter'' est lui utilisé pour tronquer le résultat en sortie de l'accumulateur, et pour gérer les nombres flottants par blocs, avec l'aide d'une unité dédiée aux exposants. Les DSPs intègrent des unités de calcul spécialisées dans les calculs d'adresse, qui sont regroupées avec les registres d'adresse et d'indice. Elles implémentent l'adressage modulo et bit-''reverse'', ainsi que les modes d'adressages à post- ou pré-incrément/décrément, et les modes d'adressage usuels. Il y a un banc de registre pour les registres d'adresse, un autre pour les registres d'indice, ainsi qu'une unité de calcul d'adresse spécialisée. Il y a en général deux unités de calcul d'adresse, une par opérande. [[File:Unité d'accès mémoire avec registres d'adresse ou d'indice.png|centre|vignette|upright=2|Unité d'accès mémoire avec registres d'adresse ou d'indice]] Un DSP avec un registre T est forcément connecté à une mémoire simple port. Sa microarchitecture est des plus simples. De tels DSP n'ont généralement pas d'ALU entière séparée de l'unité MAC, car ces opérations sont réalisées dans l'unité MAC elle-même. L'additionneur est remplacé par une ALU entière, un MUX permet de court-circuiter le multiplieur. Ses interconnexions sont particulièrement simples. : Nous omettrons les liaisons entre séquenceur et ALUs, utilisées pour les modes d'adressage immédiat (constantes immédiates). [[File:Microarchitecture d'un DSP avec un registre T.png|centre|vignette|upright=2|Microarchitecture d'un DSP avec un registre T]] Si on suppose au contraire que le DSP utilise une mémoire RAM multiport, on devrait avoir ceci : [[File:Microarchitecture d'un DSP avec mémoire multiport.png|centre|vignette|upright=3|Microarchitecture d'un DSP avec mémoire multiport.]] Si on suppose que le DSP utilise une architecture Harvard modifiée, et que les coefficients sont en mémoire ROM, l'intérieur du DSP devrait ressembler à ceci : [[File:Microarchitecture d'un DSP.png|centre|vignette|upright=3|Microarchitecture d'un DSP.]] ===Les DSPs avec optimisations pour l'opération ''butterfly''=== Les DSPs précédents n'incorporent pas d'optimisations pour l'opération ''butterfly''. En effet, celles-ci n'ont qu'un seul accumulateur, pas plus. Mais l'opération ''butterfly'' marche bien mieux avec deux accumulateurs. Aussi, de nombreux DSPs incorporent deux accumulateurs et quoi les utiliser au mieux. Dans le cas le plus simple, l'unité MAC est reliée à deux accumulateurs. Mais sur les '''DSPs ''Dual MAC''''', les deux accumulateurs sont couplés à deux unités MAC, avec une unité MAC par accumulateur. De tels DSPs peuvent faire deux opérations MAC par cycle d'horloge, souvent avec l'aide d'une instruction machine de multiplication/addition complexe. Pour donner un exemple, prenons le DSP TMS320-C54x, qui dispose de deux accumulateur, mais n'est pas un DSP ''dual MAC''. Il dispose de 6 unités de calcul : une unité MAC non-pipelinées, une ALU entière, un ''barrel shifter'', deux unités de calcul d'adresse, et une unité de comparaison spécialisée pour l'algorithme de Viterbi qu'on ne détaillera pas ici. L'ALU entière et le ''barrel shifter'' gèrent des opérandes de 40 bits, l'unité MAC gère des opérandes de 17 bits (16 bits, plus un bit de signe) et un résultat de 40 bits. Pour supporter des calculs flottants, le processeur incorpore un circuit dédié à la gestion des exposants, qui s'occupe des opérations de normalisation, d'arrondis et autres. Un détail important est que l'unité de calcul peut soit fonctionner comme une ALU unique de 40 bits, soit comme une ALU SIMD de 16 bits. Elle est capable de faire deux opérations sur deux opérandes de 16 bits en même temps. Pour le reste, les interconnexions entre ces unités de calcul sont très complexes. C'est presque comme si tout était connecté à avec tout le reste. Le DSP TMS320-C54x a deux accumulateurs, qui peuvent recevoir le résultat de l'unité MAC ou de l'ALU entière. Les deux accumulateurs envoient leur contenu en entrée de toutes les ALU, sauf les AGU. Le ''barrel shifter'' envoie son résultat soit en mémoire RAM, soit en entrée de l'ALU entière. Le TMS320-C54x dispose de trois bus de données, pour lire deux opérandes et écrire un résultat en un seul cycle d'horloge. Ils sont appelés CB, DB et EB, les deux bus CB et DB sont en lecture, le bus EB est un bus d'écriture. Les deux bus CB et DB envoient des opérandes à l'unité MAC, l'ALU entière et le ''barrel shifter''. Pour le bus EB des écritures, il n'est accesible qu'à travers le ''barrel shifter''. Ce qui est logique : lors de l'enregistrement en mémoire, un résultat de 40 bits doit être converti en donnée de 16 ou 32 bits, ce qui demande de faire un décalage pour éliminer les bits de poids faible. [[File:Chemin de données du TMS320C54x.png|centre|vignette|upright=2|Chemin de données du TMS320C54x]] ===Les DSPs VLIW, SIMD et superscalaires=== Les DSPs de seconde génération et au-delà, incorporent plusieurs unités de calcul MAC. De plus, celles-ci sont pipelinées pour augmenter le nombre d'opérations exécutées par cycle d'horloge. Pour les alimenter, le processeur dispose de trois méthodes : soit utiliser un jeu d'instruction VLIW, soit être un processeur superscalaire, soit utiliser des instructions SIMD. Les trois solutions sont utilisées, suivant le DSP. Et il n'est pas rare que l'on ait des DSPs qui mélangent SIMD et VLIW, ou encore SIMD et superscalarité. Les DSP les plus simples sont les '''DSP ''dual MAC''''', au nom assez parlent. Ils incorporent deux multiplieurs, voire deux unités de calcul FMAC, qui peuvent fonctionner en même temps. Des exemples de DSPs de ce type sont le Lucent DSP 16xxx ou le TMS C55x de Texas Instrument. Le Lucent DSP 16xxx contenait deux multiplieurs de 16 bits, couplés à une ALU entière et un additionneur trois-opérandes. Cela parait bizarre de ne pas avoir utilisé deux ALU entières, mais cela permet d'économiser un peu de circuit de remplacer une seconde ALU par un additionneur. L'ensemble permettait de faire deux opérations MAC par cycle. Il y avait aussi une unité de manipulation de bit, sans compter de nombreux circuits décaleurs intercalés en entrée et sortie des multiplieurs. [[File:Lucent DSP16xxx.png|centre|vignette|upright=2|Lucent DSP16xxx]] Mais les unités MAC ne sont pas seules au monde, il faut aussi tenir compte des ALU entières et du ''barrel shifter''. Les DSP ''dual MAC'' basiques ne les dupliquent pas, mais d'autre le font. Pour donner un exemple, le Texas Instruments TMS320 C62x incorpore deux multiplieurs, deux ALU entières, deux unités de calcul qui regroupent une ALU entière avec un ''barrel shifter'', et deux unités de calcul d'adresse. Le tout est associé à deux bancs de registres contenant 32 registres de 32 bits chacun. Pour les exploiter, le processeur utilisait un jeu d'instruction VLIW, où chaque faisceau VLIW regroupait 8 instructions, chacune allant sur une des 8 unité. L'ADI TigerSHARC est un processeur qui mélange SIMD et VLIW. L'idée est qu'il peut exécuter un même faisceau VLIW sur deux paquets de données. Pour cela, le processeur contient deux chemins de données identiques, qui exécutent le même instruction VLIW, mais sur des données différentes. Chaque chemin de données contient 32 registres, une unité mémoire (avec calcul d'adresse), un ''barrel shifter'', une ALU entière et un circuit MAC. Un faisceau VLIW encode 4 instructions : une instruction LOAD/STORE, une opération MAC, une opération de calcul entière et un décalage. Les DSP incorporent aussi ce que j'ai appelé du SWAR (''SIMD Within A Register'') dans le chapitre sur le parallélisme de données. L'idée est de configurer un additionneur 32 bits pour faire deux additions 16 bits à la fois. Les ALU entières des DSPs incorporent cette optimisation. Les DSPs ayant souvent des ALU entières de 40 bits, cela permet d'implémenter deux additions de 16 bits, avec des ''guard bit'' pour chaque addition. Les ''guard bits'' sont répartis équitablement entre les deux additions 16 bits. Concrètement, le résultat de 40 bits est composé de deux résultats de 20 bits, avec 4 ''guard bits'', les deux résultats étant concaténés. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les ISA optimisés pour la compilation/interprétation | prevText=Les ISA optimisés pour la compilation/interprétation | next=Les architectures actionnées par déplacement | nextText=Les architectures actionnées par déplacement }} </noinclude> 3s8elbuv4qyogue7w6ad5xlr62i004n 772102 772101 2026-09-12T18:24:37Z Mewtow 31375 /* L'usage de registres spécialisés */ 772102 wikitext text/x-wiki Les '''processeurs de traitement du signal''', sont des jeux d'instructions spécialement conçus pour travailler sur du son, de la vidéo, des images, ou toute autre forme de signal. Ils sont aussi appelés des DSP, abréviation de ''Digital Signal Processor''. Le jeu d'instruction d'un DSP est assez spécial, car il est conçu pour des applications très spécifiques. Et la conséquence est que leur jeu d'instruction est complétement à part du reste, au point où leur donner un chapitre à part est une nécessité. ==Contexte : le traitement temps réel d'un signal== Le traitement du signal regroupe tout ce qui traite de l'audio, de la vidéo, mais aussi d'autres formes de signaux plus difficiles à conceptualiser. Les cas d'utilisations les plus courant sont le traitement d'image (appareils photos), la compression et le filtrage vidéo, les cartes sons d'un ordinateur ou d'une console de jeu, les communications sans fil avec des périphériques, la téléphonie, et autres usages moins familiers (radars, imagerie médicale). Le traitement de signal était autrefois réalisé par des composants purement analogiques. Les circuits analogiques de ce type étaient utilisés dans les anciennes radios, les chaines HI-FI, les télévisions, les magnétoscopes, et bien d'autres composants électroniques moins familiers. De nos jours, le signal est traité par des processeurs numériques. Un système audio/vidéo/autres fonctionne cependant encore avec des signaux analogiques. Simplement, il y a une conversion analogique vers numérique, un traitement par un DSP, puis une conversion numérique vers analogique. [[File:DSP block diagram.svg|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP.]] [[File:Dsp bloc fr.png|centre|vignette|upright=2|Chaine de traitement de signal utilisant un DSP, en français.]] ===Un flux de données échantillonné=== Le signal sonore/vidéo/autre qui est capté est un signal analogique : il change en permanence, il n'a pas de fréquence définie. Mais ce signal est échantillonné, à savoir que l'on mesure sa valeur à une fréquence prédéterminée, appelée la '''fréquence d’échantillonnage'''. Par exemple, pour un signal sonore, la fréquence d’échantillonnage est de 44,1 kHz, 48 kHz, 96 kHz ou 192 kHz. Soit une mesure approximativement toutes les 22,6 µs, 20,83 µs, 10,4 µs, 5,2 µs. L'intensité sonore mesurée à un instant est appelée un échantillon sonore. Il existe un équivalent pour la vidéo : les échantillons sont les images à afficher à l'écran, il y en a une toutes les 1/24ème de secondes pour une vidéo à 24 FPS. [[File:Sampled.signal.svg|centre|vignette|upright=1.5|Signal échantillonné.]] Les échantillons sont généralement accumulés dans une structure de donnée en mémoire RAM, appelée une '''file'''. Il s'agit d'un paquet d'échantillon classés par ordre d'arrivée (une structure de donnée de type FIFO). Elle a une taille finie, ce qui fait que le nombre d'échantillons est prédéfini à l'avance. Quand un échantillon est ajouté dans une FIFO pleine, la donnée la plus ancienne est éliminée (elle a déjà été traitée de toute façon). Les FIFOs de ce type sont conçues à partir d'un tableau, auquel on a ajouté deux pointeurs : un pour la donnée la plus ancienne, un pour la plus récente. Pour le dire autrement, ces deux pointeurs correspondent au début de la file et à sa fin. Le début de la file correspond à l'endroit où l'on insère les nouvelles données. La fin de la file correspond à la donnée la plus ancienne en mémoire. À chaque ajout de donnée, on doit mettre à jour l'adresse de début de file. Lors d'une suppression, c'est l'adresse de fin de file qui doit être mise à jour. Ce tableau a une taille fixe. Si jamais celui-ci se remplit jusqu'à la dernière case, (ici la cinquième), il se peut malgré tout qu'il reste de la place au début du tableau : des retraits de données ont libéré de la place. L'insertion continue alors au tout début du tableau. Cela demande de vérifier si l'on a atteint la fin du tableau à chaque insertion. De plus, en cas de débordement, si l'on arrive à la fin du tableau, l'adresse de la donnée la plus récemment ajoutée doit être remise à la bonne valeur : celle pointant sur le début du tableau. Tout cela fait pas mal de travail. Les DSPs ont des modes d'adressages spécialisés pour accéder à des données dans de telles files, comme on le verra plus bas. ===Les algorithmes exécutés par un DSP=== Un DSP exécute des algorithmes très précis : un algorithme de filtrage, un algorithme de transformée de Fourier rapide, un algorithme de '''''Finite Impulse Response''''', des algorithmes de convolution, ou tout autre algorithme de traitement de signal. L'algorithme travaille sur un nombre fini d'échantillons, qui sont lus depuis la file décrite plus haut. Le jeu d'instruction d'un DSP est optimisé pour les algorithmes de traitement de signal les plus courants. Aussi, pour comprendre le jeu d'instruction d'un DSP, nous n'avons pas le choix : il faut étudier quelques algorithmes de traitement de signal. Mais rassurez-vous, pas besoin d'aller dans le détail. Nous allons voir quelques algorithmes simples, et encore : nous allons les survoler, sans expliquer pourquoi et comment ils marchent. L'exemple le plus utile pour l'étude des DSP est celui du filtre FIR (''Finite Impulse Response''). Celui-ci est assez simple sur le principe : on prend les N échantillons les plus récents, on les multiplie chacun par un coefficient, et on additionne le tout. La formule exacte ressemble à ceci : : <math>y(t) = {\sum_{n=0}^{N-1}} b_n \cdot x[t - n]</math>, avec <math>b_n</math> le coefficient de l'échantillon à l'instant t-n. [[File:FIRdrekteForm.png|centre|vignette|upright=2|Représentation graphique d'un filtre FIR. Les échantillons à l'instant n sont notés u(n), T représente le délai entre deux échantillons.]] Vous remarquerez que cet algorithme s'implémente avec une boucle, chaque itération faisant une multiplication suivie d'une addition. Si on suppose que les N échantillons sont mémorisés dans un tableau, et que les N coefficients sont dans un second tableau, alors le code devrait être le suivant : <syntaxhighlight lang="c"> int resultat = 0 ; for (i=0 ; i < N ; ++i) { resultat += coefficient[i] * echantillons[i] ; } </syntaxhighlight> Et c'est une règle pour de nombreux algorithmes de traitement de signal : ils s'implémentent avec une boucle, qui parcourt un ou plusieurs tableaux/files, l'intérieur de la boucle faisant des calculs du type a * b + c. Il est intéressant de regarder ce que donne le codé précédent, une fois compilé sur une architecture RISC. Un point important est que ce code manipule quatre variables par itération de boucle : les deux opérandes de la multiplication, le résultat de la multiplication, et la variable d'accumulation resultat. On va placer les deux opérandes dans les registres R0 et R1, le résultat de la multiplication dans le registre R2, et la variable resultat dans le registre R3. Le compteur de la boucle est mémorisé dans le registre R7. Voici une sorte de pseudo-code ASM qui ressemble pas mal à ce que sortirait un compilateur, avec pas mal de simplifications de notations pour faire passer la pilule. Les commentaires indiquent qu'une étape de calcul d'adresse est réalisée, en utilisant plusieurs instructions. <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> En clair, on charge les deux opérandes dans un registre, on multiplie, on additionne, puis on effectue de quoi gérer la boucle. La '''transformée de Fourier rapide''' est un algorithme un peu plus complexe que le précédent, mais particulièrement utile en traitement de signal. Sans rentrer dans les détails d'implémentation, il agit sur des nombres complexes, qui sont composés d'une partie réelle et la partie imaginaire. Les parties entières et imaginaires sont encodés avec deux nombres entiers ou flottants. L'algorithme utilise un tableau de nombres complexes, qui est en pratique séparé en deux tableaux séparées, avec un tableau pour les parties réelles et un autre pour les parties imaginaires. La transformée de Fourier rapide est composée d'une boucle qui applique à chaque itération une opération dite ''butterfly''. Elle prend en entrée un nombre complexe, et fournit un autre nombre complexe en sortie. Elle applique des multiplications/additions sur deux variables qu'on appellera A et B. À chaque itération de boucle, l'opération ''butterfly'' exécute le calcul suivant : : <math>A = A + B \times \text{coefficient A}</math> : <math>B = B + A \times \text{coefficient B}</math> Retenez bien que cette opération s'appelle l'opération ''butterfly'', car les DSPs intègrent des optimisations dédiées pour cette opération. ===Les contraintes dites ''temps réel''=== Le DSP exécute l'algorithme de traitement de signal entre deux arrivées d'échantillon. Précisément, le DSP est commandé par une interruption. Lorsqu'un nouvel échantillon est disponible, le CAN envoie une interruption au DSP pour le prévenir. Le DSP lit alors l'entrée correspondant au CAN et récupère cet échantillon dans un registre. Il met alors à jour la file des échantillons, met à jour le pointeur qui indique le début de la file. Puis il exécute l'algorithme de traitement de signal. Une fois terminé, il envoie le résultat au CNA. Il y a donc un délai temporel très strict à respecter : le traitement doit être fini avant l'arrivée du prochain échantillon. Cette contrainte dite ''temps réel'' font qu'il est préférable de ne pas utiliser de mémoire virtuelle, d'interruptions, ou beaucoup d'autres fonctionnalités courantes sur les processeurs modernes. Par exemple, les branchements sont une source de problèmes pour le ''temps réel''. Le temps d'exécution du code change selon que le branchement est pris ou non, les deux codes exécutés suivant que la condition est valide ou non ne faisaient pas forcément le même temps. En conséquence, les DSP incorporent des instructions à prédicats pour remplacer les branchements hors-boucles, et ajoutent des techniques pour accélérer les boucles. La présence de caches est une autre source de problèmes dans les systèmes ''temps réel'', car le temps d'exécution dépend de si les accès mémoire font des succès ou des défauts de cache. En conséquence, les premiers DSP commercialisés n'utilisaient pas de mémoire cache pour les données, et se limitent à des caches d'instructions. L'absence de cache est compensée l'usage de ''local store'', dans lesquels des échantillons sont accumulés. Les ''local store'' sont souvent alimentés par des transferts DMA, qui font des copies ''local store'' vers mémoire RAM ou inversement. Les ''local store'' ne posent pas de problèmes pour le temps réel, car le programmeur sait à tout moment quelles sont les données présentes dans un ''local store'', ce qui n'est pas le cas dans un cache. De même, beaucoup d'optimisations posent problème avec le temps réel, parce qu'elles rendent le temps d'exécution plus variable. L'usage d'un pipeline est parfaitement possible, mais sous certaines conditions. La plus importante est qu'il faut utiliser l'émission dans l'ordre. Pas question d'utiliser d'exécution dans le désordre, de prédiction de branchement ou toute autre optimisation du genre. Dans les faits, presque tous les DSP commercialisés après les années 90 utilisent un pipeline. L'usage de l'émission multiple est parfaitement possible, et de nombreux DSP récents sont soit superscalaires, soit des CPU VLIW. La seconde solution est plus souvent utilisée, la compatibilité matérielle n'étant pas importante sur les DSPs. ==Le jeu d'instruction d'un DSP== Les DSPs incorporent de nombreuses optimisations spécifiques, pour optimiser les algorithmes de traitement de signal. Et ces optimisations peuvent se comprendre assez facilement quand on analyse le code d'un filtre FIR. Pour rappel, il s'agit du code assembleur vu plus haut, que je reproduis ici : <syntaxhighlight lang="asm"> // Calcul adresse coefficient // Calcul adresse opérande LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 INC R7 ; CMP R7 N ; BRANCH adresse de début de la boucle ; </syntaxhighlight> Il est intéressant d'étudier comment la boucle précédente peut être optimisée, avec un jeu d'instruction adapté, car ces optimisations se généralisent à tous les algorithmes de traitement de signal. Optimiser la boucle précédente demande d'optimiser plusieurs points : optimiser les calculs d'adresse, optimiser les lectures, optimiser les calculs arithmétiques, optimiser la boucle elle-même (les trois instructions de fin). Les DSPs incorporent des optimisations pour chaque point, voyons lesquelles. ===L'optimisation des boucles sur un DSP=== Premièrement, on doit réduire le temps passé dans les tests et branchements au minimum. Sans optimisations particulières, il faut incrémenter l'indice, faire la comparaison, et le branchement conditionnel. L'intérieur de la boucle consiste en deux lectures, une addition et une multiplication, soit quatre instructions. Si on fait les comptes, un peu moins de la moitié des instructions est passé à gérer la boucle FOR. Et de nombreuses optimisations visent à réduire grandement les couts liés à la boucle FOR. En premier lieu, le nombre de répétitions restantes est mémorisé dans un '''registre compteur de boucle'''. Il est initialisé avant de la boucle FOR, et il est décrémenté à chaque itération. La boucle se termine quand ce registre atteint zéro. En soit, le registre compteur de boucle n'est pas une optimisation, il ne permet pas de gagner des cycles d'horloge. Par contre, sa présence permet d'implémenter des optimisations, qu'on va détailler dans ce qui suit. Première optimisation : les DSP ont des instructions qui effectuent un test, un branchement et une décrémentation du registre compteur de boucles. L'instruction fusionne donc un test et un branchement, comme c'est le cas sur certains processeurs RISC ou CISC, mais avec une petite subtilité. Le test et le branchement sont adaptés pour tenir compte du registre compteur de boucle. Le test en question vérifie si ce compteur de boucle vaut zéro et effectue un branchement si ce n'est pas le cas. De plus, la mise à jour du registre compteur de boucle est elle aussi réalisée automatiquement. On économise donc une décrémentation. La seconde optimisation est un peu différente. Il s'agit des techniques de '''''zero overhead looping''''', qui permettent d'exécuter des boucles sans avoir à utiliser de branchements, ou presque. Pour rappel, celles-ci utilisent une instruction REPEAT, qui précise que les N instructions suivantes doivent s'exécuter en boucle, M fois. Typiquement, elles permettent d'implémenter des boucles FOR dont le nombre d’exécution est connu à l'avance. L'instruction REPAET/LOOP utilise le registre compteur de boucle pour savoir combie d'itérations il lui reste. Une variante précise deux adresses, qui délimitent les instructions de la boucle : une adresse pour le début de la boucle, une adresse pour la fin. L'implémentation hardware est alors assez simple : quand le ''program counter'' atteint l'adresse de fin, il est réinitialisé à l'adresse de début. Avec ces techniques, le code ASM d'un filtre FIR devient ceci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MUL RO , R1 -> R2 ADD R2 , R3 -> R3 </syntaxhighlight> Autre fonctionnalité : les '''instructions autorépétées''', des instructions qui se répètent automatiquement tant qu'une certaine condition n'est pas remplie. L'instruction effectue le test, le branchement, et l’exécution de l'instruction proprement dite en un cycle d'horloge. Cela permet de gérer des boucles dont le corps se limite à une seule instruction. Cette fonctionnalité a parfois été améliorée en permettant d'effectuer cette répétition sur des suites d'instructions. Les DSPs incorporent aussi des caches d'instructions, afin de gagner de précieux cycles d'horloge. En général, les caches d'instructions en question sont spécialisés dans l'exécution de petites boucles, qui tiennent entièrement dans le cache. ===Les opérations arithmétiques d'un DSP=== Voyons maintenant quelles optimisations peuvent être réalisées pour les opérations arithmétiques. Le calcul à faire est en soi très simple : une multiplication suivie d'une addition. Aussi, vous ne serez pas étonnés d'apprendre que tous les DSP supportent les instructions ''Multiply and Add'' (MAD), qui effectuent une multiplication suivie d'une addition. Pour rappel, la première travaille sur des opérandes entiers, la seconde des opérandes flottants. Utiliser une instruction MAD simplifie donc la boucle, sans compter que cela fait économiser un registre, vu qu'on n'a pas besoin de stocker le résultat de la multiplication. Et non seulement les DSPs intègrent une instruction MAD, mais ils ont aussi une unité de calcul dédiée à cette opération. Un autre point important est que l'addition sert juste à ajouter le produit à une variable temporaire. A chaque itération de la boucle, la variable est incrémentée avec le produit a*b. Il s'agit d'un calcul d'accumulation, qui se marie très bien avec la présence d'un registre accumulateur. Les DSPs incorporent donc un registre accumulateur dans l'unité de calcul MAD, ce qui en fait des architectures à accumulateur. Les instructions MAD lisent un opérande depuis l'accumulateur et mémorisent leur résultat dedans. Il s'agit donc d'instructions MAD un peu spéciales, appelées ''multiply and accumulate'' (MAC) ou ''fused multiply and accumulate'' (FMAC). Nous parlerons d'instructions MAC dans ce qui suit. [[File:Instruction MAD avec accumulateur d'un DSP 01.png|centre|vignette|upright=2|Instruction MAD avec accumulateur d'un DSP]] Avec l'usage d'une instruction MAC, le code d'un filtre FIR devient celui-ci : <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois // Calcul adresse opérande // Calcul adresse coefficient LOAD (adresse opérande N) -> R0 ; LOAD (adresse coefficient N) -> R1 ; MAC RO , R1 </syntaxhighlight> De nombreux DSPs utilisent deux accumulateurs, pour accélérer l'opération ''butterfly'' des transformées de Fourier rapides. Mieux que ça : ils intègrent une instruction de multiplication complexe qui effectuent deux opérations MAC, sur les deux accumulateurs, en une seule instruction. Les instructions MAC n'ont besoin d'adresser que deux opérandes : celles de la multiplication. L'opérande de l'addition est dans un accumulateur adressé implicitement. Du moins, s'il y a un seul accumulateur. De nombreux DSPs ont entre 2 et 8 accumulateurs, même si la norme est à 2 accumulateurs. Dans ce cas, les accumulateurs étant séparés des autres registres, son adressage est un peu particulier. Les accumulateurs ont des numéros séparés des autres numéros/noms de registres. {|class="wikitable" |+ Encodage d'une instruction MAC |- ! Opcode !! Premier opérande !! Second opérande !! Opérande addition/résultat |- | Opcode || Numéro de registre ou adresse mémoire || Numéro de registre ou adresse mémoire || Numéro d'accumulateur |- | Un octet, environ || Variable || Variable || 1 à 3 bits, selon le nombre d'accumulateurs |} ===Les modes d'adressage d'un DSP=== Une autre source d'optimisation est liée aux calculs d'adresse. Les échantillons ne sont pas stockés dans un tableau, mais dans une file. La différence n'est pas énorme, car les files sont souvent implémentées par des tableaux, associés à deux pointeurs : un qui donne la position de la donnée la plus ancienne, un autre pour la donnée la plus récente. [[File:Fonctionnement d'une file - 1.png|centre|vignette|upright=2|Fonctionnement d'une file.]] Le tableau commence à être rempli à partir de sa première case, d'indice 0. Les données accumulées ensuite sont ajoutées dans la case d'indice 12, puis 2, puis 3, etc. Les données devenues inutiles sont retirées de la FIFO, ce qui laisse des vides, qui peuvent être réutilisées par la suite. Quand on arrive à la fin du tableau, le remplissage recommence à partir du début du tableau, si des espaces vides ont été libérés. Voici un exemple : {| |- |[[File:Circular buffer - XX123XX with pointers.svg|vignette|upright=1.5|Circular buffer - XX123XX with pointers]] |- |[[File:Circular buffer - XX1234X with pointers.svg|vignette|upright=1.5|Circular buffer - XX1234X with pointers]] |- |[[File:Circular buffer - XXX234X with pointers.svg|vignette|upright=1.5|Circular buffer - XXX234X with pointers]] |- |[[File:Circular buffer - XXX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - XXX2345 with pointers]] |- |[[File:Circular buffer - 6XX2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6XX2345 with pointers]] |- |[[File:Circular buffer - 67X2345 with pointers.svg|vignette|upright=1.5|Circular buffer - 67X2345 with pointers]] |- |[[File:Circular buffer - 6782345 with pointers.svg|vignette|upright=1.5|Circular buffer - 6782345 with pointers]] |} Les DSP tendent à utiliser des files de taille fixe, ce qui fait que le remplissage ne s'arrête pas quand la file est pleine. À la place, le nouvel échantillon remplace l'échantillon le plus ancien. Il n'y a donc pas vraiment besoin d'utiliser deux pointeurs, car on est certain que la file sera pleine en permanence et que ce remplacement se fera sans douleur. Une file sur un DSP s'implémente donc en utilisant trois pointeurs : un pour l'adresse de départ du tableau en mémoire, un autre pour l'adresse de fin du tableau, et un pointeur qui pointe vers la donnée la plus ancienne/récente. [[File:Circular buffer - 6789AB5 full.svg|centre|vignette|upright=2|File telle qu'utilisée sur un DSP.]] En clair, les files sont des tableaux dans lesquels la position des échantillons est décalée. La différence est mineure, mais elle fait que des calculs d'adresse sont requis pour déterminer à quel indice lire dans le tableau. Pour éviter cela, les DSPs intègrent des modes d'adressage spécialisés, conçus pour fonctionner au mieux avec les files mentionnées plus haut. Déjà, les files sont implémentées avec des tableaux, ce qui fait que les modes d'adressages indicés sont une nécessité absolue. Déjà, les DSP supportent l'adressage "Base + Indice", qui permet de grandement simplifier les calculs d'adresse pour une file. L'adresse de base utilisée n'est pas l'adresse de base du tableau, mais celle de la donnée la plus récente ou la plus ancienne. L'idée est que l'échantillon le plus récent est celui d'indice zéro, le précédent celui d'indice 1, celui encore précédent est d'indice 2, etc. Les DSPs anciens/basiques étant des architectures à accumulateur, ils incorporent pour cela des '''registres d'indice''', et éventuellement des '''registres d'adresse''' pour mémoriser l'adresse de base. Une autre optimisation est l'usage de modes d'adressage avec post- ou pré-incrément/décrément. L'idée est que la lecture met à jour automatiquement l'indice utilisé, afin d'économiser une instruction d'incrémentation ou une addition. La lecture qui lit un opérande en mémoire RAM incrémente alors automatiquement l'indice utilisé dans l'adressage "Base + Indice". Cependant, faire ainsi pose un petit problème : que faire quand on atteint la fin du tableau ? En théorie, on devrait reprendre au tout début du tableau. Mais l'adressage "Base + Indice" ne permet pas de faire cela automatiquement. Sans optimisations, on devrait faire un test et un branchement avant chaque lecture, pour gérer ce cas. Mais les DSPs incorporent un mode d'adressage spécialisé, qui permet de gérer automatiquement ce cas problématique, directement dans la lecture elle-même ! Il s'agit du '''mode d'adressage « modulo »'''. Si lors d'une incrémentation, on dépasse l'adresse de fin du tableau, l'adresse est réinitialisée pour pointer sur l'adresse de début du tableau. Il garantit que l'adresse reste dans la file et n'en déborde pas. Suivant les DSP, le mode d'adressage modulo est géré différemment. La méthode la plus évidente utilise deux registres : un pour stocker l'adresse de début du tableau et un autre pour l'adresse de fin. Une solution alternative n'utilise pas l'adresse de fin, mais la taille/longueur du tableau. Cette dernière se marie bien avec des registres d'indices : la longueur du tableau est comparée avec l'indice courant, pour vérifier si l'adresse dépasse la fin du tableau. Une seconde méthode utilise un registre « modulo », qui stocke la taille du tableau. Il est associé à un registre d'adresse pour l'adresse/indice de l’élément en cours. Vu que seule la taille du tableau est mémorisée, le processeur ne sait pas quelle est l'adresse de début du tableau, et doit donc ruser. La ruse ne fonctionne que pour des files/tableaux de petite taille. L'adresse est alors alignée sur un multiple de 64, 128, ou 256 octets. Cela permet ainsi de déduire l'adresse de début de la file : c'est le multiple de 64, 128, 256 strictement inférieur le plus proche de l'adresse manipulée. Un DSP a souvent plusieurs copies de chaque registre d'adresse/indice. La raison est que cela permet de gérer plusieurs files. Il faut dire qu'un DSP exécute souvent plusieurs algorithmes de traitement de signal à la suite. Par exemple, il est possible d'avoir un filtre FIR suivi d'un filtre d'antialiasing, suivi d'un algorithme de ''Fast Fourier Transform'', et ainsi de suite. Certains de ces algorithmes, comme la ''Fast Fourier Transform'', se font en plusieurs étapes enchainées les unes à la suite des autres. Et chaque étape a son propre ensemble d'échantillons, donc sa propre file. Et le DSP peut gérer ces différentes files nativement. Le mode d'adressage modulo semble assez spécialisé, mais sachez que les DSPs supportent des modes d'adressages encore plus spécialisés, utilisables seulement par un ou deux algorithmes triés sur le volet ! L''''adressage à bits inversés''' (''bit-reverse'') a été inventé pour accélérer les algorithmes de calcul de transformée de Fourier rapide, un « calcul » très courant en traitement du signal. Cet algorithme lit des échantillons dans un tableau, et fournit des résultats dans un autre tableau. Seul problème, l'ordre des résultats dans le tableau d'arrivée est assez spécial. Par exemple, pour un tableau de 8 cases, les données arrivent dans cet ordre : 0, 4, 2, 6, 1, 5, 3, 7. L'ordre semble être totalement aléatoire. Mais il n'en est rien : regardons ces nombres une fois écrits en binaire, et comparons-les à l'ordre normal : 0, 1, 2, 3, 4, 5, 6, 7. {|class="wikitable" |- !Ordre normal!!Ordre Fourier |- ||000||000 |- ||001||100 |- ||010||010 |- ||011||110 |- ||100||001 |- ||101||101 |- ||110||011 |- ||111||111 |} Comme vous le voyez, les bits de l'adresse Fourier sont inversés comparés aux bits de l'adresse normale. Inverser les bits d'une adresse peut être fait avec des opérations bit à bit, des décalages et rotations, mais cela prendrait beaucoup d'instructions. Il est possible d'imaginer une instruction REVERSE qui inverse les bits d'une adresse. Ce serait là une solution fort intéressante, que certains DSPs doivent sans doute implémenter. Mais beaucoup de DSPs préfèrent utiliser un mode d’adressage qui inverse tout ou partie des bits d'une adresse mémoire : l'adressage ''bit-reverse'' mentionné plus haut. Une autre solution utilise un adressage indicé, mais qui calcule les adresses différemment. Il suffit, lorsqu'on ajoute un indice à l'adresse, de renverser la direction de propagation de la retenue lors de l'addition. Certains DSP disposent d'instructions pour faire ce genre de calculs. ==L'architecture mémoire d'un DSP== Les DSPs ont une architecture mémoire particulière. Par architecture mémoire, je veux dire par là que leur hiérarchie mémoire est particulière. Déjà, ils n'ont généralement pas de caches de données, car celui-ci n'est pas compatible avec le temps réel. Par contre, ils tendent à compenser en utilisant des ''local store''. Si un DSP ne possède généralement pas de cache pour les données, il a parfois un cache d'instructions pour accélérer l'exécution des boucles. ===L'usage de registres spécialisés=== Les DSPs se passent de registres généraux, car les algorithmes de traitement de signal n'en ont pas besoin. Vous remarquerez que le code d'un filtre FIR n'utilise pas beaucoup de registres, et ce d'autant plus si on utilise des instructions MAC et un registre accumulateur. Et cela se généralise aux autres algorithmes de traitement de signal. Mais surtout, les conditions pour utiliser des registres ne sont pas réunies. Pour rappel, les registres servent dans deux situations. La première est quand un opérande est lu par plusieurs instructions différentes. Dans ce cas, mieux vaut copier l'opérande dans un registre, au lieu de la relire plusieurs fois en mémoire RAM. La première utilisation a un cout, mais les suivantes sont amorties. Mais les algorithmes de traitement de signal ne réutilisent pas leurs opérandes. Quand un opérande est chargé depuis la mémoire RAM, elle sera utilisée une seule fois. Un autre usage des registres est lié aux résultats des instructions. En général, le résultat d'une instruction est utilisé comme opérande par d'autres instructions, au moins une. Ainsi, il vaut mieux enregistrer ce résultat dans un registre, histoire que sa lecture en tant qu'opérande se fasse rapidement. Mais sur les DSPs, ce transfert à l'instruction suivante est le fait du registre accumulateur ! A lui seul, il prend en charge cette réutilisation des résultats. A la rigueur, pour certains algorithmes, un seul accumulateur n'est pas suffisant. Mais en utiliser 2 ou 3 accumulateurs suffit généralement à résoudre totalement ce problème. Cependant, il y a plusieurs situations qui mériteraient d'utiliser des registres : les calculs d'adresse, ainsi que les compteurs de boucle. Mais pour ces deux cas, les DSPs préfèrent utiliser des registres spécialisés. Ils intègrent ainsi des registres pour les adresses, reliés à une unité de calcul d'adresse dédiée. Idem pour les compteurs de boucle, qui ont des registres dédiés, afin de simplifier l'implémentation du ''zero-overhead looping''. Les registres d'un DSP ne correspondent donc à rien de familier à ce stade du cours, ils sont vraiment à part du reste. Cette spécialisation des registres a de nombreuses conséquences. Certaines instructions ne sont utilisables que sur certains types de registres, et il en est de même pour les modes d'adressage. Certaines instructions d'accès mémoire peuvent prendre comme destination ou comme opérande un nombre limité de registres, les autres leur étant interdits. Cela permet de diminuer le nombre de bits nécessaire pour encoder l'instruction en binaire. Mais cette spécialisation des registres pose de nombreux problèmes pour les compilateurs, qui ont du mal à utiliser correctement les modes d'adressages spécialisés, ainsi qu'à utiliser correctement les registres. Il n'est pas étonnant que les DSP aient longtemps été programmés en assembleur, et il n'est pas rare qu'ils le soient toujours. Par contre, l'usage de registres spécialisés permet des optimisations très importantes. Les DSPs modernes sont capables de faire deux calculs d'adresse, une opération MAC, et un branchement de boucle en un seul cycle d'horloge. Le branchement est réalisé via ''zero overhead looping'', les calculs d'adresse le sont via les modes d'adressage adéquats. Si l'indice de boucle, les adresses et opérandes étaient dans un banc de registre unique, alors celui-ci devrait avoir entre 5 et 10 de ports de lecture. En utilisant des bancs registres séparés, on peut se débrouiller avec seulement deux ports de lecture par banc de registre, voire moins : deux ports de lecture pour les registres d'opérandes, un registre d'indice de boucle séparé, deux-trois ports de lecture pour le banc de registre pour les adresses, etc. ===La lecture des opérandes pour l'instruction MAC=== Le reste de l'architecture mémoire d'un DSP est assez bizarre : ils utilisent des architectures Harvard, sont reliés à des mémoires multiports, n'ont pas de registres généraux, et j'en passe. Ces particularités visent à exécuter des instructions MAC rapidement. En théorie, les instructions utilisant un accumulateur sont de type ''load-op'' : un opérande est lu depuis l'accumulateur, l'autre depuis la mémoire RAM. Mais autant cela marche bien pour des instructions à deux opérandes, autant il y a un problème pour les instructions MAC. Vu que ce sont des instructions triadiques, il faut lire les deux opérandes de la multiplication depuis la mémoire RAM. Et ce n'est pas possible avec une architecture classique. La solution la plus simple lit les deux opérandes un par un, depuis la mémoire RAM. Il s'agit d'une solution assez générale, qui marche aussi pour d'autres algorithmes que les filtres FIR. Et cela demande d'adapter le processeur pour gérer la situation. La première solution ajoute un registre pour mémoriser un des opérandes de la multiplication, situé juste avant l'unité de calcul MAC, que nous nommerons le '''registre T'''. Le registre T est adressé implicitement, tout comme l'accumulateur. Une instruction MAC a juste besoin de connaitre l'adresse de la seconde opérande. Cette solution a beaucoup été utilisée sur les tout premiers DSP, notamment ceux de la marque Texas Instrument. Elle est de moins en moins utilisée de nos jours. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois LOAD RA0 ; // copie dans le registre T, instruction avec mode d'adressage en post-incrément MAC RA1 // instruction avec mode d'adressage en post-incrément </syntaxhighlight> [[File:Implémentation de l'instruction MAC avec un registre d'opérande.png|centre|vignette|upright=2|Implémentation de l'instruction MAC avec un registre d'opérande]] Une solution plus élaborée ne se contente pas d'ajouter un seul registre T, mais plusieurs registres pour les opérandes. Quelques DSPs utilisent cette solution, même s'ils sont assez minoritaires. Les DSPs avec des registres pour les opérandes se débrouillent donc avec moins d'une dizaine de registres, généralement 2 ou 4. La raison à cela est que les algorithmes de traitement de signal n'ont pas besoin de plus, comme on l'a dit plus haut. Il est possible de transférer les données de l'accumulateur vers ces registres d'opérandes, mais cela ne sert pas très souvent. De plus, cela demande de faire un arrondi, car les registres sont plus petits que l'accumulateur. La majorité des DSPs n'utilise pas les deux solutions précédentes. A la place, ils préfèrent se passer de registres pour les opérandes. Les deux opérandes sont lus directement dans la mémoire RAM, en même temps ! En clair, les instructions des DSPs peuvent faire plusieurs accès mémoire simultanés. L'instruction MAC est alors une pure instruction ''load-op'', mais adaptée à l'usage de trois opérandes. En utilisant les modes d'adressage adéquats, l'instruction MAC fait tout : elle calcule les adresses modulo, lit des opérandes depuis la mémoire RAM/ROM, puis fait l'opération MAC. Avec cette solution, le code d'un filtre FIR devient le suivant. Vous remarquerez qu'il se résume à une instruction MAC et une instruction de ''zero overhead looping''. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAD RA0 , RA1 </syntaxhighlight> La mémoire RAM doit être adaptée pour faire plusieurs accès mémoire par cycle, ce qui implique d'utiliser une mémoire multiport, pour gérer nativement plusieurs accès par cycle. Cette solution a l'avantage de fonctionner pour d'autres algorithmes que les filtres FIR, et est en quelque sorte plus générale. Les deux solutions peuvent être utilisées en même temps. Par exemple, le DSP TMS320-C54x incorpore deux ''local store'' : un ''local store'' double port pour les opérandes, un deuxième pour écrire les résultats. [[File:Architecture mémoire des DSP.png|centre|vignette|upright=2|Architecture mémoire des DSP.]] Une autre solution, qui marche parfaitement pour les filtres FIR, utilise deux mémoires séparées : une qui contient les échantillons, une autre pour les coefficients. Les deux RAMs peuvent être accédées en parallèle, ce qui permet de charger les deux opérandes d'une multiplication en même temps. La mémoire pour les coefficients peut-être une mémoire ROM dédiée, et pas une mémoire RAM. Utiliser une RAM pour les coefficients est utile si le filtre change au cours du temps, mais une ROM suffit si elle peut mémoriser tous les coefficients nécessaires. [[File:Architecture mémoire des DSP avec deux mémoires séparées.png|centre|vignette|upright=2|Architecture mémoire des DSP avec deux mémoires séparées]] ===L'usage d'une architecture Harvard modifiée=== Les solutions précédentes peuvent être améliorées, voire combinées, en utilisant une architecture Harvard modifiée. Pour rappel, une architecture Harvard permet de lire des constantes depuis la mémoire ROM. L'idée est que les coefficients d'un filtre FIR sont chargées depuis la mémoire ROM, et non la mémoire RAM. Et quand je dis la ROM, c'est sous-entendu : celle qui contient aussi le programme à exécuter. La solution est praticable, car les algorithmes de traitement de signal sont assez courts et utilisent assez peu de coefficients (moins d'un millier), ce qui fait que le programme et les coefficients rentrent tous deux dans la mémoire ROM. Elle est utilisée sur les DSPs sans pipeline, ou avec. Elle donne cependant des gains en performance immédiats sur les DSPs sans pipeline. Mais surtout, elle permet d'éliminer le besoin d'avoir une mémoire multiport. Ainsi, pour une instruction MAC d'un filtre FIR, un opérande est lu depuis la ROM, la seconde opérande est lue depuis la mémoire RAM, la troisième est lue depuis l'accumulateur, et le résultat est mémorisé dans l'accumulateur. Au final, on fait bien un seul accès en mémoire RAM par instruction MAC. Le chargement des deux opérandes est intégré dans l'instruction MAC, avec les modes d'adressage adéquats. Typiquement, le DSP incorpore des registres d'adresse séparés pour la ROM et pour la RAM, avec des unités de calcul d'adresse séparées. <syntaxhighlight lang="asm"> LOOP N X // répète les X instructions suivantes, N fois MAC RA-ROM , RA-RAM // RA-ROM est le registre d'adresse pour la ROM, RA-RAM celui pour la RAM </syntaxhighlight> Utiliser une architecture Harvard modifiée fonctionne bien pour implémenter des filtres FIR et de nombreux algorithmes de traitement de signal, mais elle est peu flexible. Avec cette solution, un des opérandes doit être constant et placé en ROM. Si jamais on souhaite utiliser une donnée variable, cette solution ne marche plus. Mais cela ne signifie pas que l'implémentation est impossible. Il suffit de rajouter le registre T ou les registres d'opérande vus plus haut, pour compenser. [[File:Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.png|centre|vignette|upright=2|Implémentation de l'instruction MAC sur un DSP avec architecture Harvard modifiée, plus général.]] ===Le contrôleur DMA intégré à un DSP=== Un point important est que les écritures dans le ''local store'' ou la RAM ne passe pas par le DSP, histoire de lui économiser du travail. Les échantillons sont écrits dans le ''local store'' ou la RAM en utilisant le ''Direct Memory Access''. Le DSP contient pour cela un contrôleur DMA, qui transfère les échantillons nécessaires du convertisseur analogique-numérique, vers la mémoire RAM et/ou le ''local store''. Il faut absolument éviter que le DSP et le contrôleur DMA se marchent sur les pieds. Pas question qu'ils accèdent en même temps à la mémoire RAM ou au ''local store''. Et il faut éviter absolument que le contrôleur DMA monopolise la RAM et laisse le DSP patienter trop longtemps, idem pour le cas inverse. La majorité des DSPs intègre des techniques d'arbitrage du bus mémoire assez complexes. Une solution alternative, elle aussi très utilisée, dédie un port mémoire au contrôleur DMA. Le contrôleur DMA accède à la RAM via son propre port mémoire dédié, en même temps que le processeur, les deux peuvent faire un accès mémoire en même temps. Plus besoin d'arbitrer le bus mémoire. [[File:DSP avec controleur DMA.png|centre|vignette|upright=2.5|DSP avec contrôleur DMA.]] ==L'instruction MAC et l'unité de calcul associée== Les DSP intègrent une unité de calcul dédiée pour l'instruction MAC. Elle contient un multiplieur, un additionneur, et un accumulateur, ainsi que d'autres circuits. Cette unité de calcul devrait en théorie être abordée dans une section sur la microarchitecture d'un DSP. Cependant, de nombreux détails de cette unité de calcul sont exposés au programmeur. Notamment, l'accumulateur a quelques particularités qui sont spécifiques au traitement de signal, que le programmeur voit. Voyons lesquelles. ===Les accumulateurs larges et leurs ''Guard Bits''=== Les DSPs ont des besoins en termes de précision plus importants que sur un ordinateur classique. Il n'est pas acceptable de perdre en qualité d'image ou sonore, parce que le processeur a fait un arrondi un peu trop visible. Et ces arrondis ou troncatures sont très fréquents avec des registres généraux, alors qu'on peut les éviter avec des accumulateurs. Voyons comment. Pour rappel, les multiplications donnent un résultat deux fois plus grand que leurs opérandes. Multipliez deux opérandes de 16 bits, le résultat en fera 32. Sur un ordinateur normal, les résultats sont tronqués pour rentrer dans les registres généraux. Par exemple, sur un processeur 32 bits, le résultat d'une multiplication est tronqué, on ne garde que les 32 bits de poids faible, en espérant qu'aucun débordement n'aura lieu. A la rigueur, certains processeurs permettent d'utiliser deux registres de 32 bits : un pour les 32 bits de poids faible du résultat, un autre pour les 32 bits de poids fort. Mais c'est assez rare. À l'opposé, les DSPs utilisent des accumulateurs de grande taille capables de mémoriser le résultat complet d'une multiplication. Il faut noter que le problème a aussi lieu pour l'addition, après la multiplication. Pour une addition, le résultat fera un bit de plus que les opérandes : additionnez deux opérandes de 32 bits, le résultat en fera 33. Vu que le DSP effectue une série d'additions consécutives, le résultat final aura facilement une dizaine de bits en plus, parfois plus, le nombre exact dépendant des opérandes et du nombre d'itérations de la boucle. Pour éviter les débordements d'entiers liés à l'addition, les accumulateurs contiennent souvent 4 à 8 bits de plus que le résultat de la multiplication. Les bits supplémentaires sont appelés des '''''guard bits'''''. Pour donner un exemple, les DSPs de 24 bits ont souvent des accumulateurs de 56 bits : 48 bits pour le résultat de la multiplication, plus 8 ''guard bits''. [[File:Instruction MAD avec accumulateur d'un DSP, avec guard bits.png|centre|vignette|upright=2|Chemin de données d'un DSP, avec guard bits et produit long]] La présence de ''Guard bits'' fait que la gestion des débordements d'entier est fort différente sur les DSPs, comparé aux autres processeurs. De fait, les DSP utilisent souvent l'arithmétique saturée, car c'est assez naturel quand on manipule un signal qui peut... saturer ! Quand un signal sonore sature, cela veut dire que l'intensité sonore dépasse le maximum représentable. En clair, l'intensité sonore dépasse le maximum encodable avec un entier/flottant, il y a un débordement entier/flottant. Si on traitait ce débordement en ne conservant que les bits de poids faible du résultat, un son qui sature donnerait un son très faible, ce qui n'est pas le comportement attendu. Il est plus naturel de mettre le son à la valeur maximale représentable. Les DSP les plus simples n'utilisent que l'arithmétique saturé, mais d'autres plus complexes permettent de configurer si on utilise l'arithmétique saturée ou non. Certains permettent d'activer et de désactiver l'arithmétique saturée, en modifiant un registre de configuration du processeur. D'autres fournissent chaque instruction de calcul en double : une en arithmétique modulaire, l'autre en arithmétique saturée. ===Le décaleur pour les arrondis=== L'accumulateur a donc une taille bien plus grande de celle des opérandes. Typiquement, les opérandes sont soit lues depuis la mémoire RAM, soit depuis des registres pour les opérandes. Dans les deux cas, l'accumulateur est plus large que les registres ou le bus de données. Lorsque les données quittent l'accumulateur, elles doivent donc être tronquées pour rentrer dans l'adresse/registre de destination. Pour cela, l'accumulateur est suivi par un ''barrel shifter'', qui décale le résultat pour éliminer les bits en trop. [[File:Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.png|centre|vignette|upright=2|Unité de calcul d'un DSP, avec un décaleur pour les arrondis finaux.]] Le décaleur peut aussi prendre en charge d'arithmétique saturée. L'idée est que les circuits qui s'occupent de saturer les résultats sont intégrés avec le décaleur. Ces circuits regardent les ''guard bit'' sortant de l'accumulateur et modifient le résultat en fonction de ceux-ci. Si aucun ''guard bit'' n'est à zéro, alors il n'y a pas eu débordement d'entier et le décaleur fait son travail normalement. Mais si un seul ''guard bit'' est à 1, c'est signe qu'un débordement d'entier a eu lieu. Le résultat est alors remplacé par la valeur maximale supportée par le DSP (en dehors de l'accumulateur). Un DSP contient souvent une unité MAC, une ALU entière, et un décaleur séparé. Un DSP doit en effet implémenter les instructions usuelles, sur des opérandes entiers. Et cela ne concerne pas que les additions/soustractions ou les opérations logiques : les décalages/rotations sont aussi de la partie. Les DSPs intègrent donc un ''barrel shifter'', qui est séparé de l'unité MAC. Et c'est une source d'optimisation : le décaleur pour les arrondis est parfois fusionné avec le ''bareel shifter'', pour économiser des circuits. En clair, le décaleur des arrondis est sorti de l'unité MAC et est une unité de calcul comme une autre. Mais ce n'est pas systématique et de nombreux DSPs préfèrent utiliser un mini-décaleur séparé du ''barel shifter'', pour des raisons de performance. ===L'implémentation matérielle de l'unité de calcul MAC=== [[File:Chemin de données d'un DSP.png|vignette|upright=1|Chemin de données d'un DSP, avec multiplieur et additionneur séparé.]] L'implémentation d'un circuit MAC pour opérandes entiers est très simple, car on peut fusionner l'additionneur et le multiplieur en un seul circuit. Rien de surprenant, nous savons qu'un multiplieur contient un additionneur multiopérande, on peut lui ajouter de quoi faire une addition entière en plus. Cependant, la plupart des DSPs préfèrent utiliser un multiplieur séparé de l'additionneur, avec un registre entre les deux. Le registre en sortie du multiplieur a une taille deux fois plus grande que les opérandes, pour mémoriser le résultat complet de la multiplication. Pour un DSP qui manipule des opérandes de 24 bits, le registre pour les multiplications fera 48 bits, soit le double. Pour donner un exemple, les DSP Blackfin+ géraient des opérandes de 32 bits, avaient un registre de 64 bits pour le résultat de la multiplication, et utilisaient des accumulateurs de 72 bits. [[File:Chemin de données d'un DSP, avec guard bits et produit long.png|centre|vignette|upright=1.5|Chemin de données d'un DSP, avec guard bits et produit long]] Faire ainsi a plusieurs avantages. Le premier est que cela permet de pipeliner l'unité de calcul MAC. Pendant que l'additionneur traite une instruction MAC, le multiplieur s'occupe de l'instruction MAC suivante. Les DSPs avec un pipeline peuvent ainsi profiter d'une hausse de performance assez conséquente. Mais au-delà de l'usage d'un pipeline, d'autres optimisations sont rendues possibles. La première est que cela permet d'implémenter l'addition de manière assez simple. En effet, l'unité MAC peut parfois être modifiée de manière à supporter d'autres instructions que l’instruction MAC. Elles peuvent être utilisées pour faire des additions ou des multiplications seules. L'addition seule court-circuite le multiplieur, et envoie un opérande en entrée de l'additionneur. Pour cela, il faut intercaler un multiplexeur entre le multiplieur et l'additionneur. L'additionneur peut aussi être remplacé par une vraie unité de calcul entière, capable de faire des opérations bit à bit. [[File:Unité MAC modifiée de manière à supporter l'addition.png|centre|vignette|upright=2|Unité MAC modifiée de manière à supporter l'addition]] L'opérande de l'addition peut provenir de plusieurs endroits : soit d'un autre accumulateur, soit des registres d'opérandes, soit de la mémoire RAM. Si les deux opérandes sont dans deux accumulateurs, alors elles ont la même taille et sont envoyées en entrée de l'additionneur sans autre forme de procès. Mais si elles viennent des registres d'opérandes ou de la RAM, elles sont plus courtes que ce que prend en entrée l'accumulateur. Par exemple, prenons un DSP avec des opérandes 16 bits et un additionneur 40 bits. L'additionneur a une entrée reliée à l'accumulateur de 40 bits, l'autre entrée provient du multiplexeur et fait 32 bits. Un opérande de l'addition provient de l'accumulateur et fait 40 bits, l'autre est un opérande de 16 bits et doit être convertie en 32 bits. Pour cela, il y a plusieurs solutions. * La première utilise l'extension de signe, à savoir que l'opérande de 16 bits est étendue sur 32 de manière à conserver son signe. * La seconde envoie l'opérande dans les 16 bits de poids fort en entrée de l'additionneur, les 16 bits de poids faible sont mis à zéro. * Il est possible de concaténer deux registres d'opérande de 16 bits pour obtenir un opérande de 32 bits, soit la taille adéquate. ===Les unités MAC flottantes=== Précisons que tout ce qui vient d'être dit précédemment ne fonctionne que pour des opérandes entiers, pas pour des opérandes flottants. Pour les opérandes flottants, la question des arrondis est un peu différente. L'opération MAC est composée d'une multiplication flottante, suivie d'une addition flottante. La question est alors la suivante : est-ce qu'il y a un arrondi entre les deux, avec la normalisation et autres subtilités propres aux nombres flottants ? Pour gérer ce cas, il existe deux types d'instructions MAC : l'instruction MAC classique et l'instruction '''''Fused MAC''''' (FMAC). L'instruction MAC classique fait un arrondi entre les deux, l'instruction FMAC n'en fait pas. L'instruction donne des résultats plus précis, mais demande de travailler avec un résultat de multiplication plus grand de quelques bits, ce qui fait des circuits en plus. Les DSP se classent en deux sous-types : ceux qui utilisent des nombres flottants et ceux qui utilisent des nombres à virgule fixe. Les premiers DSPs utilisaient la virgule fixe. Le cas classique était des DSP utilisant des opérandes de 24 bits : 16 pour la partie entière, 8 pour la partie fractionnaire. Notons que 24 bits était la norme pour encoder de l'audio sur des CD audio, ce qui fait que les DSPs de l'époque utilisaient cette précision. Par la suite, des DSP 16 et 32 bits sont apparus, puis des DSP flottants. Les DSPs à virgule fixe disposent de mécanismes pour émuler des nombres flottants en utilisant des calculs entiers. Pour être plus précis, ils émulent des nombres flottants spéciaux, appelés '''nombres flottants par blocs''' (traduction du terme anglais ''block-floating point''). L'idée est de manipuler des nombres flottants qui ont tous le même exposant, afin de simplifier les calculs. Si plusieurs nombres flottants ont le même exposant, alors les additionner demande de simplement additionner les mantisses, les multiplier demande de multiplier les mantisses. Du moins, c'est le cas en absence de débordement d'entier, mais les DSPs ont des protections pour ça, comme les ''guard bits'' et les accumulateurs larges. Les DSPs émulent les calculs sur les flottants par blocs de la manière suivante. Les DSPs disposent d'une instruction EXP, qui calcule l'exposant et le mémorise dans un registre. Une fois l'exposant connu, ils normalisent les mantisses avec des décalages, de manière à ce que tous les opérandes aient le même exposant. Puis, ils additionnent ou multiplient les mantisses ensemble, avec des instructions MAC, MUL, ADD, SUB, DIV, etc. Une fois les calculs terminés, la mantisse du résultat est dans l'accumulateur. Elle est normalisée avec un décalage, réalisé par le ''barrel shifter'', en fonction de l'exposant calculé. La gestion des flottants par blocs peut être réalisée avec le décaleur vu plus haut, dans la section précédente. Les décalages nécessaires pour normaliser et décaler les mantisses sont réalisés par de décaleur. ===Des exemples d'unités MAC=== Le DSP TMS32010 de marque Texas Instrument disposait d'un additionneur et d'un multiplieur, couplés à trois registres : un registre accumulateur, le registre T pour un opérande, et le registre P entre le multiplieur et l'additionneur. [[File:Unité de calcul du DSP TMS32010 de marque Texas Instrument.png|centre|vignette|upright=2|Unité de calcul du DSP TMS32010 de marque Texas Instrument]] Le Motorola DSP 5600x avait deux accumulateurs, ainsi que 4 registres d'opérandes appelés X1, X2, Y1 et Y2. Les deux accumulateurs faisaient 56 bits. Les registres d'opérandes, quant à eux, pouvaient être utilisés de deux manières : soit comme 4 registres de 24 bits, soit comme 2 registres de 48 bits. L'unité MAC était capable de faire une opération MAC, une addition, ou une opération bit à bit. Pour cela, l'additionneur est précédé par une unité de calcul bit à bit, qui n'est pas utilisée quand le multiplieur l'est. En clair, l'unité bit à bit sert uniquement quand on charge les opérandes depuis les registres d'opérandes. L'additionneur est suivi par un circuit capable de faire des opérations de normalisation et d'arrondis. Le circuit intègre deux décaleurs. Le premier est situé en sortie de l'accumulateur, et permet de traduire un résultat de 56 bits en un résultat de 24 bits. Il sert aussi pour des arrondis, des opérations de normalisation et bien d'autres. L'autre décaleur est lui entre l'accumulateur et l'additionneur. Il est beaucoup plus limité et ne peut que faire quatre opérations : ne rien faire, un décalage à gauche de 1 rang, un décalage à droite de 1 rang, mettre à zéro sa sortie. L'unité MAC n'était pas pipelinée, elle faisait un calcul en un cycle. Par contre, il était possible de modifier les registres d'opérandes pendant qu'un calcul MAC était en cours. En entrée du multiplieur, il y avait deux registres non-adressabbles, qui mémorisaient les opérandes pendant un cycle d'horloge complet. Ainsi, il était possible d'écrire dans les registres d'entrée, sans pour autant que cela impacte le calcul en cours. [[File:Unité de calcul du Motorola DSP 5600x.png|centre|vignette|upright=2|Unité de calcul du Motorola DSP 5600x]] ==La microarchitecture d'un DSP== Il est intéressant de regarder comment la microarchitecture des DSPs a évoluée. Et c'est en lien avec l'évolution de leur jeu d'instruction. Les DSPs sont souvent classés en trois à cinq générations, mais les frontières entre générations varient beaucoup d'un livre à l'autre, d'un auteur à l'autre. Dans ce chapitre, nous allons juste séparer les DSPs en deux : les DSPs classiques, qu'on a détaillé plus haut, et les DSP récents qui intègrent des jeux d'instructions SIMD, VLIW ou superscalaires. Sur les anciens DSP, les instructions s'exécutaient toutes en un seul cycle d'horloge et tendaient à faire pas mal de traitements assez complexes. De nos jours, les DSPs tendent à utiliser un pipeline, ce qui fait que la contrainte "1 cycle = une instruction" est battue en brèche. ===La microarchitecture d'un DSP classique=== Un DSP contient au minimum une unité de calcul MAC avec un ''barrel shifter''. De nombreux DSPs incorporent aussi une ALU entière séparée du circuit MAC, qui est utilisée pour des additions/soustractions, opérations logiques et bit à bit. Le ''barrel shifter'' est lui utilisé pour tronquer le résultat en sortie de l'accumulateur, et pour gérer les nombres flottants par blocs, avec l'aide d'une unité dédiée aux exposants. Les DSPs intègrent des unités de calcul spécialisées dans les calculs d'adresse, qui sont regroupées avec les registres d'adresse et d'indice. Elles implémentent l'adressage modulo et bit-''reverse'', ainsi que les modes d'adressages à post- ou pré-incrément/décrément, et les modes d'adressage usuels. Il y a un banc de registre pour les registres d'adresse, un autre pour les registres d'indice, ainsi qu'une unité de calcul d'adresse spécialisée. Il y a en général deux unités de calcul d'adresse, une par opérande. [[File:Unité d'accès mémoire avec registres d'adresse ou d'indice.png|centre|vignette|upright=2|Unité d'accès mémoire avec registres d'adresse ou d'indice]] Un DSP avec un registre T est forcément connecté à une mémoire simple port. Sa microarchitecture est des plus simples. De tels DSP n'ont généralement pas d'ALU entière séparée de l'unité MAC, car ces opérations sont réalisées dans l'unité MAC elle-même. L'additionneur est remplacé par une ALU entière, un MUX permet de court-circuiter le multiplieur. Ses interconnexions sont particulièrement simples. : Nous omettrons les liaisons entre séquenceur et ALUs, utilisées pour les modes d'adressage immédiat (constantes immédiates). [[File:Microarchitecture d'un DSP avec un registre T.png|centre|vignette|upright=2|Microarchitecture d'un DSP avec un registre T]] Si on suppose au contraire que le DSP utilise une mémoire RAM multiport, on devrait avoir ceci : [[File:Microarchitecture d'un DSP avec mémoire multiport.png|centre|vignette|upright=3|Microarchitecture d'un DSP avec mémoire multiport.]] Si on suppose que le DSP utilise une architecture Harvard modifiée, et que les coefficients sont en mémoire ROM, l'intérieur du DSP devrait ressembler à ceci : [[File:Microarchitecture d'un DSP.png|centre|vignette|upright=3|Microarchitecture d'un DSP.]] ===Les DSPs avec optimisations pour l'opération ''butterfly''=== Les DSPs précédents n'incorporent pas d'optimisations pour l'opération ''butterfly''. En effet, celles-ci n'ont qu'un seul accumulateur, pas plus. Mais l'opération ''butterfly'' marche bien mieux avec deux accumulateurs. Aussi, de nombreux DSPs incorporent deux accumulateurs et quoi les utiliser au mieux. Dans le cas le plus simple, l'unité MAC est reliée à deux accumulateurs. Mais sur les '''DSPs ''Dual MAC''''', les deux accumulateurs sont couplés à deux unités MAC, avec une unité MAC par accumulateur. De tels DSPs peuvent faire deux opérations MAC par cycle d'horloge, souvent avec l'aide d'une instruction machine de multiplication/addition complexe. Pour donner un exemple, prenons le DSP TMS320-C54x, qui dispose de deux accumulateur, mais n'est pas un DSP ''dual MAC''. Il dispose de 6 unités de calcul : une unité MAC non-pipelinées, une ALU entière, un ''barrel shifter'', deux unités de calcul d'adresse, et une unité de comparaison spécialisée pour l'algorithme de Viterbi qu'on ne détaillera pas ici. L'ALU entière et le ''barrel shifter'' gèrent des opérandes de 40 bits, l'unité MAC gère des opérandes de 17 bits (16 bits, plus un bit de signe) et un résultat de 40 bits. Pour supporter des calculs flottants, le processeur incorpore un circuit dédié à la gestion des exposants, qui s'occupe des opérations de normalisation, d'arrondis et autres. Un détail important est que l'unité de calcul peut soit fonctionner comme une ALU unique de 40 bits, soit comme une ALU SIMD de 16 bits. Elle est capable de faire deux opérations sur deux opérandes de 16 bits en même temps. Pour le reste, les interconnexions entre ces unités de calcul sont très complexes. C'est presque comme si tout était connecté à avec tout le reste. Le DSP TMS320-C54x a deux accumulateurs, qui peuvent recevoir le résultat de l'unité MAC ou de l'ALU entière. Les deux accumulateurs envoient leur contenu en entrée de toutes les ALU, sauf les AGU. Le ''barrel shifter'' envoie son résultat soit en mémoire RAM, soit en entrée de l'ALU entière. Le TMS320-C54x dispose de trois bus de données, pour lire deux opérandes et écrire un résultat en un seul cycle d'horloge. Ils sont appelés CB, DB et EB, les deux bus CB et DB sont en lecture, le bus EB est un bus d'écriture. Les deux bus CB et DB envoient des opérandes à l'unité MAC, l'ALU entière et le ''barrel shifter''. Pour le bus EB des écritures, il n'est accesible qu'à travers le ''barrel shifter''. Ce qui est logique : lors de l'enregistrement en mémoire, un résultat de 40 bits doit être converti en donnée de 16 ou 32 bits, ce qui demande de faire un décalage pour éliminer les bits de poids faible. [[File:Chemin de données du TMS320C54x.png|centre|vignette|upright=2|Chemin de données du TMS320C54x]] ===Les DSPs VLIW, SIMD et superscalaires=== Les DSPs de seconde génération et au-delà, incorporent plusieurs unités de calcul MAC. De plus, celles-ci sont pipelinées pour augmenter le nombre d'opérations exécutées par cycle d'horloge. Pour les alimenter, le processeur dispose de trois méthodes : soit utiliser un jeu d'instruction VLIW, soit être un processeur superscalaire, soit utiliser des instructions SIMD. Les trois solutions sont utilisées, suivant le DSP. Et il n'est pas rare que l'on ait des DSPs qui mélangent SIMD et VLIW, ou encore SIMD et superscalarité. Les DSP les plus simples sont les '''DSP ''dual MAC''''', au nom assez parlent. Ils incorporent deux multiplieurs, voire deux unités de calcul FMAC, qui peuvent fonctionner en même temps. Des exemples de DSPs de ce type sont le Lucent DSP 16xxx ou le TMS C55x de Texas Instrument. Le Lucent DSP 16xxx contenait deux multiplieurs de 16 bits, couplés à une ALU entière et un additionneur trois-opérandes. Cela parait bizarre de ne pas avoir utilisé deux ALU entières, mais cela permet d'économiser un peu de circuit de remplacer une seconde ALU par un additionneur. L'ensemble permettait de faire deux opérations MAC par cycle. Il y avait aussi une unité de manipulation de bit, sans compter de nombreux circuits décaleurs intercalés en entrée et sortie des multiplieurs. [[File:Lucent DSP16xxx.png|centre|vignette|upright=2|Lucent DSP16xxx]] Mais les unités MAC ne sont pas seules au monde, il faut aussi tenir compte des ALU entières et du ''barrel shifter''. Les DSP ''dual MAC'' basiques ne les dupliquent pas, mais d'autre le font. Pour donner un exemple, le Texas Instruments TMS320 C62x incorpore deux multiplieurs, deux ALU entières, deux unités de calcul qui regroupent une ALU entière avec un ''barrel shifter'', et deux unités de calcul d'adresse. Le tout est associé à deux bancs de registres contenant 32 registres de 32 bits chacun. Pour les exploiter, le processeur utilisait un jeu d'instruction VLIW, où chaque faisceau VLIW regroupait 8 instructions, chacune allant sur une des 8 unité. L'ADI TigerSHARC est un processeur qui mélange SIMD et VLIW. L'idée est qu'il peut exécuter un même faisceau VLIW sur deux paquets de données. Pour cela, le processeur contient deux chemins de données identiques, qui exécutent le même instruction VLIW, mais sur des données différentes. Chaque chemin de données contient 32 registres, une unité mémoire (avec calcul d'adresse), un ''barrel shifter'', une ALU entière et un circuit MAC. Un faisceau VLIW encode 4 instructions : une instruction LOAD/STORE, une opération MAC, une opération de calcul entière et un décalage. Les DSP incorporent aussi ce que j'ai appelé du SWAR (''SIMD Within A Register'') dans le chapitre sur le parallélisme de données. L'idée est de configurer un additionneur 32 bits pour faire deux additions 16 bits à la fois. Les ALU entières des DSPs incorporent cette optimisation. Les DSPs ayant souvent des ALU entières de 40 bits, cela permet d'implémenter deux additions de 16 bits, avec des ''guard bit'' pour chaque addition. Les ''guard bits'' sont répartis équitablement entre les deux additions 16 bits. Concrètement, le résultat de 40 bits est composé de deux résultats de 20 bits, avec 4 ''guard bits'', les deux résultats étant concaténés. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les ISA optimisés pour la compilation/interprétation | prevText=Les ISA optimisés pour la compilation/interprétation | next=Les architectures actionnées par déplacement | nextText=Les architectures actionnées par déplacement }} </noinclude> ctq1mg09n3wo5pthj4yqc1ft2cbs1qi Fonctionnement d'un ordinateur/Les périphériques et les cartes d'extension 0 65774 772088 759414 2026-09-12T17:09:21Z Mewtow 31375 /* L'architecture globale */ 772088 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le '''convertisseur analogique-numérique''', ou CAN, recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles régulier : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le '''convertisseur numérique-analogique''', ou CNA, transforme des informations binaires en tension à envoyer à un haut-parleur. En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrée au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes intégrées aux ''chipset'' peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] Il faut signaler que certaines cartes son possèdent un processeur, qui s'occupe du calcul de divers effets sonores. Ce processeur est techniquement un processeur de traitement de signal, aussi appelé DSP, à savoir un type de processeur que nous aborderons en détail d'ici quelques chapitres. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] En aval du CAN (ou du DSP, cas échéant), on trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisée. Cette mémoire sert à interfacer le processeur avec le CNA : le processeur est forcément très rapide, mais il n'est pas disponible à chaque fois que la carte son a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare à l'avance une certaine quantité d'information, suffisamment pour tenir durant quelques millisecondes. Une fois qu'il dispose de suffisamment d’informations sonores, il va envoyer le tout en une fois à la carte son. Celle-ci stockera ces informations dans une petite mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à un fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Les convertisseurs entre analogique et numérique=== Pour faire les conversions analogiques-numériques, on utilise deux circuits, vus dans les chapitres en début de cours : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Le signal numérique de la carte son, utilisé pour coder le son, utilise un certain nombre de bits. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> n483lni6z2hjwh4wgvn1fnfcu2n22y9 772089 772088 2026-09-12T17:14:43Z Mewtow 31375 /* L'architecture globale */ 772089 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le '''convertisseur analogique-numérique''', ou CAN, recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles régulier : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le '''convertisseur numérique-analogique''', ou CNA, transforme des informations binaires en tension à envoyer à un haut-parleur. En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrée au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes intégrées aux ''chipset'' peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisée. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare à l'avance une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à un fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Les convertisseurs entre analogique et numérique=== Pour faire les conversions analogiques-numériques, on utilise deux circuits, vus dans les chapitres en début de cours : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Le signal numérique de la carte son, utilisé pour coder le son, utilise un certain nombre de bits. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> p4rkqxek9vasplqqpsfv6dbiv1jpd5x 772090 772089 2026-09-12T17:17:13Z Mewtow 31375 /* La carte son */ 772090 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. : Le signal numérique de la carte son, utilisé pour coder le son, utilise un certain nombre de bits. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles régulier : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrée au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes intégrées aux ''chipset'' peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisée. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare à l'avance une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à un fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> ov0jy0s046zqxnto6g8vw85edpre8xi 772091 772090 2026-09-12T17:20:32Z Mewtow 31375 /* L'architecture globale */ 772091 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux cirdcuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des resistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles régulier : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrée au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes intégrées aux ''chipset'' peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisée. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare à l'avance une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à un fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> m0k9mfucdscs7r5dz8ebksv48s17jh7 772092 772091 2026-09-12T17:21:37Z Mewtow 31375 /* L'architecture globale */ 772092 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> eq0cd09hd0ngmsyn3xy8oen5uhz6s9e 772093 772092 2026-09-12T17:23:00Z Mewtow 31375 /* L'architecture globale */ 772093 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===L'architecture globale=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. ===Les convertisseurs analogique-numérique=== Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> 9beyrnk3okimlsznczbh7qllbpn4rwh 772094 772093 2026-09-12T17:23:11Z Mewtow 31375 /* La carte son */ 772094 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> 5gi6znlphl0seca1g5y671qg3pajbof 772095 772094 2026-09-12T17:23:33Z Mewtow 31375 /* La carte son */ 772095 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Ce multiplexeur récupère les tensions des différentes entrées, et en choisira une qui est recopiée sur la sortie. Ce multiplexeur comporte une entrée de commande qui permet de choisir quelle entrée sera choisie pour être recopiée sur la sortie. Ce multiplexeur est ensuite suivi par un '''amplificateur''',qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> jdmawzdl7kmnb14maq0yhtcnbul7mjk 772096 772095 2026-09-12T17:25:19Z Mewtow 31375 /* Le multiplexeur analogique */ 772096 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===L'échantillonneur=== La tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN et plusieurs échantillonneurs-bloqueurs sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN et l' échantillonneur-bloqueur sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Le multiplexeur analogique récupère les tensions des différentes entrées, et en choisit celle qui est recopiée sur la sortie. Le multiplexeur analogique comporte une entrée de commande qui permet de choisir quelle entrée choisir. Le multiplexeur analogique est ensuite suivi par un '''amplificateur''', qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> 3mhjlgiltq28lmrw8oc6hbjupu4ymph 772097 772096 2026-09-12T17:27:29Z Mewtow 31375 /* L'échantillonneur */ 772097 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===Les circuits en aval du CAN=== Une carte son n'utilise pas un CAN seul. Il est forcément entouré par des circuits de soutien, qui lui permettent de faire son travail. Dans cette section, nous allons voir ces circuits de supports. Nous allons en voir deux : l'échantillonneur-bloqueur et le multiplexeur analogique. Le premier est quasiment obligatoire si on veut que le CAN fasse son travail. Le second est totalement facultatif, mais est très utile si la carte son a plusieurs entrées audio. L'échantillonneur-bloqueur résoud un problème assez précis : la tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] ===Le multiplexeur analogique=== Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN et plusieurs échantillonneurs-bloqueurs sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN et l' échantillonneur-bloqueur sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Le multiplexeur analogique récupère les tensions des différentes entrées, et en choisit celle qui est recopiée sur la sortie. Le multiplexeur analogique comporte une entrée de commande qui permet de choisir quelle entrée choisir. Le multiplexeur analogique est ensuite suivi par un '''amplificateur''', qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> kb2pafw4jeqwcd7ue6z72hamwx4ht21 772098 772097 2026-09-12T17:27:44Z Mewtow 31375 /* Le multiplexeur analogique */ 772098 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===Les circuits en aval du CAN=== Une carte son n'utilise pas un CAN seul. Il est forcément entouré par des circuits de soutien, qui lui permettent de faire son travail. Dans cette section, nous allons voir ces circuits de supports. Nous allons en voir deux : l'échantillonneur-bloqueur et le multiplexeur analogique. Le premier est quasiment obligatoire si on veut que le CAN fasse son travail. Le second est totalement facultatif, mais est très utile si la carte son a plusieurs entrées audio. L'échantillonneur-bloqueur résoud un problème assez précis : la tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] Voyons maintenant le multiplexeur analogique; Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN et plusieurs échantillonneurs-bloqueurs sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN et l' échantillonneur-bloqueur sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Le multiplexeur analogique récupère les tensions des différentes entrées, et en choisit celle qui est recopiée sur la sortie. Le multiplexeur analogique comporte une entrée de commande qui permet de choisir quelle entrée choisir. Le multiplexeur analogique est ensuite suivi par un '''amplificateur''', qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> atp7lugx3eh0bfm554z2yj7byqqfk42 772099 772098 2026-09-12T17:28:22Z Mewtow 31375 /* Les circuits en aval du CAN */ 772099 wikitext text/x-wiki Dans ce chapitre, nous allons étudier les périphériques et les cartes d'extension. Pour rappel, les '''cartes d'extension''' sont les composants qui se connectent sur la carte mère via un connecteur, comme les cartes son ou les cartes graphiques. Quant aux '''périphériques''', ce sont les composants connectés sur l'unité centrale. De nos jours, les cartes d'extension se font de plus en plus rares. Il y a quelques décennies, tout ordinateur avait une carte son, une carte réseau, une carte graphique, et éventuellement d'autres cartes d'extension. Mais de nos jours, avec les progrès de la miniaturisation, ce n'est plus le cas. La carte son et la carte réseau sont souvent intégrées directement à la carte mère, la carte graphique est intégrée directement dans le processeur. Bref, elles n'existent plus sous forme de cartes d'extension, comme c'était le cas à une époque, la seule exception étant les cartes graphiques à haute performances. Il n'en reste pas moins que ces circuits sont conçus d'une manière assez spécifique et qu'il est intéressant de les étudier à part. Nous regroupons ces cartes d'extension avec les périphériques, car les deux ont en commun d'être des entrées-sorties assez particulières, qui doivent communiquer avec le reste de la carte mère via une interface dédiée. ==Le clavier== Les claviers sont les premiers périphériques à avoir été inventés, les tout premiers ordinateurs disposaient de claviers alors que les souris n'avaient pas été inventées. Intuitivement, on se dit qu'un clavier est un périphérique d'entrée, mais ce n'est pas le cas ! Le clavier communique avec l'ordinateur dans les deux sens, contrairement à ce qu'on pourrait penser. Voyons cela en détail. ===La communication entre le clavier et l'ordinateur=== L'interface entre clavier et ordinateur gère deux sens de transmission : du clavier vers l'ordinateur, et de l'ordinateur vers le clavier. Les deux sont gérés différemment. Du point de vue du clavier, la sortie envoie la touche appuyée vers l'ordinateur, alors que son entrée est utilisée pour configurer les diodes du clavier. Voyons maintenant l'interface clavier pour les deux sens, entrée et sortie. La transmission en sortie indique à l'ordinateur si une touche a été appuyée et laquelle. Pour indiquer quelle touche a été appuyée, le clavier attribue un numéro spécifique à chaque touche, appelé un '''scancode'''. Le scancode d'une touche est standardisé et il existe plusieurs standards de scancodes. Les tout premiers PC utilisaient le '''jeu de scancode XT''', qui codait une touche sur un octet : les 7 bits de poids faible identifient la touche, et le bit de poids fort indique si la touche a été appuyée ou relâchée. Les claviers PS/2 utilisaient le '''jeu de scancode AT'''. Avec ce jeu de scancode, les numéros des touches sont modifiés. Le relâchement d'une touche est indiqué différemment : avec les scancodes AT, il faut ajouter un octet d'une valeur 0xF0 devant le numéro de la touche. Sans ce préfixe, on considère que la touche a été appuyée. La transmission en entrée sert, entre autres, à configurer les diodes du clavier. Pour mieux comprendre, regardez votre clavier, près du clavier numérique. Vous verrez normalement trois diodes vertes : une pour indiquer si le verrouillage numérique est actif ou non, une autre pour le verrouillage majuscule et une autre pour l'arrêt défil. Et bien c'est l'ordinateur qui configure ces trois diodes, ce n'est pas fait à l'intérieur du clavier ! Un bon moyen de s'en rendre compte est de regarder ce qui se passe quand l'ordinateur plante et se fige : les trois diodes se figent elles aussi. La communication de l'ordinateur vers le clavier ne se limite pas à cela, c'est juste sa conséquence la plus visible. L'ordinateur peut envoyer d'autres informations de configuration au clavier, mais mettons cela de côté. ===L'intérieur d'un clavier=== À l'intérieur d'un clavier, on trouve un circuit relié aux touches, qui déduit les touches appuyées. Il se charge de convertir l'appui d'une touche en scancode. Il est appelé le '''''Keyboard Encoder''''', ou encore l'encodeur clavier, ce qui trahit sa fonction. Il peut être implémenté avec un vulgaire encodeur, un circuit séquentiel, ou tout autre circuit dédié, mais il est le plus souvent implémenté avec un microcontrôleur. Dans les premiers claviers de PC, l'encodeur clavier était un microcontrôleur Intel 8048. Les claviers actuels utilisent des microcontrôleurs similaires. Naïvement, on pourrait penser que le microcontrôleur est relié à chaque touche, mais ce genre d'organisation n'est utilisable que pour de tout petits claviers. Sur les claviers avec un faible nombre de touches, toutes les touches sont reliées au microcontrôleur, voire à un simple encodeur dans le cas le plus simple. Si un encodeur est utilisé, il est cependant relié à un microcontrôleur ou un autre circuit, pour gérer l'interface avec l'ordinateur, l'interface avec le bus USB/PS/2 ou autre. Autant utiliser un microcontrôleur à tout faire, qui gère à la fois l'encodage des touches et la communication avec le bus. [[File:Lock Keyboard Coder 2.png|centre|vignette|upright=1|Exemple de clavier simple, qui utilise un encodeur combinatoire.]] Avec un clavier à 102 touches, la technique précédente utiliserait 102 fils, ce qui serait difficile à mettre en œuvre. Aussi, une organisation alternative est utilisée. Les touches sont reliées à des fils électriques, organisés en lignes et en colonnes, avec une touche du clavier à chaque intersection ligne/colonne. La '''matrice de touches''' est reliée à un microcontrôleur qui déduit les touches appuyées en utilisant une procédure un peu spéciale, qu'on va détailler dans ce qui suit. [[File:Lock Keyboard Coder 3.png|centre|vignette|upright=1|Lock Keyboard Coder 3]] Pour simplifier, les touches agissent comme des interrupteurs : comme un interrupteur fermé quand elles sont appuyées, et comme un interrupteur ouvert quand elles sont relâchées. Si une touche est enfoncée, elle connecte la ligne à la colonne. À l'inverse, si la touche à l'intersection entre ligne et colonne n'est pas enfoncée, la ligne sera déconnectée. Grâce à un petit circuit (des résistances de rappels au zéro volt intégrée dans le micro-contrôleur), cette déconnexion de la ligne et de la colonne est interprétée comme un zéro. Pour savoir quelles touches sont appuyées, il suffit d'envoyer une tension sur la colonne testée et de regarder s'il y a une tension en sortie sur la ligne. Le micro-contrôleur balaye les colonnes unes par unes et regarde le résultat sur les lignes. Le résultat sur les lignes formé un nombre, qui est traduit par le microcontrôleur en un numéro de touche (une simple table de correspondance logicielle fait l'affaire). [[File:Gestion matrice clavier.png|centre|vignette|upright=1|Gestion matrice clavier]] Cette organisation a tout de même un léger problème, qui se manifeste quand trois touches ou plus sont appuyées. Dans une telle situation, il se peut que le courant passe à travers les interrupteurs des touches et active des lignes qui ne devraient pas l'être. Pour donner un exemple, prenons la configuration suivante : [[File:Ghosting - 1.png|centre|vignette|upright=1|Ghosting - 1]] Les problèmes surviennent quand le contrôleur active la troisième colonne. L'appui de la touche de droite active la colonne et la ligne sur laquelle elle se situe. L'appui de la touche immédiatement à gauche permet au courant sur la ligne de traverser la colonne. La touche en-dessous permet au courant de traverser la ligne elle aussi. Le résultat est que le résultat envoyé au microcontrôleur donnent l'illusion de l'appui d'une touche qui n'est pas appuyée, ici celle située sous la touche de droite. [[File:Ghosting - 2.png|centre|vignette|upright=1|Ghosting - 2]] Une solution pour limiter ce phénomène de '''ghosting''' est de coupler chaque touche avec une diode, qui empêche le courant de passer dans les lignes ou colonnes qui ne devraient pas être activées. [[File:Diode - ghosting.png|centre|vignette|upright=1|Diode - ghosting]] ==La souris== [[File:Mouse mechanism diagram.svg|vignette|Mécanisme interne d'une souris à boule.]] Les anciennes souris fonctionnaient avec une boule, en contact avec la surface/le tapis de souris, que le mouvement de la souris faisait rouler sur elle-même. Ce mouvement de rotation de la boule était capté par deux capteurs, un pour les déplacements sur l'axe gauche-droite, et un pour l'axe haut-bas. Les souris plus récentes contiennent une source de lumière, qui éclaire la surface sur laquelle est posée la souris (le tapis de souris). Cette source de lumière peut être une diode ou un laser, suivant la souris : on parle de '''souris optique''' si c'est une diode, et de '''souris laser''' si c'est un laser. Avec la source de lumière, on trouve une '''caméra''' qui photographie le tapis de souris intervalles réguliers, pour détecter tout mouvement de souris. Le tapis de souris n'est pas une surface parfaite, et contient des aspérités et des irrégularités à l'échelle microscopique. Quand on bouge la souris, les images successives prises par la caméra ne seront donc pas exactement les mêmes, mais seront en partie décalées à cause du mouvement de la souris. La caméra est reliée à un circuit qui détecte cette différence, et calcule le déplacement en question. Précisément, elle vérifie de combien l'image a bougé en vertical et en horizontal entre deux photographies de la surface. ===La sensibilité de la souris=== Le déplacement mesuré par le capteur est envoyé à l'ordinateur. Ce qui est envoyé est le nombre de pixels de différence entre deux images de caméra, en horizontal et en vertical. Le système d'exploitation va alors multiplier ce déplacement par un coefficient multiplicateur, la sensibilité souris, ce qui donne le déplacement du curseur sur l'écran en nombre de pixels). Plus celle-ci est faible, meilleure sera la précision. Les OS actuels utilisent l''''accélération souris''', à savoir que la sensibilité est variable suivant le déplacement, le calcul du déplacement du curseur étant une fonction non-linéaire du déplacement de la souris. Sur les anciens OS Windows, la sensibilité augmentait par paliers : un déplacement souris faible donnait une sensibilité faible, alors qu'une sensibilité haute était utilisée pour les déplacements plus importants. Cette accélération souris est désactivable, mais cette désactivation n'est conseillée que pour jouer à des jeux vidéos, l'accélération étant utile sur le bureau et dans les autres interfaces graphiques. Elle permet en effet plus de précision lors des mouvements lents (vu que la sensibilité est faible), tout en permettant des mouvements de curseurs rapides quand la souris se déplace vite. ===Les performance de la souris=== Plus la résolution de la caméra de la souris est élevée, plus celle-ci a tendance à être précise. Cette résolution de la caméra de la souris est mesurée en '''DPI''', Dot Per Inche. Il s'agit du nombre de pixels que la caméra utilise pour capturer une distance de 1 pouce (2,54 cm). Il va de soit que plus le DPI est élevé, plus la souris sera sensible. Pour un même déplacement de souris et à sensibilité souris égale, une souris avec un fort DPI entrainera un déplacement du curseur plus grand qu'une souris à faible DPI. Cela est utile quand on utilise un écran à haute résolution, mais pas dans d'autres cas. Un autre paramètre important de la souris est la '''fréquence de rafraichissement''' déterminant le nombre d'informations envoyé à l'ordinateur par seconde. Suivant le connecteur, celle-ci varie. Une souris connecté au connecteur PS/2 (celui situé l'arrière de l'unité centrale), a une fréquence par défaut de 40 hertz, mais peut monter à 200 Hz si on le configure convenablement dans le panneau de configuration. Un port USB a une fréquence de 125 Hz par défaut, mais peut monter jusqu’à 1000 Hz avec les options de configuration adéquate dans le pilote de la souris. Plus cette fréquence est élevée, meilleure sera la précision et plus le temps de réaction de la souris sera faible, ce qui est utile dans les jeux vidéos. Mais cela entrainera une occupation processeur plus importante pour gérer les interruptions matérielles générées par la souris. ==La carte son== Dans un ordinateur, toutes les données sont codées sous forme numérique, c'est à dire sous la forme de nombres entiers/ou avec un nombre de chiffres fixes après la virgule. Les ordinateurs actuels utilisent du binaire. Les informations sonores sont aussi stockées dans notre PC en binaire. Toutes vos applications qui émettent du son sur vos haut-parleurs stockent ainsi du son en binaire/numérique. Seulement, les haut-parleurs et microphone sont des composants dits analogiques, qui codent ou décodent l'information sonore sous la forme d'un tension électrique, qui peut prendre toutes les valeurs comprises dans un intervalle. Dans ces conditions, il faut bien faire l'interface entre les informations sonores numérique du PC, et le haut-parleur ou micro-phone analogique. Ce rôle est dévolu à un composant électronique qu'on appelle la '''carte son'''. ===Les convertisseurs analogique-numérique=== L'usage de microphones et d'haut-parleurs demande de faire des conversions entre analogique et numérique. Les microphones transforment un signal sonore en un signal électrique analogique, alors que les haut-parleurs font l'inverse. Mais ces signaux analogiques ne sont pas compréhensibles par le reste de l'ordinateur, qui est composé de circuits numériques. C'est pour cela que la carte son doit faire la conversion des signaux analogiques en signaux numériques, en binaire. Pour faire les conversions analogiques-numériques, on utilise deux circuits : * Le circuit qui convertit un signal analogique en signal numérique cela est un CAN ('''convertisseur analogique-numérique'''). * Le circuit qui fait la conversion inverse est un CNA ('''convertisseur numérique-analogique'''). Je ne vais pas expliquer comment fonctionnent en détail ces deux circuits. Un chapitre en annexe est dédié à ces deux circuits, mais je l'ai mis en annexe pour de bonnes raisons. Il faut dire que ces composants sont fabriqués avec des composants analogiques, comme des résistances, des amplificateurs analogiques et autres ; qui n'ont pas été abordés dans ce cours. De plus, cela ne servirait pas pour cette section. Tout ce que vous avez à savoir, c'est que les CAN et CNA sont des boites noires qui traduisent un signal sonore numérique en signal sonore analogique. Le signal numérique de la carte son est un flux de nombre, chacun codant l'intensité du son à un instant t. Le codage utilisé utilise un certain nombre de bits pour chaque nombre, pour chaque intensité sonore. Sur les cartes sons actuelles, ce nombre de bits porte un nom : c'est la '''résolution de la carte son'''. Celui-ci varie entre 16 et 24 bits sur les cartes sons récentes. [[File:CAN & CNA.png|centre|vignette|upright=2|CAN & CNA]] Une carte son contient à la fois un CAN et un CNA, qui sont utilisés respectivement pour le microphone et les haut-parleurs/casques. * Pour le micro-phone, la conversion traduit un signal analogique, proportionnel à l'intensité sonore, en signal numérique. Le CAN recueille la tension transmise par le micro-phone et la convertit en binaire. Il est relié à un composant qui mesure la tension envoyée par le microphone à intervalles réguliers : l''''échantillonneur'''. * Pour les sorties haut-parleur/casque, la carte son traduit le signal numérique provenant de l'ordinateur en un signal analogique utilisable par les haut-parleurs. Le CNA transforme des informations binaires en tension à envoyer à un haut-parleur. ===Les circuits d'interface avec le bus=== En plus de tout cela, la carte son contient aussi des circuits pour l'interfacer à un bus. Sans cela, pas de transferts entre la mémoire et la carte son. Avant les années 2010, les cartes son étaient sur des cartes d'extension. Elles utilisaient donc le bus ISA ou PCI, comme toute carte d'extension. Par la suite, elles ont progressivement été intégrées au ''chipset'' de la carte mère. Le bus utilisé a alors changé. Les cartes son modernes, intégrées aux ''chipset'', peuvent utiliser soit des bus dédiés (comme le bus HDA), soit le bus PCI Express, soit le bus USB. A l'heure où j'écris ces lignes, en 2026, les cartes son utilisant l'USB sont majoritaires. [[File:CARTE SON - architecture.PNG|centre|vignette|upright=2|Architecture d'une carte son.]] En aval du CAN, se trouve une petite mémoire dans laquelle sont stockées les informations qui viennent d'être numérisées. Elle sert à interfacer le CAN avec le reste de l'ordinateur. Le processeur n'est pas disponible à chaque fois que le CAN a fini de traduire un son. Les informations numérisées sont donc accumulées dans une petite mémoire FIFO en attendant que le processeur puisse les traiter. La même chose a lieu pour le CNA. Le processeur étant assez pris, il n'est pas forcément capable d'être disponible tous les 10 millisecondes pour envoyer un son à la carte son. Dans ces conditions, le processeur prépare une piste sonore assez longue, suffisamment pour tenir durant quelques millisecondes. La piste en question est envoyée à la carte son et mémorisée dans une mémoire FIFO qui les conservera dans l'ordre. Elle convertira ces informations au fur et à mesure, à une fréquence régulière. [[File:CARTE SON - architecture - 3.PNG|centre|vignette|upright=2|Architecture d'une carte son avec les mémoires tampons.]] ===Les circuits en aval du CAN=== Une carte son n'utilise pas un CAN seul. Il est forcément entouré par des circuits de soutien, qui lui permettent de faire son travail. Ils ont pour particularité de se situer avant le CAN, à savoir entre le microphone et le CAN. Dans cette section, nous allons en voir deux : l'échantillonneur-bloqueur et le multiplexeur analogique. Le premier est quasiment obligatoire si on veut que le CAN fasse son travail. Le second est totalement facultatif, mais est très utile si la carte son a plusieurs entrées audio. L'échantillonneur-bloqueur résoud un problème assez précis : la tension transmise par le microphone varie de manière continue, ce qui rend sa transformation en numérique difficile. Pour éviter tout problème, la valeur de la tension est mesurée à intervalle réguliers, tout les 20 millisecondes par exemple. On parle alors d’échantillonnage. Le nombre de fois que notre tension est mesurée par seconde s'appelle la '''fréquence d'échantillonnage'''. Pour donner quelques exemples, le signal sonore d'un CD audio a été échantillonné à 44,1 kHZ, c'est à dire 44100 fois par secondes. Plus cette fréquence est élevée, plus le son sera de qualité, proche du signal analogique mesuré. C'est ce qui explique qu'augmenter la fréquence d'échantillonnage augmente la quantité de mémoire nécessaire pour stocker le son. Sur les cartes sons actuelles, il est possible de configurer la fréquence d'échantillonnage. L’échantillonnage est réalisé par un circuit appelé l’'''échantillonneur-bloqueur'''. L'échantillonneur-bloqueur le plus simple ressemble au circuit du schéma ci-dessous. Les triangles de ce schéma sont ce qu'on appelle des amplificateurs opérationnels, mais on n'a pas vraiment à s'en préoccuper. Dans ce montage, ils servent juste à isoler le condensateur du reste du circuit, en ne laissant passer les tensions que dans un sens. L'entrée C est reliée à un signal d'horloge qui ouvre ou ferme l'interrupteur à fréquence régulière. La tension va remplir le condensateur quand l'interrupteur se ferme. Une fois le condensateur remplit, l'interrupteur est déconnecté isolant le condensateur de la tension d'entrée. Celui-ci mémorisera alors la tension d'entrée jusqu'au prochain échantillonnage. [[File:Sample-hold-circuit.svg|centre|vignette|Echantillonneur-bloqueur.]] Voyons maintenant le multiplexeur analogique; Une carte son peut supporter plusieurs entrées analogiques. Malheureusement, cela coûterait trop cher de mettre plusieurs CAN et plusieurs échantillonneurs-bloqueurs sur une carte son. À la place, les concepteurs de cartes sons mutualisent le CAN et l' échantillonneur-bloqueur sur plusieurs entrées analogiques grâce à un '''multiplexeur analogique'''. Le multiplexeur analogique récupère les tensions des différentes entrées, et en choisit celle qui est recopiée sur la sortie. Le multiplexeur analogique comporte une entrée de commande qui permet de choisir quelle entrée choisir. Le multiplexeur analogique est ensuite suivi par un '''amplificateur''', qui fait rentrer la tension fournit en entrée dans un intervalle de tension compatible avec le CAN. [[File:Partage de CAN sur plusieurs entrées.PNG|centre|vignette|upright=2|Partage de CAN sur plusieurs entrées.]] ===Le processeur de traitement de signal=== De rares cartes son intègrent un processeur, qui s'occupe du calcul de divers effets sonores. Il peut gérer le mixage stéréo, mixer plusieurs pistes en un seul flux sonore, gérer des effets de spatialisation sonore, faire l'équalisation, de la réverbération, et plein d'autres traitements sonores. Le processeur en question est ce qu'on appelle un ''processeur de traitement de signal''. Il s'agit de processeurs avec un jeu d'instruction très particulier, et très difficile à expliquer, que nous aborderons dans une annexe de ce wikilivre. Ce DSP est placé en aval du CNA, ce qui est évident quand on sait que le processeur ne peut traiter que des informations numériques. [[File:CARTE SON avec DSP.PNG|centre|vignette|upright=2|CARTE SON avec DSP]] ==La carte graphique== Les cartes graphiques sont des cartes qui s'occupent de communiquer avec l'écran, pour y afficher des images. Leur fonctionnement interne est cependant effroyablement complexe et il serait difficile de tout résumer en quelques lignes. Les anciennes versions de ce wikilivres ont tenté de le faire, mais le résultat était peu convainquant. La raison est que les cartes graphiques gèrent beaucoup de choses : elles gèrent l'affichage proprement dit, mais aussi le rendu 2D ou 3D, et ces trois fonctions sont relativement dépendantes les unes des autres. De plus, expliquer comment fonctionne une carte graphique demande de connaitre quelques bases sur le rendu 3D ou sur la couche logicielle de la programmation graphique, sur le pipeline graphique des API 3D modernes, et ce genre de subtilités. Et même quelque chose de très simple, comme l'affichage d'une image à l'écran, sans rendu 2D ou 3D, demande des explications assez longues, au moins un bon chapitre. Sachez cependant que nous reparlerons rapidement des cartes graphiques modernes dans les derniers chapitres de ce cours, dans le chapitre sur les architectures à parallélisme de données. De plus, je peux vous renvoyer vers un wikilivre spécialement dédié sur le sujet écrit par le même auteur que ce cours : * [[Les cartes graphiques|Les cartes graphiques]]. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'adressage des périphériques | prevText=L'adressage des périphériques | next=Les mémoires de masse : généralités | nextText=Les mémoires de masse : généralités }} </noinclude> a3xxbn4ok1vd18jtbxn5lkf4m36qe1d Fonctionnement d'un ordinateur/Le matériel réseau 0 68864 772084 765831 2026-09-12T17:02:35Z Mewtow 31375 /* La carte réseau */ 772084 wikitext text/x-wiki [[File:Osa hub.svg|droite|Hub/switch/routeur.]] Dans ce chapitre, nous allons étudier plus en détail le matériel réseau, à savoir les ''hub'', les ''switch'', et les routeurs. Il existe de nombreux protocoles pour gérer la transmission sur un réseau, mais nous ne verrons que les protocoles Ethernet, MAC et IP, seuls pertinents pour ce chapitre. Les deux premiers, MAC et Ethernet, se chargent de la communication entre deux ordinateurs reliés par un câble réseau ou via un réseau local (à travers un concentrateur/commutateur, comme on le verra plus loin). Le protocole IP et ses associés gèrent les transferts sur des réseaux étendus internet, où tout transfert passe par un grand nombre d'intermédiaires. ==Les commutateurs== Rappelons que les données sont transmises sur un réseau local sous la forme de '''trames''', des blocs de données de taille fixe. Chaque trame contient à la fois des données utiles, mais aussi un en-tête qui contient toutes les informations nécessaires à la gestion de la trame. Notamment, chaque trame indique d'elle-même sa destination dans le réseau. L'ordinateur de destination est identifié par une '''adresse MAC''' de 6 octets (48 bits). [[File:Netzwerktopologie Stern.png|vignette|Réseau local en étoile.]] Il existe plusieurs types de réseaux locaux, mais ceux que nous allons étudier sont des réseaux en étoile, où tous les ordinateurs sont reliés à un équipement central. L'équipement central sert de relai : il reçoit des trames (des paquets de données utiles) et les envoie aux ordinateurs de destination. Suivant la manière dont fonctionne l'équipement central, on distingue le concentrateur du commutateur. Un '''concentrateur''' est l'équivalent réseau d'un bus. Il redistribue chaque trame sans se préoccuper de sa destination. Chaque trame est envoyée à tous les ordinateurs/équipements réseau auquel il est connecté, sauf l'émetteur. Les concentrateurs sont à contraster avec les '''commutateurs''', au fonctionnement similaire, mais qui n'envoient les trames qu'au composant de destination. [[File:HubSwitch.gif|centre|vignette|500px|Différence entre concentrateur (à gauche) et commutateur (à droite).]] Pas besoin de parler plus en détail du concentrateur : nous avons déjà parlé des bus dans un chapitre à part et le concentrateur en lui-même n'est rien d'autre qu'un bus ! Par contre, il est intéressant de parler du commutateur. Lorsqu'il reçoit une trame, le commutateur l'analyse, déduit quel est l'ordinateur de destination et renvoie la trame sur le port associé à l'ordinateur de destination. Pour faire son travail, le commutateur dispose de plusieurs sous-circuits : * Un circuit extrait l'adresse MAC de destination des trames reçues. * Un circuit qui décide, en fonction de l'adresse MAC de destination, sur quel port l'envoyer (le ''forwarding engine''). * Un circuit d'interconnexion qui relie chaque port à tous les autres. [[File:Micro-architecture d'un switch.png|centre|vignette|upright=2.0|Micro-architecture d'un switch]] ===L'encapsulation et la commutation=== Avant de nous intéresser au circuit d'interconnexion, nous allons étudier les deux autres circuits, à savoir : l''''interpréteur de paquets''', qui détecte ou analyse les trames/paquets, et le '''Forwarding Engine''', qui détermine le port de destination à partir de l'adresse MAC de destination. À l'intérieur du ''forwarding engine'', on trouve une table de correspondance qui associe chaque adresse MAC à un port : la '''table CAM''', aussi appelée ''CAM table'' en anglais. Elle peut être implémentée de plusieurs manières : avec une machine à états finis matérielle, avec une mémoire RAM ou avec une mémoire associative. La dernière solution est la plus utilisée, même si des solutions hybrides sont aussi relativement courantes. D'ailleurs, les mémoires associatives sont souvent appelées des mémoires CAM (''Content Adressable Memories''), ce qui a donné son nom à la table CAM. Il faut noter que le contenu de la table CAM a une durée de péremption, appelée le ''Time To Live'', qui vaut entre 0 et 255 secondes. Elle permet de mettre à jour un réseau local sans avoir à redémarrer le commutateur. Par exemple, on peut remplacer un ordinateur branché sur le commutateur, ce dernier ne restera pas bloqué sur l'ancien ordinateur et finira par repérer le nouveau quand la table CAM aura été purgée. Un commutateur doit découvrir par lui-même les adresses MAC des composants qu'on branche sur ses ports : il ne peut pas les connaitre à l'avance. Pour cela, le commutateur utilise une méthode assez simple. Au démarrage du commutateur, la table CAM est vide, le commutateur ne sait pas qui est qui sur ses ports. Quand il reçoit une trame, il met à jour la table CAM avec l'adresse MAC de l'émetteur de la trame : cela fait un port de connu. Une fois que tous les ordinateurs ont envoyé quelque chose sur le réseau, il connait tous les ports. Si aucun port n'est associé à une adresse de destination, le commutateur envoie le paquet à tous les ports. [[File:Switch pipeliné.png|centre|vignette|upright=2.0|Il faut noter que le switch peut être pipeliné, pour gagner en performance : il suffit d'insérer des mémoires tampons entre les différents circuits cités au-dessus.]] ===Le circuit d'interconnexion (''Switch Fabric'')=== Le circuit d'interconnexion, aussi appelée la '''''switch fabric''''', relie les ports entre eux et est équivalent à un ensemble de connexions point à point configurables. Il est totalement configurable : il suffit de lui envoyer le numéro du port d'entrée et du port de sortie et le circuit d'interconnexion connecte ces deux ports (les autres ports restent déconnectés, en principe et sauf optimisation). [[File:Turingswitch.png|centre|vignette|''Switch Fabric''.]] Les techniques de broadcast ou de multicast permettent d'envoyer une donnée présentée sur un port d'entrée sur plusieurs sorties. Cela permet d'envoyer un message identique à plusieurs ordinateurs en même temps, sans devoir envoyer plusieurs copies. Certains commutateurs permettent de gérer cela directement dans le matériel, soit en dupliquant les paquets, soit en connectant une entrée sur plusieurs sorties. Dans ce qui va suivre, nous allons classer les commutateurs en deux types : les '''commutateurs à partage de temps''' et les '''commutateurs à partage d'espace'''. ====Les commutateurs à partage d'espace==== Les commutateurs à partage d'espace sont de loin les plus simples à comprendre. Ils sont simplement composés d'un ensemble de liaisons point à point, qui relient chacune un port d'entrée à un port de sortie. Chaque port d'entrée est relié à chaque port de sortie, chaque liaison pouvant être activée ou désactivée selon les besoins. Il est possible de concevoir ce circuit avec des multiplexeurs. [[File:Switch concu avec des multiplexeurs.png|centre|vignette|upright=2|Switch conçu avec des multiplexeurs.]] Il est aussi possible d'utiliser un '''réseau crossbar'''. Ce dernier est composé de fils organisés en lignes et en colonnes. À l'intersection de chaque ligne et de colonne, on trouve un interrupteur qui relie la ligne et la colonne. [[File:Intercpunetcrossbar.png|centre|vignette|Réseau Crossbar.]] Il est aussi possible de fabriquer un commutateur en combinant plusieurs commutateurs plus petits, avec moins d'entrées. La méthode la plus simple pour cela utilise plusieurs commutateurs ''crossbar'' pour former un commutateur plus gros, les différentes manières donnant respectivement un '''réseau CLOS''', un '''réseau de Benes''', un '''réseau de banyan''', les '''Switch Sunshine''', et bien d'autres. Dans ce qui va suivre, nous allons nous intéresser aux '''commutateurs de Banyan''', conçus à partir de commutateurs à deux entrées et deux sorties. Les commutateurs simples sont empilés en plusieurs couches, chaque couche possédant autant de sorties et d'entrée qu'il y en a dans le commutateur de Banyan final : si un commutateur a 8 entrées et 8 sorties, alors chaque couche aura 8 sorties et 8 entrées. Le nombre de couches est égal au logarithme du nombre de ports d'entrée/sortie N, ce qui fait que le nombre de commutateurs de base utilisé est proportionnel à N × log (N) : on économise donc des portes logiques comparé à un crossbar. Le commutateur de Banyan le plus simple est composé de deux couches, et possède donc 4 entrées et 4 sorties. Il ressemble à ceci : [[File:Switch de Banyan à deux couches (4 entrées et 4 sorties).png|centre|vignette|upright=2|Switch de Banyan à deux couches (4 entrées et 4 sorties)]] Pour un commutateurs à 8 entrées et 8 sorties, voici ce que cela donne : [[File:Switch de Banyan à 3 couches (8 entrées et 8 sorties).png|centre|vignette|upright=2|Switch de Banyan à 3 couches (8 entrées et 8 sorties)]] En guise d'exercice, regardez bien les schémas, et essayez d'en déduire la logique de construction. Vous verrez, rien de bien sorcier. Il existe différents types de réseaux de Banyan, qui portent les doux noms d'Omega, d'Alpha, etc. Ces réseaux se construisent simplement : si on prend un commutateur à N entrées (et autant de sorties), alors chaque couche doit réaliser une permutation des entrées et sorties, permutation qui doit respecter certaines propriétés pour tenir compte du fait que les commutateurs de base ont deux entrées et deux sorties. Le principe de création dépend donc des permutations utilisées sur chaque couche. Mais ces commutateurs ne sont pas sans défauts. En effet, ces commutateurs sont dits bloquants : il se peut que deux paquets destinés à des ports de destination différents ne puissent pas voir leurs demandes assouvies simultanément. Cela arrive quand deux paquets veulent sortir sur le même port d'un des commutateurs 2 - 2, d'où conflit. Cependant, on peut éviter ces conflits internes en triant les paquets suivant leur port de destination avec un algorithme bien précis. En conséquence, certains commutateurs de Banyan sont précédés d'un circuit de tri conçu avec des commutateurs 2 - 2, empilés en couches, ainsi qu'avec de la logique de configuration composée de comparateurs : l'ensemble forme un switch Batcher-Banyan. Il est possible d'adapter le principe des commutateurs de Banyan pour qu'ils n'utilisent pas des switchs 2 - 2 (deux entrées et deux sorties), mais 3 - 3, ou 4 - 4, voire plus : on parle alors de commutateurs de Banyan augmentés. Qui plus est, les commutateurs simples peuvent contenir des FIFO et de la logique de traitement, comme pour les commutateurs Crossbar. ====Les commutateurs à partage de temps==== Les commutateurs à partage de temps n'utilisent pas de liaisons point à point, mais les émulent à partir d'un bus ou d'un réseau en anneaux. De ce fait, ils sont parfois appelés des '''commutateurs à média partagés'''. Avec eux, chaque entrée est traitée à tour de rôle, l'une après l'autre. [[File:Switch à partage de temps conçu avec des multiplexeurs.png|centre|vignette|upright=2|Switch à partage de temps conçu avec des multiplexeurs.]] Avec cette architecture, implémenter le ''multicast'' ou le ''broadcast'' est relativement complexe. Pour résoudre ce problème, il suffit de relier chaque port de sortie sur le bus interne directement, sans démultiplexeur. En faisant cela, chaque port de sortie doit filtrer les paquets qui ne lui sont pas destinés. Pour cela, on ajoute un filtre d'adresse pour comparer l'adresse MAC/IP associée au port (CAM table) et l'adresse MAC de destination : s'il y a égalité, alors on peut recopier la donnée sur le port de sortie. Ces commutateurs sont des commutateurs à partage de temps (sauf le tout premier). [[File:Switch à média partagé.png|centre|vignette|upright=2|Switch à média partagé.]] ===L'arbitrage des trames=== Le réseau d’interconnexion est relativement lent et il arrive que de nouvelles trames arrivent pendant qu'il est en train de transmettre un paquet. Dans ce cas, il est nécessaire de mettre les trames en attente tant que le paquet précédent n'est pas totalement traité. De même, il faut gérer le cas où plusieurs paquets veulent accéder au même port de sortie, ce qui impose d'envoyer les paquets les uns après les autres (il arrive cependant que certains paquets soient perdus). Dans tous les cas, qui dit mise en attente dit : utilisation de mémoires tampons de type FIFO. Un commutateur contient donc de nombreuses mémoires FIFO. Celles-ci sont d'autant plus grosses que son réseau d'interconnexion est lent et que les trames arrivent rapidement. Mettre les trames en attente dans des mémoires FIFO permet de gérer la plupart des situations. Mais il arrive que de nouvelles trames arrivent alors que les tampons sont déjà pleins. Dans ce cas, les paquets en trop sont perdus et n'arrivent pas à destination : on laisse la situation entre les « mains » du logiciel. ====L'arbitrage hors du réseau d'interconnexion==== Dans le cas le plus simple, les FIFO tampons sont placés en-dehors du réseau d'interconnexion. On peut les mettre avant le réseau d'interconnexion, ou après, ou les deux. S'ils sont placés entre le réseau d'interconnexion et l'interface réseau de sortie, on parle d''''output buffering'''. [[File:Output-buffering.png|centre|vignette|upright=1.5|''Output buffering'']] S'ils sont placés en entrée du réseau d'interconnexion, on parle d''''input buffering'''. [[File:Input-buffering.png|centre|vignette|upright=1.5|''Input buffering'']] Il est parfaitement possible d'utiliser les deux en même temps, ce qui porte le nom d''''input-output buffering'''. [[File:Input-output-buffering.png|centre|vignette|upright=1.5|''Input-Output buffering'']] Si une requête est en attente via ''input buffering'', elle va bloquer les requêtes suivantes sur le port d'entrée, même si celles-ci ont un port de sortie différent : on parle d''''''head of line blocking'''''. Pour l'éliminer, certains commutateurs utilisent le ''Virtual output queing''. Cela consiste à découper chaque FIFO en plusieurs FIFO, chacune prenant en charge les paquets destinés à un port de sortie précis. Avec cette technique, on peut traiter les requêtes dans le désordre, afin de profiter au maximum des ports libres. [[File:Head-line-blocking.jpg|centre|vignette|upright=2|Head-of-line blocking.]] ====L'arbitrage dans le réseau d'interconnexion==== Certains commutateurs intègrent les FIFOs directement dans le réseau d'interconnexion. Dans le cadre d'un réseau ''crossbar'', il suffit de remplacer les interrupteurs ligne/colonne par des FIFO. Mais pour les commutateurs qui ont un grand nombre de ports d'entrée et de sortie, cela devient rapidement impraticable. Pour éviter cela, les commutateurs à haute performance réduisent la taille des FIFO intégrées dans le crossbar, mais rajoutent de grosses FIFO sur les ports d'entrée (''input buffering''). Les simulations montrent que le rapport entre performance et nombre de portes logiques utilisées est meilleur avec cette technique. [[File:Switch Crossbar avec arbitrage intégré.png|centre|vignette|upright=2|Switch Crossbar avec arbitrage intégré.]] ====L'arbitrage sur les commutateurs à partage d'espace==== Pour les commutateurs à partage d'espace, les tampons FIFO sont incorporés directement entre le MUX pour les ports d'entrée, et le reste (filtreur d'adresse ou DEMUX). Les FIFOS en question sont généralement implémentées avec une mémoire qui stocke les données des tampons FIFO et leur ordre d'arrivée. Le commutateur présenté dans le schéma ci-dessous peut être transformé en commutateur sans partage de temps avec une mémoire multiport qui a autant de ports d'écriture que de ports d'entrée. Dans ce qui va suivre, mes schémas utiliseront un commutateur à partage de temps. [[File:Switch à mémoire partagée.png|centre|vignette|upright=2|Switch à mémoire partagée.]] Implémenter plusieurs FIFO avec une seule mémoire peut se faire de plusieurs manières différentes. La solution la plus simple consiste à utiliser un cache (une mémoire associative, plus précisément). Chaque byte de cette mémoire mémorise un paquet, son numéro de port de sortie et son ordre d'envoi (afin de simuler une FIFO). Pour mémoriser l'ordre d'envoi, le commutateur attribue un numéro de séquence à chaque paquet : plus ce numéro est grand, plus le paquet est ancien. Obtenir le prochain paquet à envoyer demande simplement d'envoyer le numéro du prochain paquet (déterminé par un compteur) et le numéro du port de sortie à la mémoire associative. Celle-ci renvoie alors le paquet à envoyer sur ce port de sortie. Une autre solution consiste à utiliser une mémoire RAM pour stocker les paquets dans des listes doublement chainées. Il y a une liste par port de sortie : tous les paquets destinés à un port de sortie sont ajoutés à la liste qui lui est associée. Les circuits qui gèrent la mémoire RAM doivent gérer eux-mêmes les listes chaînées, ce qui fait qu'ils contiennent deux registres par liste : un pour l'adresse en tête de liste et un pour le dernier élément. Il y a un circuit pour l'ajout et un autre pour le retrait des paquets. En plus de cela, les circuits de gestion de la mémoire doivent allouer dynamiquement les nœuds de la liste et libérer la mémoire. La mémoire utilise des Bytes démesurément grands, capables de mémoriser un paquet de plusieurs centaines de bits sans problèmes. Ainsi, le commutateur a juste besoin de mémoriser quels sont les Bytes libres et les Bytes occupés dans une mémoire annexe : la ''free list'', souvent implémentée avec une mémoire FIFO. * Une première méthode mémorise les données dans la RAM, ainsi que l'ordre de stockage des paquets. [[File:Linked-list switch.png|centre|vignette|upright=2|Linked-list switch]] * La deuxième méthode réserve la mémoire centrale pour le stockage des paquets et maintient l'ordre d'envoi des paquets dans des '''tampons FIFO''', qui mémorisent les adresses des paquets dans la mémoire centrale. La taille fixe des mémoires FIFO ne permet pas d'allouer toute la mémoire pour seulement quelques ports. Mais cette organisation permet de gérer facilement le multicast et le broadcast : on peut facilement ajouter un paquet dans toutes les mémoires FIFO, simultanément avec un circuit d'ajout conçu pour. [[File:FIFO switch.png|centre|vignette|upright=2|FIFO switch]] ==Les routeurs== [[File:Internet-transit.svg|vignette|Routage.]] Il est maintenant temps de laisser les réseaux locaux derrière nous, et de voir plus grand. Par plus grand, je veux dire que nous allons aborder le réseau Internet. Sur le réseau Internet, les données sont transmises en paquets de taille variable, qui sont appelés sobrement des '''paquets réseau''', ou encore des paquets. Chaque paquet se propage dans le réseau de proche en proche, passant par de nombreux intermédiaires avant d'arriver à destination. Ces intermédiaires sont appelés des '''routeurs'''. Les routeurs sont similaires aux commutateurs, si ce n'est qu'ils gèrent des adresses différentes des adresses MAC : les adresses IP. Ces dernières permettent d'identifier un ordinateur sur Internet, mais n'a pas de lien avec les adresses MAC (qui sont limitées aux réseaux locaux). Pour simplifier, les routeurs reçoivent des paquets sur un port d'entrée, qui sont destinés à une adresse IP de destination, qui doit être envoyé à l'ordinateur de destination. Son fonctionnement est similaire à celui d'un commutateur amélioré. La seule différence notable est que la table CAM est remplacée par une '''table de routage''', qui associe une adresse IP de destination au port de sortie qui correspond. ===Routeurs de première génération=== Les tout premiers routeurs, dits de première génération, relient leurs ports d'entrée et de sortie avec un bus. ils contiennent aussi un processeur tout ce qu'il y a de plus normal pour traiter les trames IP, ainsi qu'une mémoire RAM pour stocker les trames et la table de routage. Chaque port est relié à de circuits chargés de gérer le port. Ces circuits reçoivent des trames, les envoient et effectuent quelques traitements basiques. Ils gèrent notamment tout ce qui a trait aux adresses MAC. Une fois que ces circuits ont fait leur office, ils envoient la trame traitée sur le bus interne au routeur. La trame est alors réceptionnée par le processeur, éventuellement stockée en mémoire RAM. Celui-ci accède alors à la table de routage, pour identifier le port de sortie. Enfin, le processeur envoie la trame vers le port de sortie qu'il a déduit de ses traitements. La trame est alors envoyée sur le réseau. Le défaut principal de ce type de routeur est que les transferts en direction du processeur principal saturent le bus dans certaines situations critiques. [[File:1st-generation router architecture.svg|centre|vignette|1st-generation router architecture]] ===Routeurs de seconde génération=== Les routeurs de seconde génération sont plus complexes. Ceux-ci multiplient le processeur, la RAM et la table de routage en plusieurs exemplaires : un exemplaire par port. Ainsi, les trames reçues sur un port sont directement traités dans les circuits de gestion de ce port. Une fois traitée, elles sont envoyées directement sur le port de sortie, et envoyée immédiatement sur le réseau. Cependant, cela ne vaut que pour des trames simples. Les trames plus complexes doivent être traitées par un processeur plus complexe, non-attaché à un port. Ce processeur, le superviseur, est unique dans le routeur. [[File:2nd-generation router architecture.svg|centre|vignette|2nd-generation router architecture]] ===Routeurs de troisième génération=== Cependant, les deux types de routeurs précédents utilisent un bus pour afin de faire communiquer les différents composants. Or, il se peut que les conflits d'accès au bus minent les performances. Pour éviter cela, certains routeurs remplacent le bus par une switch fabric, pour gagner en performance. Ainsi, les transfert n'entrent pas en conflit pour l'accès à un unique bus, chaque transfert pouvant se faire en parallèle des autres. [[File:3rd-generation router architecture.svg|centre|vignette|3rd-generation router architecture]] ==La carte réseau== La '''carte réseau''' est le composant qui permet à notre ordinateur de communiquer sur un réseau (local ou internet). Elle permet d'envoyer ou de recevoir des informations sur un câble réseau ou une connexion WIFI. Pour mieux comprendre son fonctionnement et les rôles qu'elle doit jouer, je vous conseille la lecture de mon wikilivre sur les [[Les réseaux informatiques|réseaux informatiques]], et notamment la lecture du chapitre sur la [[Les réseaux informatiques/La couche liaison|couche liaison]]. La carte réseau communique avec le reste de l'ordinateur via le bus de la carte mère. Les données échangées sont mémorisées temporairement dans une mémoire tampon. Celle-ci permet de mettre en attente les données à envoyer tant que le réseau n'est pas disponible, ou d'accumuler les données reçues en attendant de les recevoir complètement. Ces données sont ensuite gérées par un circuit qui s'occupe de gérer les aspects réseau de la transmission : ajout/retrait des adresses MAC pour l'encapsulation, calcul de la somme de contrôle. Ce circuit est suivi d'une mémoire appelée la fenêtre glissante, qui contrôle l'ordre d'envoi des paquets. La carte réseau contient ensuite un circuit qui transforme les données à transmettre en ondes WIFI ou en signaux électriques (pour les câbles réseau). Dans tous les cas, les transferts d'informations se font en série (le câble est l'équivalent d'un bus série). L'interface de transfert contient donc deux registres à décalage : un pour faire la conversion parallèle -> série, et un autre pour la conversion série -> parallèle. En parallèle, on trouve un circuit qui détecte les conflits d'accès aux bus et qui les gère. [[File:Architecture matérielle d'une carte réseau.png|centre|vignette|upright=2|Architecture matérielle d'une carte réseau.|800px]] <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'accélération matérielle de la virtualisation | next=La tolérance aux pannes }}{{AutoCat}} </noinclude> 5jymua00q2ylgt05tt3voj929kajhew Fonctionnement d'un ordinateur/Les architectures neuromorphiques 0 69056 772085 765830 2026-09-12T17:02:45Z Mewtow 31375 /* Simuler un neurone à partir de circuits analogiques usuels */ 772085 wikitext text/x-wiki La recherche n'hésite pas à s'inspirer de tout et n'importe quoi pour créer de nouvelles manières de faire des calculs. Par exemple, des systèmes de traitement de l’information s'inspirant de la biologie ont vu le jour. Il existe des calculateurs non-programmables à base d'ADN, spécialisés pour des problèmes bien précis. Et il y a aussi des ordinateurs plus ou moins inspirés du fonctionnement du cerveau humain. Dans ce chapitre, nous allons nous intéresser à deux choses : les '''réseaux de neurones matériels''' et les '''architectures neuromorphiques'''. Les deux s'inspirent fortement du cerveau humain et du système nerveux, surtout les architectures neuromorphiques. Les réseaux de neurones sont des systèmes capables d'apprendre presque seuls, à partir d'exemples. L'intelligence artificielle moderne utilise ces réseaux de neurones. Les réseaux de neurones peuvent se classer en deux types : ceux qui apprennent tout seuls sont appelés des ''réseaux de neurones non-supervisés'', alors que ceux qui ont besoin d'être aidés par un humain qui corrige leurs erreurs sont appelés des ''réseaux de neurones supervisés''. Pour les réseaux non-supervisés, le réseau de neurone peut apprendre tout seul à partir d'exemples et est capable de catégoriser de lui-même les entrées qu'on lui fournit. Ce genre d'apprentissage automatique (on dit aussi non-supervisé) est très efficace pour une grande classe d'applications : reconnaissance des visages, reconnaissance d'émotion, rétines artificielles, vidéo-surveillance intelligente, systèmes de contrôle de moteurs, etc. En temps normal, les réseaux de neurones sont mis en œuvre par un logiciel, qui simule le fonctionnement d'un réseau de neurones. Et il existe des accélérateurs d'IA capables d'accélérer les calculs des réseaux de neurones. De plus, dans ce chapitre, nous allons voir des exemples de réseaux de neurones implémentés en matériel. La différence entre accélérateurs d'IA et réseaux de neurones matérielles deviendra plus claire à la fin du chapitre. Mais pour le dire rapidement, l'IA a un but pratique où le résultat compte plus que le réalisme des réseaux de neurones implémentés. À l'opposé, les architectures neuromorphiques visent à se rapprocher du cerveau humain, elle vise à implémenter des réseaux de neurones proches des neurones réels, en espérant que cela permette d'obtenir de meilleurs résultats. La différence se manifeste en pratique sur les neurones utilisés. L'intelligence artificielle actuelle et passée utilise surtout des neurones très simples, qui n'ont pas grand chose à voir avec les neurones biologiques. Il ne s'agit pas de simulations de neurones biologiquement réalistes. Pour faire la différence, nous parlerons de neurones artificiels. Les circuits pour simuler un neurone artificiel se résument à des circuits additionneurs/multiplieurs. Par contre, les neurones plus réalistes demandent des circuits beaucoup plus complexes, qu sont presque toujours analogiques. Cette différence entre neurones très simples d'un côté et véritable simulation du tissu neuronal de l'autre, est une distinction qui va organiser ce chapitre. Nous allons d'abord voir des circuits basés sur des neurones simples, puis de véritables circuits neuromorphiques. Les deux seront séparés dans plusieurs sections différentes. Une première section va parler des anciens perceptrons matériels, suivi par une section sur les accélérateurs d'IA numériques, avant qu'une troisième section parle des véritables architectures neuromorphiques. En introduction de chaque section, on trouvera une introduction aux notions biologiques utiles. ==Les perceptrons et réseau de Hopfield : la théorie== Les premiers réseaux de neurone que nous allons aborder sont basés sur des neurones artificiels les plus simples qui puissent existe. Mais pour comprendre comment ils fonctionnent, il est intéressant de faire une analogie avec un vrai neurone. Même si les percetrons n'utilisent pas des neurones réalistes, ils s'inspirent de leur fonctionnement d'une manière superficielle. Et cette analogie se comprend bien à partir des vrais neurones. ===Rappels de base sur les neurones biologiques=== Les cellules du cerveau sont appelées des '''neurones'''. Il existe un grand nombre de neurones différents, qui se différencient par leur taille, leur forme, ou quelques autres paramètres. Mais tous ces neurones gardent malgré tout des points communs quant à leur forme. Si on omet certaines classes de neurones un peu particulière, un neurone a une forme canonique en 4 parties. Les neurones de ce type, dit multipolaires, sont composés : * d'une dendrite souvent en forme d'arbre, très touffue ; * d'un soma, un corps cellulaire avec le noyau au milieu ; * d'un axone avec un ensemble de boutons synaptiques à son extrémité. [[File:Neurone français schéma.svg|centre|vignette|upright=2|Neurone, français schéma]] Les neurones sont parcourus par des influx nerveux, des sortes de "courants électriques" qui passent de neurones en neurones et se propagent à travers tout le système nerveux. Le terme technique n'est pas '"influx nerveux", mais "potentiel d'action". Les potentiels d'action ne sont pas des courants électriques, comme on pourrait le croire. Ce sont des pics de tension qui parcourent le neurone sur ses dendrites, ou sur son axone. Lorsque le neurone ne fait rien, une tension d'environ – 70 millivolts est présente sur sa membrane. Lorsqu'un influx nerveux passe, cette tension augmente localement. La forme de ce pic de tension est illustrée ci-dessous. Il faut noter que les potentiels d'action sont tous les mêmes. L'amplitude de la tension est la même pour tous les potentiels d'action, elle ne varie pas, pas plus que la durée du potentiel d'action. On dit que ceux-ci sont en tout ou rien. [[File:Action potential (no labels).svg|centre|vignette|upright=2|Potentiel d'action.]] Un potentiel d'action se propage sur le neurone, que ce soit sur sa dendrite ou sur son axone, mais il peut aussi passer d'un neurone à l'autre. Pour cela, les neurones sont reliés entre eux par ce qu'on appelle des '''synapses'''. Une synapse connecte l'axone d'un neurone aux dendrites d'un autre. Le potentiel d'action est généré au milieu du neurone, dans la zone appelée le soma. Il se propage alors sur l'axone, qui sert en quelque sorte de câble de transmission du potentiel d'action. Là, l'axone entre dans la synapse et passer dans la dendrite d'un autre neurone. Il se propage alors sur la dendrite et arrive au soma. Au niveau du soma, il donne éventuellement naissance à un nouveau potentiel d'action sur l'axone. Pour simplifier drastiquement, le soma fait la somme de tous les potentiels d'action qui arrivent sur ses dendrites à un moment donné. Si cette somme dépasse un seuil fixé à l'avance, alors le neurone émet un potentiel d'action sur son axone. Dans le cas contraire, il n'émet rien. [[File:Description fonctionnelle du fonctionnement d'un neurone.png|centre|vignette|upright=2|Description fonctionnelle du fonctionnement d'un neurone]] Les synapses ne sont pas fixes et peuvent se reconfigurer : de nouvelles synapses peuvent se créer, d'autres mourir, etc. De plus, l'efficacité d'une synapse à transmettre les potentiels d'action varie dans le temps. L'ensemble de ces phénomènes s'appelle la '''plasticité synaptique'''. Ce serait le mécanisme qui nous permettrait d'apprendre. Autant dire que simuler la plasticité est primordial pour obtenir des circuits qui apprennent tous seuls. ===Les neurones artificiels d'un perceptron=== Un perceptron utilise des neurones simplifiés. Les neurones simplifiés sont appelés des '''neurones artificiels''', aussi appelés des ''perceptrons''. Leur fonctionnement copie le fonctionnement basique d'un neurone, mais appliqué au domaine numérique. Si les neurones sont fondamentalement analogiques, les neurones artificiels en sont une sorte d'équivalent numérique. Le potentiel d'action est un pic de tension foncièrement analogique dans les détails, mais qui a un comportement en tout ou rien. Pour rappel, tous les potentiels d'action sont identiques, leur durée et leur tension est tout le temps la même. Ce comportement en tout ou rien du potentiel d'action est simulé en codant un potentiel d'action par un bit : 0 en absence de potentiel d'action à un instant t, 1 en cas de survenue d'un potentiel d'action. Cela permet d'utiliser un encodage non seulement numérique, mais aussi binaire, ce qui nous arrange bien. Un neurone est donc simulé par un circuit qui prend en entrée un ou plusieurs bits, et fournit en sortie un ou plusieurs bits. Pour gérer son interface, les neurones artificiels s'inspirent de la forme d'un neurone avec des dendrites et un axone. Ils ont donc plusieurs entrées et une seule sortie : la sortie unique représente l'axone, il y a une entrée par dendrite. Pour simplifier, ils reçoivent des bits sur leur entrée et fournissent un bit en sortie. Les bits d'entrées représentent les potentiels d'action reçus par le neurone, le bit de sortie indique si le neurone a émis un nouveau potentiel d'action. [[File:Neuron3.png|centre|vignette|upright=2|Analogie entre un neurone réel et un circuit.]] Le fonctionnement d'un neurone simplifié vu précédemment est assez simple. Il fait la somme de tous les potentiels d'actions qui arrivent sur ses dendrites, et émet un potentiel d'action si la somme dépasse un certain seuil. Ce comportement est directement reproduit par un neurone artificiel : il fait la somme de ses entrées et compare la somme à un seuil. Le plus compliqué est de simuler la plasticité synaptique. Pour cela, on suppose que celle-ci vient d'une évolution de la sensibilité des synapses. Elles laissent plus ou moins bien passer les potentiels d'action. Pour simuler cela dans un neurone artificiel, les bits d'entrées sont multipliés par un coefficient multiplicateur, appelé le '''poids de la synapse''', qui représente la sensibilité d'une synapse. Il y a un poids différent par synapse, donc un coefficient différent par entrée. Pour résumer, les bits d'entrée sont multipliés par un coefficient multiplicateur, qui est un nombre à virgule flottante ou entière. Les résultats des multiplications sont additionnés entre eux, pour simuler l'action du soma du neurone, son corps cellulaire. Puis le résultat passe dans une fonction qui transforme la somme en un bit de sortie, qui représente le potentiel d'action produit par le neurone. La fonction est une simple comparaison entre la somme et un seuil configurable. [[File:ANN neuron.svg|centre|vignette|upright=2|Neurone artificiel comparé à un neurone réel.]] Pour résumer, un neurone artificiel effectue le calcul suivant : : <math>\text{Sortie} = f\left[ \sum^i (a_i \times w_i) \right]</math>, avec <math>w_i</math> les poids de chaque synapse et f une fonction qui calcule le bit de sortie. Une alternative ajoute un biais à la somme précédente : : <math>\text{Sortie} = f\left[ \sum^i (a_i \times w_i) + \text{biais} \right]</math>, le biais étant une sorte de seuil ajouté. Implémenter un neurone artificiel est assez simple : il suffit de circuits multiplieurs pour les poids, d'un additionneur pour le soma et d'un comparateur pour la sortie. Et les trois peuvent s'implémenter de manière soit purement numérique, soit analogique. Les implémentations numériques sont généralement des circuits de calcul flottants basiques. Les implémentations analogiques utilisent souvent des circuits basés sur des amplificateurs opérationnels, ou quelque chose d'approchant. [[File:ArtificialNeuronModel francais.png|centre|vignette|upright=2|Neurone artificiel.]] ===Les règles d'apprentissage : la Perceptron Learning Rule=== L'apprentissage se fait en faisant évoluer les poids dans le temps. Les poids évoluent quand l'utilisateur indique que le réseau fournit une mauvaise réponse. Pour cela, il existe plusieurs '''règles d'apprentissage''' qui décrivent comment les poids doivent évoluer. Mais elles dépendent beaucoup du perceptron utilisé. La règle d'apprentissage est intégrée dans le neurone. Généralement, les poids des synapses sont mémorisés quelque part, dans un circuit spécialisé. Un circuit spécialisé lit ces poids et les modifie, ce qui permet de modifier les poids. Le calcul réalisé par ce circuit varie grandement selon la règle d'apprentissage utilisée. Une règle d'apprentissage simple est la suivante, appelée la '''''Perceptron Learning Rule''''' (PLR). L'idée est que les poids sont adaptés en cas d'erreur, en fonction de l'entrée. En premier lieu, on compare la sortie attendue et celle fournie par le perceptron, on calcule la différence. La différence vaut 0, 1 ou -1. Elle vaut 0 si le perceptron a raison. Elle vaut 1 si le perceptron a sorti un 0 alors qu'on attendait un 1, elle vaut -1 dans le cas inverse. Cette différence dit s'il faut augmenter ou réduire les poids. Reste à savoir de quel montant. Une idée serait d'additionner ou soustraire une valeur fixe, mais ce ne serait pas une bonne idée. Une méthode plus efficace additionne ou soustrait une valeur qui est proportionnelle à l'entrée. Ainsi, les synapses avec un bit d'entrée à 1 sont modifiées, pas celles où le bit d'entrée est à 0. Pour cela, les poids sont rassemblés dans un vecteur, les bits de l'entrée sont rassemblés dans un autre vecteur. L'idée est de multiplier le vecteur d'entrée par un coefficient multiplicateur et de l'ajouter/soustraire au vecteur des poids. Le coefficient multiplicateur est choisit assez petit pour faire converger le réseau lentement, afin que les résultats finaux soient assez précis. Il y a trois cas, qui sont résumés dans les formules suivantes. On note <math>\eta</math> le coefficient, <math>x_i</math> le bit envoyé sur l'entrée i, <math>\Delta w_i</math> ce qu'on ajoute/soustrait au poids de la synapse. : <math>\Delta w_i = 0</math> : si le perceptron ne s'est pas trompé. : <math>\Delta w_i = \left( \eta \times x_i \right)</math> : si le perceptron sort un 1 au lieu d'un 0. : <math>\Delta w_i = - \left( \eta \times x_i \right)</math> : si le perceptron sort un 0 au lieu d'un 1. Le tout cela est résumé avec la formule suivante, en notant D la différence calculée : : <math>\Delta w_i = \left( \eta \times x_i \right) \times D</math> ===Les perceptrons et autres réseaux de neurones artificiels=== Maintenant que l'on a un neurone artificiel, il faut les interconnecter entre eux pour obtenir un réseau de neurones. Pour cela, il y a plusieurs méthodes. La plus simple d'entre elle place plusieurs neurones les uns à côté des autres, sans les relier. On dit alors qu'il y avait une seule couche de neurones. Quelques machines fonctionnaient sur ce principe, comme l'ADALINE, qu'on verra plus bas. [[File:Neural network example.svg|vignette|perceptron basique.]] Mais à part ces rares exceptions, les réseaux de neurones disposent de plusieurs couches de neurones, connectées entre elles. Les réseaux de neurones les plus simples sont ceux utilisées ci-contre. Un tel réseau est appelé un '''perceptron'''. Ils ont deux à trois couches, chaque couche est connectée uniquement à la suivante. Les perceptrons implémentent des classifieurs binaires, terme barbare pourtant simple à comprendre. Un classifieur binaire prend en entrée un exemple et dit si celui-ci appartient ou non à une catégorie précise. Par exemple, si on lui présente une photographie d'animal, le réseau sera entrainé pour dire si la photo est celle d'un chat ou non. Le résultat est toujours une réponse de type oui/non, d'où le terme binaire. Le résultat peut être représenté sous la forme d'un bit : 0 si la réponse est "faux", 1 pour un "vrai". Le réseau de neurone est entrainé en lui présentant des exemples divers, mais il n'apprend pas tout seul. Un utilisateur doit l'entrainer en précisant si ses réponses sont bonnes ou non. Le réseau fournit une réponse à chaque exemple, l'utilisateur lui dit si sa réponse est bonne ou non. En fonction de la réponse de l'utilisateur, le réseau de neurone s'adapte et se modifie, il apprend. [[File:Nonlinear separable.JPG|centre|vignette|Nonlinear separable]] [[File:Hopfield-net-vector.svg|vignette|Réseau de Hopfield.]] D'autres réseaux de neurones autorisent des boucles dans le réseau, à savoir que la sortie d'un neurone est bouclée sur l'entrée d'un neurone précédent, dans une couche précédente. Les plus simples sont les '''réseaux de Hopfield'''. Sans rentrer dans les détails mathématiques très complexes de ce genre de réseaux, ils sont composés d'une à deux couches, dont l'une est bouclée sur elle-même. Chaque neurone émet un axone en direction de tous les autres neurones de la même couche. ==Les implémentations matérielle de perceptrons== Maintenant que nous avons vu la théorie, nous allons voir comment de tels réseaux de neurones peuvent être implémentés physiquement, dans un ordinateur, avec des circuits matériels. Nous allons voir quelques exemples d'architectures ayant existé dans le passé, dont le but était de réellement implémenter des neurones en silicium. Nous laissons de côté les puces accélératrices d'IA récentes, car elles fonctionnent d'une manière totalement différente. ===L'ADALINE et le MADALINE=== Une implémentation d'un perceptron était l'ADALINE (''Adaptive Linear Neuron or later Adaptive Linear Element''). Elle était un bel exemple de circuit analogique. Si les entrées du circuit sont des bits, donc des données numériques, tout est converti à l’intérieur du neurone en tensions analogiques. D'ailleurs, la tension de sortie était analogique, avec une valeur allant de -1 à 1 volt. Et les bits d'entrées étaient codés avec une tension valant soit 1 volt, soit -1 Volt. Le réseau de neurone n'avait qu'une seule couche de neurones indépendants, comme illustré ci-dessous. [[File:Adaline.jpg|centre|vignette|upright=2|Architecture de l'ADALINE.]] Les multiplieurs pour les poids étaient initialement implémentés par de simples potentiomètres, réglés par l'utilisateur.. Vu que c'était des potentiomètres, on pouvait faire varier le poids en les tournant. Le perceptron n'avait donc pas de circuit d'entrainement proprement dit, on devait régler les potentiomètres à la main, la machine ne pouvait pas faire varier les poids d'elle-même. Un biais était ajouté via un potentiomètre séparé, relié à une de ces entrées (le a0 dans le schéma ci-dessous). [[File:Schematic of adaline.png|centre|vignette|upright=2|Un neurone de l'ADALINE.]] Sur la façade de la machine, on trouvait 16 interrupteurs qui servaient à configurer ce qu'on envoyait sur l'entrée du perceptron. On trouvait aussi 16 potentiomètres pour les poids, ainsi qu'un potentiomètre pour configurer le biais. Niveau sortie, il y avait un cadran de voltmètre qui permettait de mesurer la tension de sortie du circuit. Et n'oublions pas le bouton pour allumer la machine [[File:Knobby ADALINE.jpg|centre|vignette|upright=2|Interface de l'ADALINE.]] [[File:Adaline flow chart.gif|vignette|Adaline, implémentation simplifiée.]] La seconde version de l'ADALINE était appelé la MADALINE (''Memistor Adaptive Linear Neuron or later Adaptive Linear Element''). Elle utilisait quant à elle trois couches de neurones successives. La différence majeure avec l'ADALINE est que les potentiomètres des poids étaient remplacés par un composant appelé un memistor, capable d'une capacité de mémorisation. Memisoter qui ne doit pas être confondu avec le mem'''r'''istor, qui est un autre composant. L'avantage est que cela rendait la puce capable d'apprendre d'elle-même. Un algorithme d'apprentissage était intégré dans la machine, sans avoir besoin de régler les potentiomètres eux-mêmes. D'ailleurs, sur la facade de la machine, on trouvait 16 interrupteurs qui servaient à configurer les bits d'entrée du perceptron, mais les potentiomètres avaient disparus. Pour information, Bernard Widrow, un des concepteurs de l'ADALINE/MADALINE, a publié deux vidéos youtube pour présenter son travail. Dans la seconde vidéo, il présente l'ADALINE et la MADALINE, montre comment elles fonctionnent, les manipules, etc. La première vidéo explique l'algorithme d'apprentissage utilisé dans la MADALINE. Voici un lien vers ces deux vidéos : * [https://www.youtube.com/watch?v=skfNlwEbqck The LMS algorithm and ADALINE. Part II - ADALINE and memistor ADALINE] * [https://www.youtube.com/watch?v=hc2Zj55j1zU The LMS algorithm and ADALINE. Part I - The LMS algorithm] ===La Mark I Perceptron machine=== [[File:Mark I Perceptron, Figure 2 of operator's manual.png|vignette|upright=1|La ''Mark I Perceptron machine'', photographie.]] La première implémentation d'un perceptron était la '''Mark I Perceptron machine'''. Il s'agissait d'un projet de recherche datant de 1958, dirigé par Rosenblatt . Il s'agissait d'un réseau de neurones à trois couches, donc quelque chose de plus complexe que l'ADALINE. La première couche n'appartenait pas au réseau de neurones proprement dit, mais convertissait les tensions provenant de 400 photodétecteurs en bits d'entrée. Les photodétecteurs étaient organisés en un carré de 20 capteurs de côté. La seconde couche avait 512 neurones artificiels, la troisième avait seulement 8 neurones artificiels. Les deux couches de neurones étaient appelées la couche d'association et la couche de réponse, abréviées A et R. Elles sont interconnectées via des potentiomètres, qui permettaient de configurer le poids de chaque connexion, de chaque synapse. Rosenblatt, le directeur du projet, voulait simuler le cerveau humain. Dans ce perceptron, la rétine était l'équivalent de la couche de photorécepteur, les couches de neurone étaient l'équivalent du cortex visuel (la portion du cerveau qui s'occupe de la vision). Les deux couches étaient peu, comparé aux nombreuses couches du cortex visuel. Les connexions entre la couche de photorécepteurs et la suivante étaient aléatoires, car Rosenblatt était persuadé que la rétine était connectée aléatoirement au cortex visuel. [[File:Organization of a biological brain and a perceptron.png|centre|vignette|upright=2.5|Organization du Mark I Perceptron, comparé à un modèle très simplifié du cerveau humain.]] ===L'ETANN d'Intel=== L'ETANN (''Electronically Trainable Analog Neural Network'') était un des tout premiers processeurs neuronal, une des toutes première architecture neuromorphique à avoir existé. Elle a été annoncé en 1989 et a été commercialisée la même année. Elle gérait deux couches de 64 neurones chacune, interconnectés par 10240 synapses (80 synapses par neurone). Elle permettait 'implémenter un perceptron basique, avec cependant une option pour créer un réseau de Hopfield. La différence entre les deux étant que les sorties des neurones sont bouclées sur les entrées. Les neurones restent implémentés avec des circuits analogiques, à savoir des amplificateurs analogiques configurés en montage sommateur, couplés à un circuit multiplieur (la rumeur dit que c'était un multiplieur différentiel de Gilbert à 4 quadrant). Le tout était suivi par 64 circuits pour générer les potentiels d'action (une fonction sigmoïde matérielle). L'ETANN incorporait beaucoup de synapses, donc beaucoup de poids. Pour tous les gérer, Intel a du recourir à une solution assez élégante : mémoriser les poids dans une mémoire, séparée des autres circuits. Intuitivement, le choix aurait du porter sur une mémoire RAM, mais ils étaient en réalité mémorisés dans une mémoire EEPROM non-volatile. Les poids des synapses étaient des entiers en virgule fixe codés sur 8 bits, donc en binaire, pas en analogique. Avant d'être envoyés au neurone, les poids devaient être convertis en tensions analogiques, avec un convertisseur numérique-analogique dédié. [[File:Microarchitecture de l'ETANN.png|centre|vignette|upright=2.5|Microarchitecture de l'ETANN]] Le fait que les poids étaient mémorisés dans une EEPROM avait autant de défauts que de désavantages. Des avantages car il n'y avait pas besoin de circuits de rafraichissement, nécessaires pour les DRAM. Par contre, les changements de poids étaient lents, ce qui fait que la puce n'était pas très rapide. Et la quantité de reprogrammation était limitée à quelques dizaines ou centaines de millions de réécritures, au-delà lesquelles la EEPROM s'abimait. Mais une fois que le circuit avait été entrainé, il n'y avait plus besoin de changer les poids. L'architecture de l'ETANN a été décrite dans deux articles, qui ne sont malheureusement plus facilement accesibles librement sur le net. Voici les noms de ces deux articles : * "An electrically trainable artificial neural network (ETANN) with 10240 floating gate synapses." * "Implementation and performance of an analog nonvolatile neural network." ==Les accélérateurs d'applications d'intelligence artificielle== Les architectures précédentes utilisaient toutes des neurones analogiques, au moins partiellement. La raison est qu'un circuit binaire équivalent aurait utilisé beaucoup de portes logiques. Imaginez : une dizaine/centaine de circuits multiplieurs, suivis par un circuit additionneur multiopérande. L'implémentation binaire aurait été très gourmande en portes logiques. Et ce même en utilisant des poids entiers, alors que les poids flottants codés sur 16/32 bits donnent de meilleurs résultats. Cependant, ce n'est plus vraiment un problème de nos jours. La loi de Moore et la miniaturisation qui en découle ont changé la donne. Autant les ordinateurs des années 50-90 devaient faire avec un budget en transistor limité, autant les puces modernes peuvent parfaitement implémenter des neurones artificiels avec des circuits binaires. Et elles ne s'en privent pas, il existe de nombreuses puces dites '''accélératrices d'IA''' qui effectuent des calculs entiers/flottants pour émuler un neurone artificiel. Cependant, n'allez pas croire qu'elles implémentent des neurones directement en matériel, elles font autrement. ===La représentation matricielle d'un réseau de neurone=== Les perceptrons sont des réseaux très simples, surtout comparé aux réseaux de neurones modernes. Ces derniers sont beaucoup plus complexes, avec plusieurs centaines de couches et des interconnexions très complexes entre elles. La majorité des applications d'intelligence artificielle utilise des réseaux de neurones de ce genre. Pour de telles applications, le réseau de neurone est implémenté en logiciel, avec une implémentation particulière. Le réseau de neurone est représenté par une matrice. Les interconnexions entre neurones sont mémorisées dans des matrices, qui mémorisent le poids de chaque synapse. Les bits de sortie de chaque couche de neurone forment un vecteur, ce qui fait que les calculs se résument à multiplier des vecteurs d'entrée par une matrice de poids, pour obtenir le vecteur de sortie. Les accélérateurs d'IA sont conçus pour faire de tels calculs matriciels. [[File:Fully connected neural network and it's expression as a tensor product.jpg|centre|vignette|upright=2|Réseaux de neurone représenté par une matrice.]] : Une telle représentation est liée au fait qu'un graphe peut être encodé par une matrice. Ici, le graphe formé par les neurones et leurs interconnexions est représenté par une matrice de connectivité, améliorée pour tenir compte des poids des synapses. ===Les accélérateurs d'intelligence artificielle=== Des puces ont été inventées pour accélérer ces calculs matriciels, pour accélérer en priorité les logiciels d'intelligence artificielle. Aussi, elles sont appelées '''accélérateur d'IA'''. Elles sont fortement différentes des précédentes, dans le sens où elles n'implémentent pas des neurones en matériel, mais effectuent simplement des calculs matriciels. Là où les simulateurs de neurones implémentent des perceptrons, voire des équations différentielles, les accélérateurs d'IA font des calculs sur des matrices, qui contiennent des nombres flottants. Pour accélérer les calculs, elles utilisent souvent des flottants spécialisés, avec une faible précision, qui sont codés sur 16 bits, rarement 32. Les accélérateurs d'IA exécutent quasi-exclusivement des additions et des multiplications matricielles, qui s'implémentent avec des additions et multiplications arithmétiques usuelles. Les accélérateurs l'IA sont spécialisés pour réaliser en parallèle un très grand nombre d'opérations MAD (une multiplication suivie d'une addition). En soi, les circuits MAD ne sont pas compliqués, mais la difficulté tient à lire/écrire un grand nombre d'opérandes depuis la mémoire. La hiérarchie mémoire de ces accélérateurs est donc assez compliquée. Les accélérateurs l'IA sont spécialisés pour exécuter un très grand nombre d'opérations arithmétiques en parallèle. Les processeurs récents ne sont pas capables de faire autant que calculs en parallèle que nécessaire, mais les cartes graphiques récentes le peuvent. Ce qui explique que les cartes graphiques récentes incorporent des technologies pour accélérer les calculs d'IA. Par exemple, les cartes NVIDIA récentes incorporent des cœurs ''Tensor Core'' spécialisés dans les calculs matriciels, ces derniers étant fortement utilisés dans les réseaux de neurones logiciels. On peut classer les accélérateurs en deux types : les architectures temporelles et spatiales. Les '''architectures temporelles''' lisent toutes les opérandes depuis une mémoire globale, avec éventuellement des caches ou des ''local store'' pour limiter la casse. Elles sont composées d'un grand nombre d'unités de calcul, de circuits de contrôle et d'une mémoire RAM de grande capacité. Les '''architectures spatiales''' sont composées d'un grand nombre de cœurs, qui disposent chacun de sa propre mémoire associée. Les coeurs sont reliés entre eux par un réseau d'interconnexion complexe. [[File:Brainchip NPU Mesh.png|centre|vignette|upright=2|Architectures spatiale.]] : Une revue des architecture utilsiées sur les accélérateurs d'IA de Google, les fameux TPU, est disponible ici : [https://considerthebulldog.com/tte-tpu/ Touching the Elephant - TPUs, Understanding the Tensor Processing Unit] ==Les architectures neuromorphiques== Passons aux architectures neuromorphiques. Avant toute chose, précisons que nous allons faire une séparation totalement arbitraire entre perceptrons matériels et architectures neuromorphiques. La séparation est liée à l'implémentation du neurone. Les architectures précédentes se contentent de neurones simples, très simples, qu'on peut émuler avec des multiplieurs-additionneurs. Mais les architectures neuromorphiques utilisent des neurones plus réalistes, plus complexes. Elles cherchent à simuler le cerveau humain, à être réaliste au point de vue cellulaire. Les architectures neuromorphiques mélangent circuits numériques et circuits analogiques. Les poids des synapses sont mémorisés dans une mémoire RAM, alors que les neurones sont implémentés en analogique. Pour faire l'interface entre les deux, le circuit intègre des circuits de conversion analogique-numérique, ainsi que des circuits de conversion inverse, entre la mémoire et les neurones/synapses. Il n'y a pas le choix, les modèles réalistes des neurones se basent sur des équations différentielles dont l'implémentation est beaucoup plus simple en analogique. Surtout que l'on a pas besoin d'une précision importante et que l'imprécision des circuits analogiques n'est alors pas un problème. Les architectures neuromorphiques sont donc des '''circuits hybrides analogiques-numériques'''. Si vous voulez un aperçu de l'état de l'art sur le sujet, voici des liens qui devraient vous intéresser : * [https://www.frontiersin.org/journals/neuroscience/articles/10.3389/fnins.2011.00073/full Neuromorphic silicon neuron circuits] * [https://www.sciencedirect.com/science/article/pii/S2095809919306356 A Survey of Accelerator Architectures for Deep Neural Networks] ===Historique partiel des architectures neuromorphiques=== Mine de rien, la simulation logicielle d'un système nerveux, même simple, demande beaucoup de puissance de calcul. Par exemple, Markam, un des utilisateurs du supercalculateur Blue-gene a déclaré qu'il était capable de simuler seulement 50.000 neurones en temps réel biologique (à la même vitesse que ce qui se passe dans un vrai réseau de neurones). Pour simuler 1 millions de neurones, cela prendrait 8 à 10 fois plus de temps que le temps réel biologique et serait réellement impraticable. Mais avec les technologies VLSI récentes, on peut créer des circuits électroniques capables de simuler des réseaux de neurones matériels. On peut ainsi créer des circuits électroniques qui fonctionnent comme un neurone, dans le sens où la tension et le courant à leurs bornes suit les mêmes équations qu'un neurone. Ce n'est pas la première fois que des chips matériels sont créés pour accélérer des simulations très spécifiques. Il existe par exemple des systèmes matériels spécialement conçus pour les simulations physiques de champ électriques ou gravitationnels, comme le projet GRAPE. Quelques puces neuromorphiques ont vu le jour. Au niveau industriel, il y a quelques puces basées sur ce principe. * Une entreprise du nom de CogniMem a déjà commercialisé un accélérateur neuromorphique comprenant trois couches de respectivement 256, 1024, et 16392 neurones. L'ensemble fonctionne à la fréquence de 27 Mhz. * En 2014, IBM a sorti sa puce TrueNorth, utilisée dans le projet SyNAPSE du DARPA, ce dernier a permis de créer une carte accélératrice qui se connecte sur PC via un port US. La puce TrueNorth contient 4096 coeurs, chacun contient 256 neurones, reliés entre eux par 262144 (256*256) synapses. * En 2017, Intel a sorti sa puce Loihi. D'autres projets d'architectures neuromorphiques avaient pour but avoué de simuler un cerveau humain, ou du moins une portion de celui-ci, afin de faire avancer la biologie. Le projet BrainScaleS est à l'origine d'un circuit VLSI de 200000 neurones et 49 millions de synapses. Le projet Neurogrid du groupe de recherche "brain in silicon", de l'université de Stanford. Celui travaille sur la simulation du cortex, une région du cerveau qui contient des neurones spécialisés appelés neurones pyramidaux. Ce groupe de recherche a déjà créé une puce non-programmable : le câblage des synapses ne peut pas être modifié, mais les paramètres des synapses sont configurables. Enfin, certains chercheurs du MIT ont créé un simulateur matériel simulant quelques neurones, dans un but de recherche fondamentale sur le comportement des récepteurs endo-cannabinoide de la membrane des neurones. ===La modélisation théorique d'un neurone et d'une synapse=== Comme dit plus haut, les architectures neuromorphiques utilisent des neurones artificiels assez réalistes. Aussi, vous ne serez pas étonnés d'être obligés de voir ce qu'est un neurone et une synapse en détail avant de poursuivre. Préparez-vous : le cours de biologie arrive. Simuler le véritable comportement d'un neurone ou d'une synapse coûterait vraiment beaucoup de circuits. À la place, les concepteurs de simulateurs logiciels et matériels utilisent des neurones simplifiés, dont la relation entre tension et courant (influx nerveux) est décrite par une équation relativement simple, et surtout approximative. Le premier type de neurone se base sur un principe relativement simple : il modélise le principe qui est derrière la conduction de l'influx nerveux. Pour commencer, il faut savoir que l'influx nerveux n'est pas, comme on pourrait le croire, un courant électrique qui parcours l'axone et les dendrites. Les axones et les dendrites ne sont pas des câbles électriques. À la place, cet influx nerveux consiste en une onde de tension, qui se propage sur des segments d'axone, et éventuellement de dendrites (dans la suite, je ne parlerais que d'axone par simplicité). Mais d'où sort cette onde de tension ? Simple : le neurone est une cellule comme une autre, dans laquelle l'intérieur et l'extérieur sont séparés par une membrane : la membrane plasmique. Des deux côtés de cette membrane, on trouve respectivement le milieu intra-cellulaire (dans la cellule), et extra-cellulaire (en-dehors de la cellule). Ces deux milieux sont composés d'une solution qui mélange de l'eau, diverses molécules, et surtout : quelques ions, des atomes de charge non-neutre. En conséquence, chacun de ces milieux est relativement conducteur. L'ensemble forme donc un ensemble formé de deux milieux conducteurs, séparés par une membrane isolante. Deux morceaux de conducteur séparés par un isolant, cela ressemble fortement à un composant électronique que l'on nomme le condensateur. Conséquence : la membrane se comporte comme un condensateur. Des deux côtés de la membrane, les quantités d'ions ne sont pas les mêmes. Par exemple, les quantités de calcium, potassium, et sodium, changent suivant le côté de la membrane où l'on se place. Cela vient du fait que la membrane est percée par de nombreuses molécules qui servent de pompes. Ces pompes vont expulser les ions d'un côté de la membrane vers l'autre côté. Ces pompes vont fonctionner jusqu'à ce que la concentration en ions de l'autre côté de la membrane devienne trop forte. En conséquence, l'intérieur et l'extérieur sont chargés différemment, donnant naissance à une tension de repos, d'environ -70 millivolts. Ces pompes peuvent donc se modéliser comme une tension de repose fixe, de -70 millivolts à -30 millivolts (selon le neurone). Lors de l'émission d'un influx nerveux, de petites portes moléculaires vont s'ouvrir dans la membrane, et vont laisser passer sélectivement certains ions, et pas les autres. Ainsi, on va trouver des portes pour le potassium, d'autres pour le sodium, etc. Ces portes, des canaux ioniques, vont donc plus ou moins laisser passer un courant d'ions. Conséquence : ceux-ci sont modélisés par des résistances variables, qui laisseront plus ou moins bien passer le courant. En supposant que seul un seul type d'ion puisse passer la membrane, on trouve alors un condensateur, et une seule résistance. Si on suppose que plusieurs types d'ions peuvent passer la membrane, alors on trouve un modèle plus complexe, composé de plusieurs condensateurs et résistances en parallèle. Si les ions choisis sont le potassium, le sodium, et le calcium, les résistances et condensateurs auront des conductances et capacités d'une certaine valeur : on trouve un '''modèle de type Hodgkin-Huxley'''. [[File:MembraneCircuit.svg|centre|vignette|upright=2|Membrane Circuit]] Dans les deux cas, à partir de ces deux modèles de neurones, on peut obtenir une relation entre courant i et tension V qui a la forme d'une équation différentielle. ===Simuler un neurone à partir de circuits analogiques usuels=== [[File:Implémentation anlogique d'un neurone.jpg|vignette|Implémentation analogique d'un neurone.]] Les premières implémentations de neurones se basent sur des circuits analogiques. Cela vient du fait que dans les modèles de neurones, la tension évolue : * soit via une équation différentielle ; * soit, un potentiel d'action a lieu, faisant passer celle-ci à son maximum. Or, simuler convenablement en matériel l'équation différentielle ne peut se faire convenablement avec des circuits numériques. Quoique, certains ont déjà essayés, avec parfois de bons résultats. Mais il est communément admis que l'analogique est roi pour ce genre de situations. Quoiqu'il en soit, on trouve grosso-modo trois morceaux de circuit dans la majorité des implémentations matérielles de neurones : * un circuit qui simule "le poids de la synapse", sa sensibilité aux influx nerveux entrants ; * un circuit "mémoire", qui stocke l'état actuel de la tension, en faisant varier celle-ci par l'équation différentielle du modèle. * et un circuit qui détecte le dépassement du seuil, et émet un influx nerveux. Il y a aussi quelques subtilités, mais on va simplement parler de l'essentiel. Le circuit qui simule le poids de la synapse peut se résumer dans le cas le plus simple à un simple multiplieur analogique. Mais la majorité des design créent un générateur d'impulsions, des fronts de tension dont la durée dépend de la tension d'entrée (l'influx nerveux). Le circuit qui implémente l'équation différentielle de la membrane en dehors d'un potentiel d'action est conçu à base de résistances, de condensateurs, et éventuellement de bobines : n'importe quel électronicien vous dira que toute équation différentielle peut être modélisée par un circuit ne contenant que des sources de tension, des condensateurs, des bobines, et des résistances. Quant au circuit de détection du dépassement de seuil et de génération du nouvel influx nerveux, un simple amplificateur opérationnel correctement configuré peut suffire. Mais il faut signaler que chaque influx nerveux doit remettre la tension du neurone à la valeur de repos, ce qui demande quelques modifications sur le circuit de l'équation différentielle (un simple interrupteur bien placé peut suffire avec certains designs). Une solution plus silmple conceptuellement utilise des '''memristor''', un composant en cours de développement. Le memristor n'est pas un composant électronique bien précis, et divers modèles théoriques existent à ce jour, chacun d'entre eux ayant des comportements très différents. Ceux-ci peuvent être vus comme des résistances variables, avec quelques particularités. En conséquence, cette résistance a été renommée memristance, pour éviter les confusions. Si jamais du courant positif traverse un memristor, sa memristance augmente. Si le courant est négatif, elle diminue. En clair : ces composants ont une sorte de mémoire du courant qui les a traversés depuis leur initialisation. Pour rentrer dans les détails, la valeur de la memristance dépend de l'intégrale du courant qui est passé dans la memristance. Suivant les modèles de memristor, cette fonction varie énormément. Les memristors permettent de modéliser fidèlement une synapse : il suffit de faire en sorte que les courants qui simulent un influx nerveux soient relativement courts. Grosso-modo, la memristance correspond au poids de la synapse. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les architectures systoliques | prevText=Les architectures systoliques | next=L'accélération matérielle de la virtualisation | nextText=L'accélération matérielle de la virtualisation }} </noinclude> syookkq07olrc7kwe3z87jvwgjfud7t Fonctionnement d'un ordinateur/Sommaire 0 69596 772080 768624 2026-09-12T16:52:28Z Mewtow 31375 /* Les jeux d’instruction spécialisés */ 772080 wikitext text/x-wiki __NOTOC__ * [[Fonctionnement d'un ordinateur/Introduction|Introduction]] ==Le codage des informations== * [[Fonctionnement d'un ordinateur/L'encodage des données|L'encodage des données]] * [[Fonctionnement d'un ordinateur/Le codage des nombres|Le codage des nombres]] * [[Fonctionnement d'un ordinateur/Les codes de détection/correction d'erreur|Les codes de détection/correction d'erreur]] ==Les circuits électroniques== * [[Fonctionnement d'un ordinateur/Les portes logiques|Les portes logiques]] ===Les circuits combinatoires=== * [[Fonctionnement d'un ordinateur/Les circuits combinatoires|Les circuits combinatoires]] * [[Fonctionnement d'un ordinateur/Les circuits de masquage|Les circuits de masquage]] * [[Fonctionnement d'un ordinateur/Les circuits de sélection|Les circuits de sélection]] * [[Fonctionnement d'un ordinateur/Les circuits incrémenteurs/décrémenteurs|Les circuits incrémenteurs/décrémenteurs]] ===Les circuits séquentiels=== * [[Fonctionnement d'un ordinateur/Les bascules : des mémoires de 1 bit|Les bascules : des mémoires de 1 bit]] * [[Fonctionnement d'un ordinateur/Les circuits synchrones et asynchrones|Les circuits synchrones et asynchrones]] * [[Fonctionnement d'un ordinateur/Les registres et mémoires adressables|Les registres et mémoires adressables]] * [[Fonctionnement d'un ordinateur/Les compteurs et timers|Les compteurs et timers]] * [[Fonctionnement d'un ordinateur/Les registres à décalage et les LSFR|Les registres à décalage et les LSFR]] ===Les circuits de calcul et de comparaison=== * [[Fonctionnement d'un ordinateur/Les circuits de décalage et de rotation|Les circuits de décalage et de rotation]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition et la soustraction|Les circuits pour l'addition et la soustraction]] * [[Fonctionnement d'un ordinateur/Les circuits de comparaison|Les circuits de comparaison]] * [[Fonctionnement d'un ordinateur/Les unités arithmétiques et logiques entières (simples)|Les unités arithmétiques et logiques entières (simples)]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition multiopérande|Les circuits pour l'addition multiopérande]] * [[Fonctionnement d'un ordinateur/Les circuits pour la multiplication et la division|Les circuits pour la multiplication et la division]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul logique et bit à bit|Les circuits de calcul logique et bit à bit]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul flottant|Les circuits de calcul flottant]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul trigonométriques|Les circuits de calcul trigonométriques]] ===Les circuits intégrés à semi-conducteurs=== * [[Fonctionnement d'un ordinateur/Les transistors et portes logiques|Les transistors et portes logiques]] * [[Fonctionnement d'un ordinateur/Les circuits intégrés|Les circuits intégrés]] * [[Fonctionnement d'un ordinateur/L'interface électrique entre circuits intégrés et bus|L'interface électrique entre circuits intégrés et bus]] ==L'architecture d'un ordinateur== * [[Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur|L'architecture de base d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La hiérarchie mémoire|La hiérarchie mémoire]] * [[Fonctionnement d'un ordinateur/La performance d'un ordinateur|La performance d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La loi de Moore et les tendances technologiques|La loi de Moore et les tendances technologiques]] * [[Fonctionnement d'un ordinateur/Les techniques de réduction de la consommation électrique d'un processeur|Les techniques de réduction de la consommation électrique d'un processeur]] ==Les bus électroniques et la carte mère== * [[Fonctionnement d'un ordinateur/La carte mère, chipset et BIOS|La carte mère, chipset et BIOS]] * [[Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités)|Les bus et liaisons point à point (généralités)]] * [[Fonctionnement d'un ordinateur/Les encodages spécifiques aux bus|Les encodages spécifiques aux bus]] * [[Fonctionnement d'un ordinateur/Les liaisons point à point|Les liaisons point à point]] * [[Fonctionnement d'un ordinateur/Les bus électroniques|Les bus électroniques]] * [[Fonctionnement d'un ordinateur/Quelques exemples de bus et de liaisons point à point|Quelques exemples de bus et de liaisons point à point]] ==Les mémoires RAM/ROM== * [[Fonctionnement d'un ordinateur/Les différents types de mémoires|Les différents types de mémoires]] * [[Fonctionnement d'un ordinateur/L'interface d'une mémoire électronique|L'interface d'une mémoire électronique]] * [[Fonctionnement d'un ordinateur/Le bus mémoire|Le bus mémoire]] ===La micro-architecture d'une mémoire adressable=== * [[Fonctionnement d'un ordinateur/Les cellules mémoires|Les cellules mémoires]] * [[Fonctionnement d'un ordinateur/Le plan mémoire|Le plan mémoire]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire interne|Le contrôleur mémoire interne]] * [[Fonctionnement d'un ordinateur/Mémoires évoluées|Les mémoires évoluées]] ===Les mémoires primaires=== * [[Fonctionnement d'un ordinateur/Les mémoires ROM|Les mémoires ROM : Mask ROM, PROM, EPROM, EEPROM, Flash]] * [[Fonctionnement d'un ordinateur/Les mémoires SRAM synchrones|Les mémoires SRAM synchrones]] * [[Fonctionnement d'un ordinateur/Les mémoires RAM dynamiques (DRAM)|Les mémoires RAM dynamiques (DRAM)]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire externe|Le contrôleur mémoire externe]] ===Les mémoires exotiques=== * [[Fonctionnement d'un ordinateur/Les mémoires associatives|Les mémoires associatives]] * [[Fonctionnement d'un ordinateur/Les mémoires FIFO et LIFO|Les mémoires FIFO et LIFO]] ==Le processeur== ===L'architecture externe=== * [[Fonctionnement d'un ordinateur/Langage machine et assembleur|Langage machine et assembleur]] * [[Fonctionnement d'un ordinateur/Les registres du processeur|Les registres du processeur]] * [[Fonctionnement d'un ordinateur/Le modèle mémoire : alignement et boutisme|Le modèle mémoire : alignement et boutisme]] * [[Fonctionnement d'un ordinateur/Les modes d'adressage|Les modes d'adressage]] * [[Fonctionnement d'un ordinateur/L'encodage des instructions|L'encodage des instructions]] * [[Fonctionnement d'un ordinateur/Les jeux d'instructions|Les jeux d'instructions]] * [[Fonctionnement d'un ordinateur/La pile d'appel et les fonctions|La pile d'appel et les fonctions]] * [[Fonctionnement d'un ordinateur/Les interruptions et exceptions|Les interruptions et exceptions]] ===La micro-architecture=== * [[Fonctionnement d'un ordinateur/Les composants d'un processeur|Les composants d'un processeur]] * [[Fonctionnement d'un ordinateur/Le chemin de données|Le chemin de données]] * [[Fonctionnement d'un ordinateur/L'unité de chargement et le program counter|L'unité de chargement et le program counter]] * [[Fonctionnement d'un ordinateur/L'unité de contrôle|L'unité de contrôle]] * [[Fonctionnement d'un ordinateur/L'implémentation matérielle des branchements|L'implémentation matérielle des branchements]] ===Les jeux d'instruction anciens, avant les registres généraux ou exotiques=== * [[Fonctionnement d'un ordinateur/Les architectures à accumulateur|Les architectures à accumulateur]] * [[Fonctionnement d'un ordinateur/Les architectures à pile et mémoire-mémoire|Les architectures à pile et mémoire-mémoire]] * [[Fonctionnement d'un ordinateur/Les processeurs 8 bits et moins|Les processeurs 8 bits et moins]] ===L'espace d'adressage du processeur et la multiprogrammation=== * [[Fonctionnement d'un ordinateur/L'espace d'adressage du processeur|L'espace d'adressage du processeur]] * [[Fonctionnement d'un ordinateur/L'abstraction mémoire et la mémoire virtuelle|L'abstraction mémoire et la mémoire virtuelle]] ==Les entrées-sorties et périphériques== * [[Fonctionnement d'un ordinateur/Les méthodes de synchronisation entre processeur et périphériques|Les méthodes de synchronisation entre processeur et périphériques]] * [[Fonctionnement d'un ordinateur/L'adressage des périphériques|L'adressage des périphériques]] * [[Fonctionnement d'un ordinateur/Les périphériques et les cartes d'extension|Les périphériques et les cartes d'extension]] ==Les mémoires de stockage== * [[Fonctionnement d'un ordinateur/Les mémoires de masse : généralités|Les mémoires de masse : généralités]] * [[Fonctionnement d'un ordinateur/Les disques durs|Les disques durs]] * [[Fonctionnement d'un ordinateur/Les solid-state drives|Les solid-state drives]] * [[Fonctionnement d'un ordinateur/Les disques optiques|Les disques optiques]] * [[Fonctionnement d'un ordinateur/Compléments sur les mémoires de masse|Compléments sur les mémoires de masse]] ==La ou les mémoires caches== * [[Fonctionnement d'un ordinateur/Les mémoires cache|Les mémoires cache]] * [[Fonctionnement d'un ordinateur/Le préchargement|Le préchargement]] * [[Fonctionnement d'un ordinateur/Le Translation Lookaside Buffer|Le ''Translation Lookaside Buffer'']] ==Le parallélisme d’instructions== * [[Fonctionnement d'un ordinateur/Le pipeline|Le pipeline]] ===Les branchements et le ''front-end''=== * [[Fonctionnement d'un ordinateur/La prédiction de branchement|La prédiction de branchement]] * [[Fonctionnement d'un ordinateur/Les optimisations du chargement des instructions|Les optimisations du chargement des instructions]] ===Les pipelines multicycles simples=== * [[Fonctionnement d'un ordinateur/Les pipelines multicycles|Les pipelines multicycles]] * [[Fonctionnement d'un ordinateur/L'émission dans l'ordre des instructions|L'émission dans l'ordre des instructions]] * [[Fonctionnement d'un ordinateur/Le contournement (data forwarding)|Le contournement (data forwarding)]] * [[Fonctionnement d'un ordinateur/Les premiers processeurs Intel|Les premiers processeurs Intel]] ===L’exécution dans le désordre=== * [[Fonctionnement d'un ordinateur/L'exécution dans le désordre|L'exécution dans le désordre]] * [[Fonctionnement d'un ordinateur/Le renommage de registres|Le renommage de registres]] * [[Fonctionnement d'un ordinateur/Le scoreboarding et l'algorithme de Tomasulo|Annexe : Le scoreboarding et l'algorithme de Tomasulo]] ===Les optimisations des accès mémoire=== * [[Fonctionnement d'un ordinateur/La désambiguïsation mémoire|La désambiguïsation mémoire]] * [[Fonctionnement d'un ordinateur/Le parallélisme mémoire|Le parallélisme mémoire]] ===L'émission multiple=== * [[Fonctionnement d'un ordinateur/Les processeurs superscalaires|Les processeurs superscalaires]] * [[Fonctionnement d'un ordinateur/Exemples de microarchitectures CPU : le cas du x86|Exemples de CPU superscalaires: le cas du x86]] * [[Fonctionnement d'un ordinateur/Les processeurs VLIW et EPIC|Les processeurs VLIW et EPIC]] * [[Fonctionnement d'un ordinateur/Les architectures dataflow|Les architectures dataflow]] ==Les architectures parallèles== * [[Fonctionnement d'un ordinateur/Les architectures parallèles|Les architectures parallèles]] * [[Fonctionnement d'un ordinateur/Architectures multiprocesseurs et multicœurs|Les architectures multiprocesseurs et multicœurs]] * [[Fonctionnement d'un ordinateur/Architectures multithreadées et Hyperthreading|Les architectures multithreadées et Hyperthreading]] * [[Fonctionnement d'un ordinateur/Les architectures à parallélisme de données|Les architectures à parallélisme de données]] * [[Fonctionnement d'un ordinateur/La cohérence des caches|La cohérence des caches]] * [[Fonctionnement d'un ordinateur/Les sections critiques et le modèle mémoire|Les sections critiques et le modèle mémoire]] ==Annexes== ===Les nombres flottants : FPUs et coprocesseurs=== * [[Fonctionnement d'un ordinateur/Un exemple de jeu d'instruction : l'extension x87|Un exemple de jeu d'instruction : l'extension x87]] * [[Fonctionnement d'un ordinateur/Les coprocesseurs : FPU et IO|Les coprocesseurs : FPU et IO]] ===Les jeux d’instruction spécialisés=== * [[Fonctionnement d'un ordinateur/L'accélération matérielle de la virtualisation|L'accélération matérielle de la virtualisation]] * [[Fonctionnement d'un ordinateur/Les ISA optimisés pour la compilation/interprétation|Les ISA optimisés pour la compilation/interprétation]] * [[Fonctionnement d'un ordinateur/Les processeurs de traitement du signal|Les processeurs de traitement du signal]] * [[Fonctionnement d'un ordinateur/Les architectures actionnées par déplacement|Les architectures actionnées par déplacement]] ===Réseaux de neurones et accélérateurs d'IA=== * [[Fonctionnement d'un ordinateur/Les architectures systoliques|Les architectures systoliques]] * [[Fonctionnement d'un ordinateur/Les architectures neuromorphiques|Les réseaux de neurones matériels]] ===Les autres annexes=== * [[Fonctionnement d'un ordinateur/Le matériel réseau|Le matériel réseau]] * [[Fonctionnement d'un ordinateur/La tolérance aux pannes|La tolérance aux pannes]] * [[Fonctionnement d'un ordinateur/Les ordinateurs de première génération : tubes à vide et mémoires|Les ordinateurs de première génération : tubes à vide et mémoires]] * [[Fonctionnement d'un ordinateur/Les ordinateurs à encodages non-binaires|Les ordinateurs à encodages non-binaires]] * [[Fonctionnement d'un ordinateur/Les circuits réversibles|Les circuits réversibles]] * [[Fonctionnement d'un ordinateur/Les circuits de conversion analogique-numérique|Les circuits de conversion analogique-numérique]] {{autocat}} hc3h8v69zrqe7ojx613to7hoabhhsdr 772081 772080 2026-09-12T17:01:00Z Mewtow 31375 /* Annexes */ 772081 wikitext text/x-wiki __NOTOC__ * [[Fonctionnement d'un ordinateur/Introduction|Introduction]] ==Le codage des informations== * [[Fonctionnement d'un ordinateur/L'encodage des données|L'encodage des données]] * [[Fonctionnement d'un ordinateur/Le codage des nombres|Le codage des nombres]] * [[Fonctionnement d'un ordinateur/Les codes de détection/correction d'erreur|Les codes de détection/correction d'erreur]] ==Les circuits électroniques== * [[Fonctionnement d'un ordinateur/Les portes logiques|Les portes logiques]] ===Les circuits combinatoires=== * [[Fonctionnement d'un ordinateur/Les circuits combinatoires|Les circuits combinatoires]] * [[Fonctionnement d'un ordinateur/Les circuits de masquage|Les circuits de masquage]] * [[Fonctionnement d'un ordinateur/Les circuits de sélection|Les circuits de sélection]] * [[Fonctionnement d'un ordinateur/Les circuits incrémenteurs/décrémenteurs|Les circuits incrémenteurs/décrémenteurs]] ===Les circuits séquentiels=== * [[Fonctionnement d'un ordinateur/Les bascules : des mémoires de 1 bit|Les bascules : des mémoires de 1 bit]] * [[Fonctionnement d'un ordinateur/Les circuits synchrones et asynchrones|Les circuits synchrones et asynchrones]] * [[Fonctionnement d'un ordinateur/Les registres et mémoires adressables|Les registres et mémoires adressables]] * [[Fonctionnement d'un ordinateur/Les compteurs et timers|Les compteurs et timers]] * [[Fonctionnement d'un ordinateur/Les registres à décalage et les LSFR|Les registres à décalage et les LSFR]] ===Les circuits de calcul et de comparaison=== * [[Fonctionnement d'un ordinateur/Les circuits de décalage et de rotation|Les circuits de décalage et de rotation]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition et la soustraction|Les circuits pour l'addition et la soustraction]] * [[Fonctionnement d'un ordinateur/Les circuits de comparaison|Les circuits de comparaison]] * [[Fonctionnement d'un ordinateur/Les unités arithmétiques et logiques entières (simples)|Les unités arithmétiques et logiques entières (simples)]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition multiopérande|Les circuits pour l'addition multiopérande]] * [[Fonctionnement d'un ordinateur/Les circuits pour la multiplication et la division|Les circuits pour la multiplication et la division]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul logique et bit à bit|Les circuits de calcul logique et bit à bit]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul flottant|Les circuits de calcul flottant]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul trigonométriques|Les circuits de calcul trigonométriques]] ===Les circuits intégrés à semi-conducteurs=== * [[Fonctionnement d'un ordinateur/Les transistors et portes logiques|Les transistors et portes logiques]] * [[Fonctionnement d'un ordinateur/Les circuits intégrés|Les circuits intégrés]] * [[Fonctionnement d'un ordinateur/L'interface électrique entre circuits intégrés et bus|L'interface électrique entre circuits intégrés et bus]] ==L'architecture d'un ordinateur== * [[Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur|L'architecture de base d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La hiérarchie mémoire|La hiérarchie mémoire]] * [[Fonctionnement d'un ordinateur/La performance d'un ordinateur|La performance d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La loi de Moore et les tendances technologiques|La loi de Moore et les tendances technologiques]] * [[Fonctionnement d'un ordinateur/Les techniques de réduction de la consommation électrique d'un processeur|Les techniques de réduction de la consommation électrique d'un processeur]] ==Les bus électroniques et la carte mère== * [[Fonctionnement d'un ordinateur/La carte mère, chipset et BIOS|La carte mère, chipset et BIOS]] * [[Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités)|Les bus et liaisons point à point (généralités)]] * [[Fonctionnement d'un ordinateur/Les encodages spécifiques aux bus|Les encodages spécifiques aux bus]] * [[Fonctionnement d'un ordinateur/Les liaisons point à point|Les liaisons point à point]] * [[Fonctionnement d'un ordinateur/Les bus électroniques|Les bus électroniques]] * [[Fonctionnement d'un ordinateur/Quelques exemples de bus et de liaisons point à point|Quelques exemples de bus et de liaisons point à point]] ==Les mémoires RAM/ROM== * [[Fonctionnement d'un ordinateur/Les différents types de mémoires|Les différents types de mémoires]] * [[Fonctionnement d'un ordinateur/L'interface d'une mémoire électronique|L'interface d'une mémoire électronique]] * [[Fonctionnement d'un ordinateur/Le bus mémoire|Le bus mémoire]] ===La micro-architecture d'une mémoire adressable=== * [[Fonctionnement d'un ordinateur/Les cellules mémoires|Les cellules mémoires]] * [[Fonctionnement d'un ordinateur/Le plan mémoire|Le plan mémoire]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire interne|Le contrôleur mémoire interne]] * [[Fonctionnement d'un ordinateur/Mémoires évoluées|Les mémoires évoluées]] ===Les mémoires primaires=== * [[Fonctionnement d'un ordinateur/Les mémoires ROM|Les mémoires ROM : Mask ROM, PROM, EPROM, EEPROM, Flash]] * [[Fonctionnement d'un ordinateur/Les mémoires SRAM synchrones|Les mémoires SRAM synchrones]] * [[Fonctionnement d'un ordinateur/Les mémoires RAM dynamiques (DRAM)|Les mémoires RAM dynamiques (DRAM)]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire externe|Le contrôleur mémoire externe]] ===Les mémoires exotiques=== * [[Fonctionnement d'un ordinateur/Les mémoires associatives|Les mémoires associatives]] * [[Fonctionnement d'un ordinateur/Les mémoires FIFO et LIFO|Les mémoires FIFO et LIFO]] ==Le processeur== ===L'architecture externe=== * [[Fonctionnement d'un ordinateur/Langage machine et assembleur|Langage machine et assembleur]] * [[Fonctionnement d'un ordinateur/Les registres du processeur|Les registres du processeur]] * [[Fonctionnement d'un ordinateur/Le modèle mémoire : alignement et boutisme|Le modèle mémoire : alignement et boutisme]] * [[Fonctionnement d'un ordinateur/Les modes d'adressage|Les modes d'adressage]] * [[Fonctionnement d'un ordinateur/L'encodage des instructions|L'encodage des instructions]] * [[Fonctionnement d'un ordinateur/Les jeux d'instructions|Les jeux d'instructions]] * [[Fonctionnement d'un ordinateur/La pile d'appel et les fonctions|La pile d'appel et les fonctions]] * [[Fonctionnement d'un ordinateur/Les interruptions et exceptions|Les interruptions et exceptions]] ===La micro-architecture=== * [[Fonctionnement d'un ordinateur/Les composants d'un processeur|Les composants d'un processeur]] * [[Fonctionnement d'un ordinateur/Le chemin de données|Le chemin de données]] * [[Fonctionnement d'un ordinateur/L'unité de chargement et le program counter|L'unité de chargement et le program counter]] * [[Fonctionnement d'un ordinateur/L'unité de contrôle|L'unité de contrôle]] * [[Fonctionnement d'un ordinateur/L'implémentation matérielle des branchements|L'implémentation matérielle des branchements]] ===Les jeux d'instruction anciens, avant les registres généraux ou exotiques=== * [[Fonctionnement d'un ordinateur/Les architectures à accumulateur|Les architectures à accumulateur]] * [[Fonctionnement d'un ordinateur/Les architectures à pile et mémoire-mémoire|Les architectures à pile et mémoire-mémoire]] * [[Fonctionnement d'un ordinateur/Les processeurs 8 bits et moins|Les processeurs 8 bits et moins]] ===L'espace d'adressage du processeur et la multiprogrammation=== * [[Fonctionnement d'un ordinateur/L'espace d'adressage du processeur|L'espace d'adressage du processeur]] * [[Fonctionnement d'un ordinateur/L'abstraction mémoire et la mémoire virtuelle|L'abstraction mémoire et la mémoire virtuelle]] ==Les entrées-sorties et périphériques== * [[Fonctionnement d'un ordinateur/Les méthodes de synchronisation entre processeur et périphériques|Les méthodes de synchronisation entre processeur et périphériques]] * [[Fonctionnement d'un ordinateur/L'adressage des périphériques|L'adressage des périphériques]] * [[Fonctionnement d'un ordinateur/Les périphériques et les cartes d'extension|Les périphériques et les cartes d'extension]] ==Les mémoires de stockage== * [[Fonctionnement d'un ordinateur/Les mémoires de masse : généralités|Les mémoires de masse : généralités]] * [[Fonctionnement d'un ordinateur/Les disques durs|Les disques durs]] * [[Fonctionnement d'un ordinateur/Les solid-state drives|Les solid-state drives]] * [[Fonctionnement d'un ordinateur/Les disques optiques|Les disques optiques]] * [[Fonctionnement d'un ordinateur/Compléments sur les mémoires de masse|Compléments sur les mémoires de masse]] ==La ou les mémoires caches== * [[Fonctionnement d'un ordinateur/Les mémoires cache|Les mémoires cache]] * [[Fonctionnement d'un ordinateur/Le préchargement|Le préchargement]] * [[Fonctionnement d'un ordinateur/Le Translation Lookaside Buffer|Le ''Translation Lookaside Buffer'']] ==Le parallélisme d’instructions== * [[Fonctionnement d'un ordinateur/Le pipeline|Le pipeline]] ===Les branchements et le ''front-end''=== * [[Fonctionnement d'un ordinateur/La prédiction de branchement|La prédiction de branchement]] * [[Fonctionnement d'un ordinateur/Les optimisations du chargement des instructions|Les optimisations du chargement des instructions]] ===Les pipelines multicycles simples=== * [[Fonctionnement d'un ordinateur/Les pipelines multicycles|Les pipelines multicycles]] * [[Fonctionnement d'un ordinateur/L'émission dans l'ordre des instructions|L'émission dans l'ordre des instructions]] * [[Fonctionnement d'un ordinateur/Le contournement (data forwarding)|Le contournement (data forwarding)]] * [[Fonctionnement d'un ordinateur/Les premiers processeurs Intel|Les premiers processeurs Intel]] ===L’exécution dans le désordre=== * [[Fonctionnement d'un ordinateur/L'exécution dans le désordre|L'exécution dans le désordre]] * [[Fonctionnement d'un ordinateur/Le renommage de registres|Le renommage de registres]] * [[Fonctionnement d'un ordinateur/Le scoreboarding et l'algorithme de Tomasulo|Annexe : Le scoreboarding et l'algorithme de Tomasulo]] ===Les optimisations des accès mémoire=== * [[Fonctionnement d'un ordinateur/La désambiguïsation mémoire|La désambiguïsation mémoire]] * [[Fonctionnement d'un ordinateur/Le parallélisme mémoire|Le parallélisme mémoire]] ===L'émission multiple=== * [[Fonctionnement d'un ordinateur/Les processeurs superscalaires|Les processeurs superscalaires]] * [[Fonctionnement d'un ordinateur/Exemples de microarchitectures CPU : le cas du x86|Exemples de CPU superscalaires: le cas du x86]] * [[Fonctionnement d'un ordinateur/Les processeurs VLIW et EPIC|Les processeurs VLIW et EPIC]] * [[Fonctionnement d'un ordinateur/Les architectures dataflow|Les architectures dataflow]] ==Les architectures parallèles== * [[Fonctionnement d'un ordinateur/Les architectures parallèles|Les architectures parallèles]] * [[Fonctionnement d'un ordinateur/Architectures multiprocesseurs et multicœurs|Les architectures multiprocesseurs et multicœurs]] * [[Fonctionnement d'un ordinateur/Architectures multithreadées et Hyperthreading|Les architectures multithreadées et Hyperthreading]] * [[Fonctionnement d'un ordinateur/Les architectures à parallélisme de données|Les architectures à parallélisme de données]] * [[Fonctionnement d'un ordinateur/La cohérence des caches|La cohérence des caches]] * [[Fonctionnement d'un ordinateur/Les sections critiques et le modèle mémoire|Les sections critiques et le modèle mémoire]] ==Annexes== ===Les nombres flottants : FPUs et coprocesseurs=== * [[Fonctionnement d'un ordinateur/Un exemple de jeu d'instruction : l'extension x87|Un exemple de jeu d'instruction : l'extension x87]] * [[Fonctionnement d'un ordinateur/Les coprocesseurs : FPU et IO|Les coprocesseurs : FPU et IO]] ===Les jeux d’instruction spécialisés=== * [[Fonctionnement d'un ordinateur/Les ISA optimisés pour la compilation/interprétation|Les ISA optimisés pour la compilation/interprétation]] * [[Fonctionnement d'un ordinateur/Les processeurs de traitement du signal|Les processeurs de traitement du signal]] * [[Fonctionnement d'un ordinateur/Les architectures actionnées par déplacement|Les architectures actionnées par déplacement]] ===Réseaux de neurones et accélérateurs d'IA=== * [[Fonctionnement d'un ordinateur/Les architectures systoliques|Les architectures systoliques]] * [[Fonctionnement d'un ordinateur/Les architectures neuromorphiques|Les réseaux de neurones matériels]] ===Les autres annexes=== * [[Fonctionnement d'un ordinateur/L'accélération matérielle de la virtualisation|L'accélération matérielle de la virtualisation]] * [[Fonctionnement d'un ordinateur/Le matériel réseau|Le matériel réseau]] * [[Fonctionnement d'un ordinateur/La tolérance aux pannes|La tolérance aux pannes]] * [[Fonctionnement d'un ordinateur/Les circuits de conversion analogique-numérique|Les circuits de conversion analogique-numérique]] * [[Fonctionnement d'un ordinateur/Les ordinateurs de première génération : tubes à vide et mémoires|Les ordinateurs de première génération : tubes à vide et mémoires]] * [[Fonctionnement d'un ordinateur/Les ordinateurs à encodages non-binaires|Les ordinateurs à encodages non-binaires]] * [[Fonctionnement d'un ordinateur/Les circuits réversibles|Les circuits réversibles]] {{autocat}} hrp762rqmzdmm93tkxu93uujq3d3o02 Optimisation des compilateurs/Les optimisations des expressions et calculs 0 71447 772110 686974 2026-09-13T10:00:56Z DavidL 1746 /* La suppression des calculs redondants */ 772110 wikitext text/x-wiki De nos jours, les compilateurs cherchent par tous les moyens à réduire la vitesse d'exécution des programmes qu'ils compilent. Cela peut se faire de plusieurs manières, mais toutes se rapportent à deux techniques assez générales : soit on diminue le nombre d'instructions pour faire la même chose, soit on utilise des instructions équivalentes mais qui sont plus rapides. Les deux méthodes sont complémentaires, ce qui fait qu'elles sont utilisées de concert. Elles permettent de transformer une suite d'instructions en une autre suite, qui fait exactement la même chose, mais plus rapidement Nul besoin de magie pour ce faire, surtout pour les langages de haut-niveau. Du fait de leur abstraction, un code source peut être traduit en langage machine de plusieurs manières différentes, qui donnent chacune une suite d'instruction différente. Le compilateur a juste besoin de trouver celle qui donne la suite d'instruction la plus rapide. Généralement, les compilateurs font une traduction directe du code source en langage machine, et améliorent ensuite le code obtenu. Pour l'améliorer, ils appliquent diverses transformations et simplifications sur le code machine obtenu. Ces simplifications sont souvent effectuées, par souci de simplicité, sur des suites de quelques instructions, qui correspondent généralement à une fonction ou à une entité précise du programme. Mais d'autres peuvent être appliquées au-delà des barrières des fonctions et peuvent s'appliquer sur des suites plus grandes, voire sur tout un programme. En clair, on peut classer ces techniques en trois catégories : * Les premières techniques remplacent une instruction assez complexe par une instruction plus simple, mais équivalente. * Les secondes s'appliquent localement, à savoir qu'elles simplifient une suite de quelques instructions adjacentes (une fonction, par exemple). * Les dernières s'appliquent globalement sur tout le programme et permettent d'obtenir des gains plus importants mais avec une implémentation plus complexe. Dans ce qui va suivre, nous allons voir chaque type d’optimisation dans l'ordre indiqué ci-dessus. ==Les optimisations des instructions== Le premier type d'optimisation des calculs consiste à remplacer une instruction par une autre, plus rapide. Évidemment, cette technique ne s'applique pas systématiquement : les concepteurs de processeur ne sont pas stupides et ne créent pas d'instructions complexes inutilement. Le remplacement ne peut se faire que dans quelques cas particuliers, quand les opérandes ont des valeurs particulières. Par exemple, on peut citer le cas d'une multiplication par une puissance n de 2 (2<sup>n</sup>) revient à effectuer un décalage de n bits vers la gauche (vers les bits de poids fort). On pourrait aussi citer le cas du modulo par une puissance de deux, équivalent à un ET logique avec le masque adéquat. Beaucoup de ces simplifications sont expliquées dans [[Les opérations bit à bit|le livre « Les opérations bit à bit », disponible sur Wikilivres]]. ==Les optimisations locales== Les optimisations locales s'appliquent sur une suite d'instruction, qui est limitée par les règles de portée du langage de programmation source. Pour simplifier, on peut dire que ces suites correspondent le plus souvent à une fonction, un sous-programme, une méthode (selon le langage utilisé). Ces techniques sont assez diverses : certaines changent l'ordre des calculs, de manière à mieux utiliser les registres ou le pipeline du processeur, d'autres vont simplifier des suites de calculs. ===Les simplifications algébriques=== Un compilateur peut, sous certaines conditions, effectuer des simplifications algébriques. De nombreuses optimisations de ce genre sont possibles pour les entiers : a * b + a * c qui se transforme en a * ( b + c ). Cependant, ces optimisations ne sont pas toujours possibles : par exemple, calculer -( a - b ) avec des entiers ne peut pas être simplifié en -a + b à cause d'une possibilité d'overflow assez bien cachée. Quelque chose de similaire a lieu pour les flottants : les opérations flottantes ne sont pas associatives ni distributives. Mais certains compilateurs ne se gênent pas pour faire les simplifications, à partir d'un certain niveau d'optimisation. On trouve aussi la même chose pour les booléens, sous certaines conditions. Par exemple, l'expression if(!a && !b) peut être simplifiée en if (! (a || b) ). Mais ces optimisations ne sont pas toujours possibles, modifier l'ordre des comparaisons ou en supprimer peut ne pas donner le même résultat. Dans un tel cas, sachez que simplifier ces expressions à la main permet d'améliorer la lisibilité de votre programme (même si c'est souvent une amélioration marginale). ===La suppression des calculs inutiles=== Il arrive que certaines instructions soient inutiles. Par inutiles, on veut dire que leur résultat n'est pas utilisé dans le programme. Plus précisément, ces résultats sont écrits dans une variable qui n'est jamais lue. Il existe de nombreux algorithmes pour détecter de tels résultats, mais la plupart examinent des fonctions, et pas plus. Ils examinent si la variable est exploitée dans le corps de la fonction et/ou retournée : si elle ne l'est pas, alors elle est inutile. Le compilateur peut alors supprimer les instructions qui calculent ce résultat, qui ne servent à rien. Ces calculs inutiles apparaissent souvent après que la propagation de constantes a fait son travail. ===La suppression des calculs redondants=== Certains calculs sont inutiles ou redondants : il arrive souvent que des expressions calculent la même valeur que ce soit dans le code source ou dans la représentation intermédiaire d'un programme. Dans ce cas, une valeur est calculée plusieurs fois à des endroits relativement proches, par des suites d'instructions séparées. Prenons l'exemple classique, à savoir une simple boucle qui parcourt une chaine de caractère. <syntaxhighlight lang="c"> for (unsigned i = 0; i < strlen(string); ++i) { ... } </syntaxhighlight> Cette boucle recalcule la longueur de la chaine à chaque itération de la boucle, ce qui donne des calculs redondants. {{Attention|La condition est évaluée à chaque itération, donc ce qui suit n'est valable que si la chaîne ne change pas au cours de la boucle.}} Or, un bon compilateur C peut peut stocker cette valeur dans une variable, variable qui est alors réutilisée en lieu et place du résultat des expressions redondantes. Dans notre exemple, il va optimiser de lui-même l'usage de la fonction strlen, et donner un code assembleur équivalent au code suivant : <syntaxhighlight lang="c"> unsigned length = strlen(string); for (unsigned i = 0; i < length; ++i) { ... } </syntaxhighlight> Il faut préciser que cette technique n'est pas toujours possible. Notamment, le compilateur ne peut rien faire si la valeur est calculée par une fonction impure. Quand le compilateur voit que deux fonctions impures sont appelées avec des arguments identiques, il ne peut pas savoir si le résultat renvoyé sera le même et ne peut pas remplacer la seconde exécution de la fonction par une simple lecture de variable. Il faut toutefois signaler qu'il y a des exceptions à cette exception. Par exemple, prenez le code suivant : ===L'optimisation sur des fenêtres « peephole »=== Cette technique, appliquée après génération du code machine, examine quelques instructions adjacentes et détecte s'il est possible de les remplacer par une instruction ou une séquence d’instructions plus courte. Le cas classique est celui de l''''instruction MAD''', disponible sur de nombreux processeurs, qui permet d'effectuer le calcul A + B * C en une seule instruction. Dans un code source écrit dans un langage de haut niveau, on ne peut pas utiliser celle-ci directement, et on doit utiliser une addition et une multiplication à la place. C'est au compilateur de fusionner l'addition avec une multiplication en une seule instruction MAD. Un exemple d’optimisation de ce type est l’élimination des lectures redondantes. Ce code A = B + C ; D = A + E ; devient MOV b, R0 ADD c, R0 MOV R0, a MOV a, R0 # lecture redondante, elle peut être supprimée ADD e, R0 MOV R0, d On peut en donner un autre exemple avec ce code en assembleur Java : … aload 1 aload 1 mul … Il peut être remplacé par : … aload 1 dup mul … Ce type d’optimisation a besoin d’avoir des hypothèses sur l’efficacité des instructions. Dans ce cas précis, on a assumé que l’opération « dup », qui duplique et écrit dans la pile, est plus efficace que l’opération « aload X », qui lit une variable locale et l’écrit dans la pile. ===La vectorisation=== Un autre exemple, plus intéressant, est celui des instructions vectorielles. Le compilateur possède de nombreuses techniques qui permettent au compilateur de découvrir des suites d'instructions qui peuvent profiter des instructions SIMD des processeurs modernes. L'ensemble des techniques sont ce qu'on appelle la '''vectorisation'''. De nos jours, les compilateurs font du bon travail et donnent des résultats nettement meilleurs que la majorité des programmeurs quand il s'agit de vectoriser un code source. Mais un bon programmeur peut cependant faire mieux qu'un bon compilateur, si on lui laisse la possibilité d'utiliser l'assembleur. Évidemment, cela demande des programmeurs extrêmement compétents en assembleur, qui maitrisent l'architecture des ordinateurs sur les doigts de la main, mais cela peut donner des gains assez importants pour certaines fonctions particulières. Le cas classique est celui de l'utilisation des instructions SIMD dans la programmation de routines de traitement de signal ou de vidéo, qui peut donner des fonctions de trois à quatre fois plus rapides ! ===L'ordonnancement des instructions=== Les compilateurs modernes sont capables de changer l'ordre des opérations pour profiter au mieux du pipeline des processeurs modernes. Ils vont pour cela échanger des instructions de place, ce qui permettra au processeur de les exécuter en même temps. Mais cela n'est pas toujours possible, en raison de contraintes appelées dépendances. Celles-ci sont nombreuses et il en existe plusieurs types : dépendances de données, de contrôle, structurelles, etc. Le cas classique est celui où une instruction exploite le résultat d'un calcul précédent : on ne peut alors pas échanger ces instructions de place, pour des raisons évidentes. De même, on ne peut pas faire passer un calcul avant un branchement, si celui-ci dépend de son résultat. Ces optimisations donnent souvent de bons résultats, mais leur utilisation pratique dépend fortement du pipeline du processeur. On n'optimise pas un code source de la même manière pour un pipeline a 5 étages que pour un pipeline à 20 étages... Tout cela limite les possibilités de réorganisation des instructions, même si les compilateurs disposent de quelques techniques pour limiter les dégâts. <noinclude> {{NavChapitre | book=Optimisation des compilateurs | prev=Les optimisations liées aux constantes | prevText=Les optimisations liées aux constantes | next=Les optimisations des branchements | nextText=Les optimisations des branchements }} </noinclude> {{autocat}} sgd2po0ifp5v29u0vdmbavea7blm8n6 772111 772110 2026-09-13T10:03:44Z DavidL 1746 /* L'optimisation sur des fenêtres « peephole » */ 772111 wikitext text/x-wiki De nos jours, les compilateurs cherchent par tous les moyens à réduire la vitesse d'exécution des programmes qu'ils compilent. Cela peut se faire de plusieurs manières, mais toutes se rapportent à deux techniques assez générales : soit on diminue le nombre d'instructions pour faire la même chose, soit on utilise des instructions équivalentes mais qui sont plus rapides. Les deux méthodes sont complémentaires, ce qui fait qu'elles sont utilisées de concert. Elles permettent de transformer une suite d'instructions en une autre suite, qui fait exactement la même chose, mais plus rapidement Nul besoin de magie pour ce faire, surtout pour les langages de haut-niveau. Du fait de leur abstraction, un code source peut être traduit en langage machine de plusieurs manières différentes, qui donnent chacune une suite d'instruction différente. Le compilateur a juste besoin de trouver celle qui donne la suite d'instruction la plus rapide. Généralement, les compilateurs font une traduction directe du code source en langage machine, et améliorent ensuite le code obtenu. Pour l'améliorer, ils appliquent diverses transformations et simplifications sur le code machine obtenu. Ces simplifications sont souvent effectuées, par souci de simplicité, sur des suites de quelques instructions, qui correspondent généralement à une fonction ou à une entité précise du programme. Mais d'autres peuvent être appliquées au-delà des barrières des fonctions et peuvent s'appliquer sur des suites plus grandes, voire sur tout un programme. En clair, on peut classer ces techniques en trois catégories : * Les premières techniques remplacent une instruction assez complexe par une instruction plus simple, mais équivalente. * Les secondes s'appliquent localement, à savoir qu'elles simplifient une suite de quelques instructions adjacentes (une fonction, par exemple). * Les dernières s'appliquent globalement sur tout le programme et permettent d'obtenir des gains plus importants mais avec une implémentation plus complexe. Dans ce qui va suivre, nous allons voir chaque type d’optimisation dans l'ordre indiqué ci-dessus. ==Les optimisations des instructions== Le premier type d'optimisation des calculs consiste à remplacer une instruction par une autre, plus rapide. Évidemment, cette technique ne s'applique pas systématiquement : les concepteurs de processeur ne sont pas stupides et ne créent pas d'instructions complexes inutilement. Le remplacement ne peut se faire que dans quelques cas particuliers, quand les opérandes ont des valeurs particulières. Par exemple, on peut citer le cas d'une multiplication par une puissance n de 2 (2<sup>n</sup>) revient à effectuer un décalage de n bits vers la gauche (vers les bits de poids fort). On pourrait aussi citer le cas du modulo par une puissance de deux, équivalent à un ET logique avec le masque adéquat. Beaucoup de ces simplifications sont expliquées dans [[Les opérations bit à bit|le livre « Les opérations bit à bit », disponible sur Wikilivres]]. ==Les optimisations locales== Les optimisations locales s'appliquent sur une suite d'instruction, qui est limitée par les règles de portée du langage de programmation source. Pour simplifier, on peut dire que ces suites correspondent le plus souvent à une fonction, un sous-programme, une méthode (selon le langage utilisé). Ces techniques sont assez diverses : certaines changent l'ordre des calculs, de manière à mieux utiliser les registres ou le pipeline du processeur, d'autres vont simplifier des suites de calculs. ===Les simplifications algébriques=== Un compilateur peut, sous certaines conditions, effectuer des simplifications algébriques. De nombreuses optimisations de ce genre sont possibles pour les entiers : a * b + a * c qui se transforme en a * ( b + c ). Cependant, ces optimisations ne sont pas toujours possibles : par exemple, calculer -( a - b ) avec des entiers ne peut pas être simplifié en -a + b à cause d'une possibilité d'overflow assez bien cachée. Quelque chose de similaire a lieu pour les flottants : les opérations flottantes ne sont pas associatives ni distributives. Mais certains compilateurs ne se gênent pas pour faire les simplifications, à partir d'un certain niveau d'optimisation. On trouve aussi la même chose pour les booléens, sous certaines conditions. Par exemple, l'expression if(!a && !b) peut être simplifiée en if (! (a || b) ). Mais ces optimisations ne sont pas toujours possibles, modifier l'ordre des comparaisons ou en supprimer peut ne pas donner le même résultat. Dans un tel cas, sachez que simplifier ces expressions à la main permet d'améliorer la lisibilité de votre programme (même si c'est souvent une amélioration marginale). ===La suppression des calculs inutiles=== Il arrive que certaines instructions soient inutiles. Par inutiles, on veut dire que leur résultat n'est pas utilisé dans le programme. Plus précisément, ces résultats sont écrits dans une variable qui n'est jamais lue. Il existe de nombreux algorithmes pour détecter de tels résultats, mais la plupart examinent des fonctions, et pas plus. Ils examinent si la variable est exploitée dans le corps de la fonction et/ou retournée : si elle ne l'est pas, alors elle est inutile. Le compilateur peut alors supprimer les instructions qui calculent ce résultat, qui ne servent à rien. Ces calculs inutiles apparaissent souvent après que la propagation de constantes a fait son travail. ===La suppression des calculs redondants=== Certains calculs sont inutiles ou redondants : il arrive souvent que des expressions calculent la même valeur que ce soit dans le code source ou dans la représentation intermédiaire d'un programme. Dans ce cas, une valeur est calculée plusieurs fois à des endroits relativement proches, par des suites d'instructions séparées. Prenons l'exemple classique, à savoir une simple boucle qui parcourt une chaine de caractère. <syntaxhighlight lang="c"> for (unsigned i = 0; i < strlen(string); ++i) { ... } </syntaxhighlight> Cette boucle recalcule la longueur de la chaine à chaque itération de la boucle, ce qui donne des calculs redondants. {{Attention|La condition est évaluée à chaque itération, donc ce qui suit n'est valable que si la chaîne ne change pas au cours de la boucle.}} Or, un bon compilateur C peut peut stocker cette valeur dans une variable, variable qui est alors réutilisée en lieu et place du résultat des expressions redondantes. Dans notre exemple, il va optimiser de lui-même l'usage de la fonction strlen, et donner un code assembleur équivalent au code suivant : <syntaxhighlight lang="c"> unsigned length = strlen(string); for (unsigned i = 0; i < length; ++i) { ... } </syntaxhighlight> Il faut préciser que cette technique n'est pas toujours possible. Notamment, le compilateur ne peut rien faire si la valeur est calculée par une fonction impure. Quand le compilateur voit que deux fonctions impures sont appelées avec des arguments identiques, il ne peut pas savoir si le résultat renvoyé sera le même et ne peut pas remplacer la seconde exécution de la fonction par une simple lecture de variable. Il faut toutefois signaler qu'il y a des exceptions à cette exception. Par exemple, prenez le code suivant : ===L'optimisation sur des fenêtres « peephole »=== Cette technique, appliquée après génération du code machine, examine quelques instructions adjacentes et détecte s'il est possible de les remplacer par une instruction ou une séquence d’instructions plus courte. Le cas classique est celui de l''''instruction MAD''', disponible sur de nombreux processeurs, qui permet d'effectuer le calcul A + B * C en une seule instruction. Dans un code source écrit dans un langage de haut niveau, on ne peut pas utiliser celle-ci directement, et on doit utiliser une addition et une multiplication à la place. C'est au compilateur de fusionner l'addition avec une multiplication en une seule instruction MAD. Un exemple d’optimisation de ce type est l’élimination des lectures redondantes. Ce code A = B + C ; D = A + E ; devient # Syntaxe AT&T où l'opérande source est placé avant l'opérande destination MOV b, R0 ADD c, R0 MOV R0, a MOV a, R0 # lecture redondante, elle peut être supprimée ADD e, R0 MOV R0, d On peut en donner un autre exemple avec ce code en assembleur Java : … aload 1 aload 1 mul … Il peut être remplacé par : … aload 1 dup mul … Ce type d’optimisation a besoin d’avoir des hypothèses sur l’efficacité des instructions. Dans ce cas précis, on a assumé que l’opération « dup », qui duplique et écrit dans la pile, est plus efficace que l’opération « aload X », qui lit une variable locale et l’écrit dans la pile. ===La vectorisation=== Un autre exemple, plus intéressant, est celui des instructions vectorielles. Le compilateur possède de nombreuses techniques qui permettent au compilateur de découvrir des suites d'instructions qui peuvent profiter des instructions SIMD des processeurs modernes. L'ensemble des techniques sont ce qu'on appelle la '''vectorisation'''. De nos jours, les compilateurs font du bon travail et donnent des résultats nettement meilleurs que la majorité des programmeurs quand il s'agit de vectoriser un code source. Mais un bon programmeur peut cependant faire mieux qu'un bon compilateur, si on lui laisse la possibilité d'utiliser l'assembleur. Évidemment, cela demande des programmeurs extrêmement compétents en assembleur, qui maitrisent l'architecture des ordinateurs sur les doigts de la main, mais cela peut donner des gains assez importants pour certaines fonctions particulières. Le cas classique est celui de l'utilisation des instructions SIMD dans la programmation de routines de traitement de signal ou de vidéo, qui peut donner des fonctions de trois à quatre fois plus rapides ! ===L'ordonnancement des instructions=== Les compilateurs modernes sont capables de changer l'ordre des opérations pour profiter au mieux du pipeline des processeurs modernes. Ils vont pour cela échanger des instructions de place, ce qui permettra au processeur de les exécuter en même temps. Mais cela n'est pas toujours possible, en raison de contraintes appelées dépendances. Celles-ci sont nombreuses et il en existe plusieurs types : dépendances de données, de contrôle, structurelles, etc. Le cas classique est celui où une instruction exploite le résultat d'un calcul précédent : on ne peut alors pas échanger ces instructions de place, pour des raisons évidentes. De même, on ne peut pas faire passer un calcul avant un branchement, si celui-ci dépend de son résultat. Ces optimisations donnent souvent de bons résultats, mais leur utilisation pratique dépend fortement du pipeline du processeur. On n'optimise pas un code source de la même manière pour un pipeline a 5 étages que pour un pipeline à 20 étages... Tout cela limite les possibilités de réorganisation des instructions, même si les compilateurs disposent de quelques techniques pour limiter les dégâts. <noinclude> {{NavChapitre | book=Optimisation des compilateurs | prev=Les optimisations liées aux constantes | prevText=Les optimisations liées aux constantes | next=Les optimisations des branchements | nextText=Les optimisations des branchements }} </noinclude> {{autocat}} 7hv6vs11yyjp23eu11ajh4k506ugd10 Mathc initiation/Fichiers h : c44a4 0 76524 772125 771979 2026-09-13T10:32:39Z Xhungab 23827 772125 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] Remarque : cosh(x)^2 = 1/2 + 1/2 cosh(2x) sinh(x)^2 = 1/2 cosh(2x) - 1/2 cosh(x)^3 = 3/4 cosh(x) + 1/4 cosh(3x) sinh(x)^3 = 1/4 sinh(3x) - 3/4 sinh(x) L{sinh(t)} = 1/(s^2-1) ... L{sinh(at)} = a/(s^2-a^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(at)} = s/(s^2-a^2) a) Calculons la transformée de Laplace de : y(t) = cosh(2t)^2 = 1/2 +1/2 cosh(2(2t)) = 1/2 +1/2 cosh(4t) = 1/2 (1 + cosh(4t)) L{y(t)} = 1/2 [ L{1} + L{cosh(4t)} ] = 1/2 [ 1/s + s/(s^2-(4)^2)} ] = 1/2 [ 1/s + s/(s^2-16) ] b) Calculons la transformée de Laplace de : y(t) = sinh(3t)^2 = 1/2 cosh(2(3t)) -1/2 = 1/2 cosh(6t) - 1/2 = 1/2 (cosh(6t) - 1) L{y(t)} = 1/2 [ L{cosh(6t)} - L{1}] = 1/2 [ s/(s^2+(6)^2) - 1/s] = 1/2 [ s/(s^2+36) - 1/s] c) Calculons la transformée de Laplace de : y(t) = cosh(2t)^3 = 3/4 cosh(2t) + 1/4 cosh(3(2t)) = 3/4 cosh(2t) + 1/4 cosh(6t)) L{y(t)} = 3/4 L{cosh(2t)} + 1/4 L{cosh(6t)} = 3/4 s/(s^2+4) + 1/4 s/(s^2+36) d) Calculons la transformée de Laplace de : y(t) = sinh(4x)^3 = 1/4 sinh(3(4t)) - 3/4 sinh(4t) = 1/4 sinh(12t) - 3/4 sinh(4t) L{y(t)} = 1/4 L{sinh(12t)} - 3/4 L{sinh(4t)} = 1/4 12/(s^2+144) - 3/4 4/(s^2+16) = 3/(s^2+144) - 3/(s^2+16) * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} sods8ctb9hpslm2hb12y646ff5e3mgy Mathc initiation/a512 0 80964 772078 772073 2026-09-12T14:46:27Z Xhungab 23827 news 772078 wikitext text/x-wiki [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPP8YlloOLhIv5WflA0cpr5n&si=n_rhSX0G-o18nxFY Playlist]].''' : . : * La transformée de Laplace va nous permettre de passer du domaine temporel (t) au domaine fréquentiel (s). * La transformée de Laplace va transformer les fonctions trigonométriques, exponentielles, ... en fonctions algébriques (+,-,*). * La transformée de Laplace ne fonctionne que sur les '''fonctions causales'''. [https://commons.wikimedia.org/wiki/File:Causal_function_with_gnuplot_and_C_language.png Une '''fonction causale'''] est une fonction qui ne prend sa valeur que quand t est supérieur à zéro. La fonction est nulle entre moins l'infini et zéro. Ceci se matérialise sur l'intégrale dont les bornes sont entre zéro et l'infini positif. L'intégrale de la transformée de Laplace de F(t) : / +oo | L{F(t)} = | exp(-s t) F(t) dt = f(s) | / 0 * Si G(t) est une fonction (sin, cos, exp, t^n, ...) alors : F(t) = G(t) * U(t) est une fonction causale, ou '''U(t)''' est la fonction [[Mathc initiation/a579| '''Heaviside''']]. U(t) = 0 si t < 0 U(t) = 1 si t >= 0 Pour simplifier la lecture de ce texte j'ai remplacé systématiquement '''G(t) * U(t)''' par '''F(t)'''. * La transformée de Laplace est un '''opérateur linéaire''' : L{a F(t) + b G(t)} = a L{F(t)} + b L{G(t)} * La transformée inverse de Laplace est un '''opérateur linéaire''' : L<sup>-1</sup>{a f(s) + b g(s)} = a L<sup>-1</sup>{f(s)} + b L<sup>-1</sup>{g(s)} : . : '''Se familiariser avec la transformée de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a513|* la Transformée de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a520|* la Transformée de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a536|* la Transformée de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a528|* La transformée de Laplace de la dérivée]]}} {{Partie{{{type|}}}|[[Mathc initiation/a532|* La transformée de Laplace de la dérivée seconde]]}} {{Partie{{{type|}}}|[[Mathc initiation/a524|* La transformée de Laplace d'une intégrale]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a559|* La transformée de Laplace : Multiplication par t^n]]}} {{Partie{{{type|}}}|[[Mathc_initiation/a563|* La transformée de Laplace : Division par t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a540|* la Transformée de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a551|* la Transformée de Laplace : Translation de la variable t]]}} : . : '''Se familiariser avec la transformée Inverse de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a541|* la Transformée '''Inverse''' de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a542|* la Transformée '''Inverse''' de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a543|* la Transformée '''Inverse''' de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a546|* La transformée '''Inverse''' de Laplace de : (s)f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a545|* La transformée '''Inverse''' de Laplace de : (1/s)f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a554|* La transformée '''Inverse''' de Laplace de la dérivée de f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a555|* La transformée '''Inverse''' de Laplace de l'intégrale de f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a544|* la Transformée '''Inverse''' de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a552|* la Transformée '''Inverse''' de Laplace : Translation de la variable t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a570|* la Transformée '''Inverse''' de Laplace : La Méthode d'Expansion d'Heaviside]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a574|* la Transformée Inverse de Laplace : Le Théorème De Convolution]]}} : . : '''Quelques exercices : ''' {{Partie{{{type|}}}|[[Mathc initiation/a538|* Calculons : L{sin(t)sin(2t)} L{cos(3t)cos(2t)} L{sin(4t)cos(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a549|* Calculons : L{sinh(t)sinh(2t)} L{cosh(3t)cosh(2t)} L{sinh(4t)cosh(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a526|* Calculons : L{cos(2t)^2} L{sin(3t)^2} L{cos(2t)^3} L{sin(4t)^3}]]}} {{Partie{{{type|}}}|[[Mathc initiation/Fichiers h : c44a4|* Calculons : L{cosh(2t)^2} L{sinh(3t)^2} L{cosh(2t)^3} L{sinh(4t)^3}]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/006o|* Calculons : L{exp(at)sin(bt)} L{exp(at)sinh(bt)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006p|* Calculons : L{t sin(at)} L{t sinh(at)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006q|* Calculons : L{t^2 sin(at)} L{t^2 sinh(at)}]]}} : . : '''Quelques applications : ''' {{Partie{{{type|}}}|[[Mathc initiation/a547|* Résoudre : y(t)'+y(t)=1 avec y(0) = 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/a00ad|* Résoudre : y(t)'+3 y(t)=6 avec y(0) = 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/006f|* Résoudre : y(t)'+2 y(t)=4 avec y(0) = 1]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/006l|* Résoudre : y(t)'+2y(t)=exp(-t) avec y(0) = 1]]}} {{Partie{{{type|}}}|[[Mathc initiation/006j|* Résoudre : y(t)'+3y(t)=exp(-2t) avec y(0) = 2]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a608|* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3]]}} {{Partie{{{type|}}}|[[Mathc initiation/006h|* Résoudre : y(t) ' ' + 3 y(t)' + 2 y(t) = 0 avec y(0)=1 y(0)'=0]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a613|* Résoudre un sytème d'équations différentielles]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a580|* L'intégrale impropre en posant s tend vers 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/a564|* L'intégrale impropre avec la multiplication par t^n avec n=1]]}} {{Partie{{{type|}}}|[[Mathc initiation/a565|* L'intégrale impropre avec la division par t]]}} : . : '''Quelques rappels mathématiques : ''' {{Partie{{{type|}}}|[[Mathc initiation/a566|* Trigonométriques. Trigonométriques hyperboliques]]}} {{Partie{{{type|}}}|[[Mathc initiation/a569|* Fractions partielles]]}} : . : {{AutoCat}} sjrnph0xg32arun708771dw2ogb76fx 772116 772078 2026-09-13T10:17:00Z Xhungab 23827 772116 wikitext text/x-wiki [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPP8YlloOLhIv5WflA0cpr5n&si=n_rhSX0G-o18nxFY Playlist]].''' : . : * La transformée de Laplace va nous permettre de passer du domaine temporel (t) au domaine fréquentiel (s). * La transformée de Laplace va transformer les fonctions trigonométriques, exponentielles, ... en fonctions algébriques (+,-,*). * La transformée de Laplace ne fonctionne que sur les '''fonctions causales'''. [https://commons.wikimedia.org/wiki/File:Causal_function_with_gnuplot_and_C_language.png Une '''fonction causale'''] est une fonction qui ne prend sa valeur que quand t est supérieur à zéro. La fonction est nulle entre moins l'infini et zéro. Ceci se matérialise sur l'intégrale dont les bornes sont entre zéro et l'infini positif. L'intégrale de la transformée de Laplace de F(t) : / +oo | L{F(t)} = | exp(-s t) F(t) dt = f(s) | / 0 * Si G(t) est une fonction (sin, cos, exp, t^n, ...) alors : F(t) = G(t) * U(t) est une fonction causale, ou '''U(t)''' est la fonction [[Mathc initiation/a579| '''Heaviside''']]. U(t) = 0 si t < 0 U(t) = 1 si t >= 0 Pour simplifier la lecture de ce texte j'ai remplacé systématiquement '''G(t) * U(t)''' par '''F(t)'''. * La transformée de Laplace est un '''opérateur linéaire''' : L{a F(t) + b G(t)} = a L{F(t)} + b L{G(t)} * La transformée inverse de Laplace est un '''opérateur linéaire''' : L<sup>-1</sup>{a f(s) + b g(s)} = a L<sup>-1</sup>{f(s)} + b L<sup>-1</sup>{g(s)} : . : '''Se familiariser avec la transformée de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a513|* la Transformée de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a520|* la Transformée de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a536|* la Transformée de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a528|* La transformée de Laplace de la dérivée]]}} {{Partie{{{type|}}}|[[Mathc initiation/a532|* La transformée de Laplace de la dérivée seconde]]}} {{Partie{{{type|}}}|[[Mathc initiation/a524|* La transformée de Laplace d'une intégrale]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a559|* La transformée de Laplace : Multiplication par t^n]]}} {{Partie{{{type|}}}|[[Mathc_initiation/a563|* La transformée de Laplace : Division par t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a540|* la Transformée de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a551|* la Transformée de Laplace : Translation de la variable t]]}} : . : '''Se familiariser avec la transformée Inverse de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a541|* la Transformée '''Inverse''' de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a542|* la Transformée '''Inverse''' de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a543|* la Transformée '''Inverse''' de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a546|* La transformée '''Inverse''' de Laplace de : (s)f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a545|* La transformée '''Inverse''' de Laplace de : (1/s)f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a554|* La transformée '''Inverse''' de Laplace de la dérivée de f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a555|* La transformée '''Inverse''' de Laplace de l'intégrale de f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a544|* la Transformée '''Inverse''' de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a552|* la Transformée '''Inverse''' de Laplace : Translation de la variable t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a570|* la Transformée '''Inverse''' de Laplace : La Méthode d'Expansion d'Heaviside]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a574|* la Transformée Inverse de Laplace : Le Théorème De Convolution]]}} : . : '''Quelques exercices : ''' {{Partie{{{type|}}}|[[Mathc initiation/a538|* Calculons : L{sin(t)sin(2t)} L{cos(3t)cos(2t)} L{sin(4t)cos(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a549|* Calculons : L{sinh(t)sinh(2t)} L{cosh(3t)cosh(2t)} L{sinh(4t)cosh(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a526|* Calculons : L{cos(2t)^2} L{sin(3t)^2} L{cos(2t)^3} L{sin(4t)^3}]]}} {{Partie{{{type|}}}|[[Mathc initiation/Fichiers h : c44a4|* Calculons : L{cosh(2t)^2} L{sinh(3t)^2} L{cosh(2t)^3} L{sinh(4t)^3}]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/006o|* Calculons : L{exp(at)sin(bt)} L{exp(at)sinh(bt)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006p|* Calculons : L{t sin(at)} L{t sinh(at)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006q|* Calculons : L{t^2 sin(at)} L{t^2 sinh(at)}]]}} : . : '''Quelques rappels mathématiques : ''' {{Partie{{{type|}}}|[[Mathc initiation/a566|* Trigonométriques. Trigonométriques hyperboliques]]}} {{Partie{{{type|}}}|[[Mathc initiation/a569|* Fractions partielles]]}} : . : {{AutoCat}} c67t3hw8cqo5pj15svai8umtaf05u9h 772119 772116 2026-09-13T10:23:32Z Xhungab 23827 772119 wikitext text/x-wiki [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPP8YlloOLhIv5WflA0cpr5n&si=n_rhSX0G-o18nxFY Playlist]].''' : . : * La transformée de Laplace va nous permettre de passer du domaine temporel (t) au domaine fréquentiel (s). * La transformée de Laplace va transformer les fonctions trigonométriques, exponentielles, ... en fonctions algébriques (+,-,*). * La transformée de Laplace ne fonctionne que sur les '''fonctions causales'''. [https://commons.wikimedia.org/wiki/File:Causal_function_with_gnuplot_and_C_language.png Une '''fonction causale'''] est une fonction qui ne prend sa valeur que quand t est supérieur à zéro. La fonction est nulle entre moins l'infini et zéro. Ceci se matérialise sur l'intégrale dont les bornes sont entre zéro et l'infini positif. L'intégrale de la transformée de Laplace de F(t) : / +oo | L{F(t)} = | exp(-s t) F(t) dt = f(s) | / 0 * Si G(t) est une fonction (sin, cos, exp, t^n, ...) alors : F(t) = G(t) * U(t) est une fonction causale, ou '''U(t)''' est la fonction [[Mathc initiation/a579| '''Heaviside''']]. U(t) = 0 si t < 0 U(t) = 1 si t >= 0 Pour simplifier la lecture de ce texte j'ai remplacé systématiquement '''G(t) * U(t)''' par '''F(t)'''. * La transformée de Laplace est un '''opérateur linéaire''' : L{a F(t) + b G(t)} = a L{F(t)} + b L{G(t)} * La transformée inverse de Laplace est un '''opérateur linéaire''' : L<sup>-1</sup>{a f(s) + b g(s)} = a L<sup>-1</sup>{f(s)} + b L<sup>-1</sup>{g(s)} : . : '''Se familiariser avec la transformée de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a513|* la Transformée de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a520|* la Transformée de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a536|* la Transformée de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a528|* La transformée de Laplace de la dérivée]]}} {{Partie{{{type|}}}|[[Mathc initiation/a532|* La transformée de Laplace de la dérivée seconde]]}} {{Partie{{{type|}}}|[[Mathc initiation/a524|* La transformée de Laplace d'une intégrale]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a559|* La transformée de Laplace : Multiplication par t^n]]}} {{Partie{{{type|}}}|[[Mathc_initiation/a563|* La transformée de Laplace : Division par t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a540|* la Transformée de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a551|* la Transformée de Laplace : Translation de la variable t]]}} : . : '''Se familiariser avec la transformée Inverse de Laplace : ''' {{Partie{{{type|}}}|[[Mathc initiation/a541|* la Transformée '''Inverse''' de Laplace : Première approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a542|* la Transformée '''Inverse''' de Laplace : Deuxième approche]]}} {{Partie{{{type|}}}|[[Mathc initiation/a543|* la Transformée '''Inverse''' de Laplace : Changement d'échelle]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a546|* La transformée '''Inverse''' de Laplace de : (s)f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a545|* La transformée '''Inverse''' de Laplace de : (1/s)f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a554|* La transformée '''Inverse''' de Laplace de la dérivée de f(s)]]}} {{Partie{{{type|}}}|[[Mathc initiation/a555|* La transformée '''Inverse''' de Laplace de l'intégrale de f(s)]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a544|* la Transformée '''Inverse''' de Laplace : Translation de la variable s]]}} {{Partie{{{type|}}}|[[Mathc initiation/a552|* la Transformée '''Inverse''' de Laplace : Translation de la variable t]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a570|* la Transformée '''Inverse''' de Laplace : La Méthode d'Expansion d'Heaviside]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a574|* la Transformée Inverse de Laplace : Le Théorème De Convolution]]}} : . : '''Quelques rappels mathématiques : ''' {{Partie{{{type|}}}|[[Mathc initiation/a566|* Trigonométriques. Trigonométriques hyperboliques]]}} {{Partie{{{type|}}}|[[Mathc initiation/a569|* Fractions partielles]]}} : . : {{AutoCat}} 81dvl9ud8jsorly3hc9i6ueb1ypvgvo Mathc initiation/a522 0 80975 772112 771973 2026-09-13T10:12:03Z Xhungab 23827 772112 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/Sommaire#Analyse IV|Sommaire]] Je vous propose comme cours de référence les trois livres de '''openstax''' en accès libre. Vous pouvez les lire en ligne ou télécharger les PDF. * [https://openstax.org/details/books/calculus-volume-1 Calculus 1], * [https://openstax.org/details/books/calculus-volume-2 Calculus 2], * [https://openstax.org/details/books/calculus-volume-3 Calculus 3]. : . : {{Partie{{{type|}}}|[[Mathc initiation/a10| Analyse IV : Les équations différentielles]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a594| Analyse IV : Se familiariser avec les séries de Fourier]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a592| Analyse IV : Se familiariser avec la transformée de Fourier discrète]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a512| Analyse IV : Se familiariser avec la Transformée de Laplace]]}} {{Partie{{{type|}}}|[[Mathc initiation/006r| Analyse IV : la Transformée de Laplace : Quelques applications]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a584| Analyse IV : Se familiariser avec la transformée en Z]]}} {{AutoCat}} bv6cdfbc3r21948hisyziqtyq850ve6 772115 772112 2026-09-13T10:15:56Z Xhungab 23827 772115 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/Sommaire#Analyse IV|Sommaire]] Je vous propose comme cours de référence les trois livres de '''openstax''' en accès libre. Vous pouvez les lire en ligne ou télécharger les PDF. * [https://openstax.org/details/books/calculus-volume-1 Calculus 1], * [https://openstax.org/details/books/calculus-volume-2 Calculus 2], * [https://openstax.org/details/books/calculus-volume-3 Calculus 3]. : . : {{Partie{{{type|}}}|[[Mathc initiation/a10| Analyse IV : Les équations différentielles]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a594| Analyse IV : Se familiariser avec les séries de Fourier]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a592| Analyse IV : Se familiariser avec la transformée de Fourier discrète]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a512| Analyse IV : Se familiariser avec la Transformée de Laplace]]}} {{Partie{{{type|}}}|[[Mathc initiation/006r| Analyse IV : la Transformée de Laplace : Quelques applications]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a584| Analyse IV : Se familiariser avec la transformée en Z]]}} {{AutoCat}} hdyw9cmorrc6ghzd3y4z2t8nhcoforl 772117 772115 2026-09-13T10:20:40Z Xhungab 23827 772117 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/Sommaire#Analyse IV|Sommaire]] Je vous propose comme cours de référence les trois livres de '''openstax''' en accès libre. Vous pouvez les lire en ligne ou télécharger les PDF. * [https://openstax.org/details/books/calculus-volume-1 Calculus 1], * [https://openstax.org/details/books/calculus-volume-2 Calculus 2], * [https://openstax.org/details/books/calculus-volume-3 Calculus 3]. : . : {{Partie{{{type|}}}|[[Mathc initiation/a10| Analyse IV : Les équations différentielles]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a594| Analyse IV : Se familiariser avec les séries de Fourier]]}} : {{Partie{{{type|}}}|[[Mathc initiation/a592| Analyse IV : Se familiariser avec la transformée de Fourier discrète]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a512| Analyse IV : Se familiariser avec la Transformée de Laplace]]}} {{Partie{{{type|}}}|[[Mathc initiation/006s| Analyse IV : la Transformée de Laplace : Quelques exercices]]}} {{Partie{{{type|}}}|[[Mathc initiation/006r| Analyse IV : la Transformée de Laplace : Quelques applications]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a584| Analyse IV : Se familiariser avec la transformée en Z]]}} {{AutoCat}} bp9o0ae2u0c0tx5j0v3jidhfega5r92 772143 772117 2026-09-13T10:52:30Z Xhungab 23827 772143 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/Sommaire#Analyse IV|Sommaire]] Je vous propose comme cours de référence les trois livres de '''openstax''' en accès libre. Vous pouvez les lire en ligne ou télécharger les PDF. * [https://openstax.org/details/books/calculus-volume-1 Calculus 1], * [https://openstax.org/details/books/calculus-volume-2 Calculus 2], * [https://openstax.org/details/books/calculus-volume-3 Calculus 3]. : . : {{Partie{{{type|}}}|[[Mathc initiation/a10| Analyse IV : Les équations différentielles]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a594| Analyse IV : Se familiariser avec les séries de Fourier]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a592| Analyse IV : Se familiariser avec la transformée de Fourier discrète]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a512| Analyse IV : Se familiariser avec la Transformée de Laplace]]}} {{Partie{{{type|}}}|[[Mathc initiation/006s| Analyse IV : la Transformée de Laplace : Quelques exercices]]}} {{Partie{{{type|}}}|[[Mathc initiation/006r| Analyse IV : la Transformée de Laplace : Quelques applications]]}} . {{Partie{{{type|}}}|[[Mathc initiation/a584| Analyse IV : Se familiariser avec la transformée en Z]]}} {{AutoCat}} dh3vcl0pxvyzjbokj75vggag9tkvova Mathc initiation/a526 0 80983 772124 771978 2026-09-13T10:32:20Z Xhungab 23827 772124 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] Remarque : cos(x)^2 = 1/2 + 1/2 cos(2x) sin(x)^2 = 1/2 - 1/2 cos(2x) cos(x)^3 = 3/4 cos(x) + 1/4 cos(3x) sin(x)^3 = 3/4 sin(x) - 1/4 sin(3x) L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) a) Calculons la transformée de Laplace de : y(t) = cos(2t)^2 = 1/2 +1/2 cos(2(2t)) = 1/2 +1/2 cos(4t) = 1/2 (1 + cos(4t)) L{y(t)} = 1/2 [ L{1} + L{cos(4t)} ] = 1/2 [ 1/s + s/(s^2+(4)^2)} ] = 1/2 [ 1/s + s/(s^2+16) ] b) Calculons la transformée de Laplace de : y(t) = sin(3t)^2 = 1/2 -1/2 cos(2(3t)) = 1/2 -1/2 cos(6t) = 1/2 (1 - cos(6t)) L{y(t)} = 1/2 [ L{1} - L{cos(6t)} ] = 1/2 [ 1/s - s/(s^2+(6)^2)} ] = 1/2 [ 1/s - s/(s^2+36) ] c) Calculons la transformée de Laplace de : y(t) = cos(2t)^3 = 3/4 cos(2t) + 1/4 cos(3(2t)) = 3/4 cos(2t) + 1/4 cos(6t)) L{y(t)} = 3/4 L{cos(2t)} + 1/4 L{cos(6t)} = 3/4 s/(s^2+4) + 1/4 s/(s^2+36) d) Calculons la transformée de Laplace de : y(t) = sin(4x)^3 = 3/4 sin(4x) - 1/4 sin(3(4x)) = 3/4 sin(4x) - 1/4 sin(12x) L{y(t)} = 3/4 L{sin(4x)} - 1/4 L{sin(12x)} = 3/4 4/(s^2+16) - 1/4 12/(s^2+144) = 3/(s^2+16) - 3/(s^2+144) * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} 7y1i6hb132ta5kcuj4vujomidvoc6dl Mathc initiation/a538 0 80998 772120 771976 2026-09-13T10:25:46Z Xhungab 23827 772120 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/Mathc initiation/006s|Sommaire]] Remarque : sin(x)sin(y) = 1/2 [cos(x-y) - cos(x+y)] cos(x)cos(y) = 1/2 [cos(x-y) + cos(x+y)] sin(x)cos(y) = 1/2 [sin(x-y) + sin(x+y)] L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) a) Calculons la transformée de Laplace de : y(t) = sin(t) sin(2t) = 1/2 [cos(t-2t) - cos(t+2t)] = 1/2 [cos(-t) - cos(3t)] L{y(t)} = 1/2 [ L{cos(-t)} - L{cos(3t)} ] = 1/2 [ s/(s^2+(-1)^2) - s/(s^2+(3)^2)} ] = 1/2 [ s/(s^2+1) - s/(s^2+9) ] b) Calculons la transformée de Laplace de : y(t) = cos(3t) cos(2t) = 1/2 [cos(3t-2t) + cos(3t+2t)] = 1/2 [cos(t) + cos(5t)] L{y(t)} = 1/2 [ L{cos(t)} + L{cos(5t)} ] = 1/2 [ s/(s^2+(1)^2) + s/(s^2+(5)^2)} ] = 1/2 [ s/(s^2+1) + s/(s^2+25) ] c) Calculons la transformée de Laplace de : y(t) = sin(4t) cos(3t) = 1/2 [sin(4t-3t) + sin(4t+3t)] = 1/2 [sin(t) + sin(7t)] L{y(t)} = 1/2 [ L{sin(t)} + L{sin(7t)} ] = 1/2 [ 1/(s^2+(1)^2) + 7/(s^2+(7)^2)} ] = 1/2 [ 1/(s^2+1) + 7/(s^2+49) ] * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} 9jgxco5xcj4lk06bgchxu6yd0zww5ei 772121 772120 2026-09-13T10:26:51Z Xhungab 23827 772121 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] Remarque : sin(x)sin(y) = 1/2 [cos(x-y) - cos(x+y)] cos(x)cos(y) = 1/2 [cos(x-y) + cos(x+y)] sin(x)cos(y) = 1/2 [sin(x-y) + sin(x+y)] L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) a) Calculons la transformée de Laplace de : y(t) = sin(t) sin(2t) = 1/2 [cos(t-2t) - cos(t+2t)] = 1/2 [cos(-t) - cos(3t)] L{y(t)} = 1/2 [ L{cos(-t)} - L{cos(3t)} ] = 1/2 [ s/(s^2+(-1)^2) - s/(s^2+(3)^2)} ] = 1/2 [ s/(s^2+1) - s/(s^2+9) ] b) Calculons la transformée de Laplace de : y(t) = cos(3t) cos(2t) = 1/2 [cos(3t-2t) + cos(3t+2t)] = 1/2 [cos(t) + cos(5t)] L{y(t)} = 1/2 [ L{cos(t)} + L{cos(5t)} ] = 1/2 [ s/(s^2+(1)^2) + s/(s^2+(5)^2)} ] = 1/2 [ s/(s^2+1) + s/(s^2+25) ] c) Calculons la transformée de Laplace de : y(t) = sin(4t) cos(3t) = 1/2 [sin(4t-3t) + sin(4t+3t)] = 1/2 [sin(t) + sin(7t)] L{y(t)} = 1/2 [ L{sin(t)} + L{sin(7t)} ] = 1/2 [ 1/(s^2+(1)^2) + 7/(s^2+(7)^2)} ] = 1/2 [ 1/(s^2+1) + 7/(s^2+49) ] * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} 0a6i19xe3q5ezv0ebd5lrg07o22xcnx Mathc initiation/a547 0 81008 772128 771845 2026-09-13T10:40:57Z Xhungab 23827 772128 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t)'+y(t)=1 avec y(0) = 0|Sommaire]] : '''Résoudre l'équation : ''' y(t)' + y(t) = 1 y(0) = 0 '''Utilisons la transformée de Laplace''' : L{y(t)'} + L{y(t)} = L{1} sY(s) - y(0) + Y(s) = 1/s y(0) = 0 sY(s) - 0 + Y(s) = 1/s Y(s) (s + 1) = 1/s Y(s) = 1/s 1/(s + 1) '''Utilisons la méthode des fractions partielles.''' '''[[Mathc initiation/a567|Voir explication Ici]]''' 1 1 A B Y(s) = - ------- = --- + ------- s (s + 1) s (s + 1) si s = 0 A = 1 si s = -1 B = -1 donc 1 1 1 1 Y(s) = - ------- = - - ------- s (s + 1) s (s + 1) '''Utilisons la transformée inverse de Laplace :''' 1 1 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{ - } - L<sup>-1</sup>{ ------ } s s-(-1) -------------------- | y(t) = 1 - exp(-t) | -------------------- '''Vérifions :''' y(t)' + y(t) = 1 (1-exp(-t))' + (1-exp(-t)) = 1 +exp(-t) + 1-exp(-t) = 1 + 1 = 1 {{AutoCat}} a49fdfmexg3lbqpz1df1sjmukkeox9n Mathc initiation/a549 0 81013 772123 771977 2026-09-13T10:32:05Z Xhungab 23827 772123 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] Remarque : sinh(x)sinh(y) = 1/2 [cosh(x-y) - cosh(x+y)] cosh(x)cosh(y) = 1/2 [cosh(x-y) + cosh(x+y)] sinh(x)cosh(y) = 1/2 [sinh(x-y) + sinh(x+y)] L{sinh(t)} = 1/(s^2-1) ... L{sinh(at)} = a/(s^2-a^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(at)} = s/(s^2-a^2) a) Calculons la transformée de Laplace de : y(t) = sinh(t) sinh(2t) = 1/2 [cosh(t-2t) - cosh(t+2t)] = 1/2 [cosh(-t) - cosh(3t)] L{y(t)} = 1/2 [ L{cosh(-t)} - L{cosh(3t)} ] = 1/2 [ s/(s^2-(-1)^2) - s/(s^2-(3)^2)} ] = 1/2 [ s/(s^2-1) - s/(s^2-9) ] b) Calculons la transformée de Laplace de : y(t) = cosh(3t) cosh(2t) = 1/2 [cosh(3t-2t) + cosh(3t+2t)] = 1/2 [cosh(t) + cosh(5t)] L{y(t)} = 1/2 [ L{cosh(t)} + L{cosh(5t)} ] = 1/2 [ s/(s^2-(1)^2) + s/(s^2-(5)^2)} ] = 1/2 [ s/(s^2-1) + s/(s^2-25) ] c) Calculons la transformée de Laplace de : y(t) = sinh(4t) cosh(3t) = 1/2 [sinh(4t-3t) + sinh(4t+3t)] = 1/2 [sinh(t) + sinh(7t)] L{y(t)} = 1/2 [ L{sinh(t)} + L{sinh(7t)} ] = 1/2 [ 1/(s^2-(1)^2) + 7/(s^2-(7)^2)} ] = 1/2 [ 1/(s^2-1) + 7/(s^2-49) ] * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} 6u6336jojtdnii24u7t15oh35ys65j6 Mathc initiation/a564 0 81027 772136 771848 2026-09-13T10:43:13Z Xhungab 23827 772136 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3|Sommaire]] : '''Évaluer l'intégrale impropre suivante :''' /oo *** | exp(-'''3''' t) '''t sin(t)''' dt = /0 '''Écrivons la définition de Laplace de :''' /oo L{'''t sin(t)'''} = | exp(-s t) ['''t sin(t)'''] dt /0 '''Utilisons la propriété de la multiplication par t^n avec n = 1''' '''L{t F(t)} = -1 f'(s)''' L{t sin(t)} = -1 (-2 '''s''')/('''s'''^2+1)^2 f(s) = 1/(s^2+1) Posons '''s = 3''' *** = -1 (-2*'''3''')/('''3'''^2+1)^2 = 6/10^2 = 3/50 Vérifions avec [https://www.wolframalpha.com/ Mathematica] : integrate exp(-3 *t) * t *sin(t) dt from t=0 to infinity {{AutoCat}} 75va6nsizv30il349gi38rnyuq5w2kv Mathc initiation/a565 0 81028 772137 771849 2026-09-13T10:43:28Z Xhungab 23827 772137 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3|Sommaire]] : '''Évaluer l'intégrale impropre suivante :''' /oo *** | exp(-'''3''' t) '''sin(t) / t''' dt = /0 '''Écrivons la définition de Laplace de :''' /oo L{sin(t)/t} = | exp(-s t) ['''sin(t)/t'''] dt /0 '''Utilisons la propriété de la division par t''' /+oo L{ F(t)/t} = | f(u) du f(s) = '''1/(s^2+1)''' /s /+oo L{sin(t)/t} = | '''1/(u^2+1)''' du = PI/2 - atan(s) /s Posons s = '''3''' *** PI/2 - atan(3) = 0.321750554 Vérifions avec [https://www.wolframalpha.com/ Mathematica] : integrate exp(-3*t) * sin(t)/t dt from t=0 to infinity tan^(-1)(1/3) = 0.321750554 integrate 1/(u^2+1) dt from u=s to infinity π/2 - tan^(-1)(s) integrate 1/(u^2+1) dt from u=3 to infinity π/2 - tan^(-1)(3) = 0.321750554 {{AutoCat}} io9gcpfkypfbwt8atxdjnuwoer68f2i Mathc initiation/a566 0 81031 772114 771410 2026-09-13T10:15:20Z Xhungab 23827 772114 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] {| class="wikitable" |+Transformer des produits en sommes : |- ! [[Mathc initiation/a77|* Trigonométrie]] !! [[Mathc initiation/a78|* Trigonométrie hyperbolique]] |- || <syntaxhighlight lang="C"> cos(x)^2 = 1/2 +1/2 cos(2x) sin(x)^2 = 1/2 -1/2 cos(2x) cos(x)^3 = 3/4 cos(x) +1/4 cos(3x) sin(x)^3 = 3/4 sin(x) -1/4 sin(3x) cos(x)^4 = 3/8 +1/2 cos(2x) +1/8 cos(4x) sin(x)^4 = 3/8 -1/2 cos(2x) +1/8 cos(4x) cos(x) sin(x) = sin(2x)/2 sin(x)sin(y) = 1/2 [cos(x-y) -cos(x+y)] cos(x)cos(y) = 1/2 [cos(x-y) +cos(x+y)] sin(x)cos(y) = 1/2 [sin(x-y) +sin(x+y)] </syntaxhighlight> || <syntaxhighlight lang="C"> cosh(x)^2 = 1/2 +1/2 cosh(2x) sinh(x)^2 = 1/2 cosh(2x) -1/2 cosh(x)^3 = 3/4 cosh(x) +1/4 cosh(3x) sinh(x)^3 = 1/4 sinh(3x) -3/4 sinh(x) cosh(x)^4 = 3/8 +1/2 cosh(2x) +1/8 cosh(4x) sinh(x)^4 = 3/8 -1/2 cosh(2x) +1/8 cosh(4x) cosh(x)sinh(x) = sinh(2x)/2 sinh(x)sinh(y) = 1/2 [cosh(x+y) -cosh(x-y)] cosh(x)cosh(y) = 1/2 [cosh(x-y) +cosh(x+y)] sinh(x)cosh(y) = 1/2 [sinh(x-y) +sinh(x+y)] </syntaxhighlight> |} [[Mathc initiation/a406|.]] {{AutoCat}} tuilb0w7kjex0iubiw4h94pil1mx9cg Mathc initiation/a584 0 81062 772138 772072 2026-09-13T10:46:24Z Xhungab 23827 772138 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Se familiariser avec la transformée en Z|Sommaire]] {{Partie{{{type|}}}|Se familiariser avec la transformée en Z :}} Soit f(n) un signal causal discret : _oo+__ \ La transformée en Z de f(n) est F(z) = | f(n) z^(-n) /_____ n = 0 1 1 1 1 Soit = f(0) ----- + f(1) ----- + f(2) ----- + ... + f(n) ----- z^(0) z^(1) z^(2) z^(n) {{Partie{{{type|}}}|[[Mathc initiation/a581|* Les suites usuelles :]]}} {{Partie{{{type|}}}|[[Mathc initiation/a582|* Transformées en Z usuelles, des signaux causales discrets ::]]}} {{Partie{{{type|}}}|[[Mathc initiation/a583|* Propriétés des transformées en Z : ]]}} Se familiariser avec '''la transformée en Z Inverse''' : Pour ce familiariser avec '''la transformée en Z''', je vous conseille de voir les sections précédentes en étudiant les colonnes de gauche à droite. Pour '''la transformée en Z inverse''', il suffit de travailler avec les colonnes de droite à gauche. Il faudra se familiariser avec [[Mathc initiation/a569|la méthode des fractions partielles]], et la division des polynômes. Vous pouvez revoir [[Mathc initiation/Fichiers h : c18|La méthode de Horner (Factoriser, diviser des polynômes)]] Les méthodes plus avancées dépassent mes compétences. : {{AutoCat}} 4snqjd1t9ve77okh3uvd5az4h5a5m85 772142 772138 2026-09-13T10:51:27Z Xhungab 23827 772142 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Se familiariser avec la Transformée de Laplace|Sommaire]] {{Partie{{{type|}}}|Se familiariser avec la transformée en Z :}} Soit f(n) un signal causal discret : _oo+__ \ La transformée en Z de f(n) est F(z) = | f(n) z^(-n) /_____ n = 0 1 1 1 1 Soit = f(0) ----- + f(1) ----- + f(2) ----- + ... + f(n) ----- z^(0) z^(1) z^(2) z^(n) {{Partie{{{type|}}}|[[Mathc initiation/a581|* Les suites usuelles :]]}} {{Partie{{{type|}}}|[[Mathc initiation/a582|* Transformées en Z usuelles, des signaux causales discrets ::]]}} {{Partie{{{type|}}}|[[Mathc initiation/a583|* Propriétés des transformées en Z : ]]}} Se familiariser avec '''la transformée en Z Inverse''' : Pour ce familiariser avec '''la transformée en Z''', je vous conseille de voir les sections précédentes en étudiant les colonnes de gauche à droite. Pour '''la transformée en Z inverse''', il suffit de travailler avec les colonnes de droite à gauche. Il faudra se familiariser avec [[Mathc initiation/a569|la méthode des fractions partielles]], et la division des polynômes. Vous pouvez revoir [[Mathc initiation/Fichiers h : c18|La méthode de Horner (Factoriser, diviser des polynômes)]] Les méthodes plus avancées dépassent mes compétences. : {{AutoCat}} q53gezx3kdt8426i3phybnca78nofx4 Mathc initiation/a581 0 81063 772139 725846 2026-09-13T10:47:18Z Xhungab 23827 772139 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : : [[Mathc initiation/a584#* Les suites usuelles :| Sommaire]] : {{Partie{{{type|}}}|Les suites usuelles :}} * '''L'impulsion unitaire :''' δ(n) : Si n = 0 alors '''δ(0) = 1''' si n != 0 alors δ(n) = 0 * '''L'échelon unitaire :''' u(n) : Si n >= 0 alors '''u(n) = 1''' si n < 0 alors u(n) = 0 * '''La rampe :''' r(n) : Si n >= 0 alors '''r(n) = n''' si n < 0 alors r(n) = 0 * '''Le carré :''' c(n) : Si n >= 0 alors '''c(n) = n^2''' si n < 0 alors c(n) = 0 * '''L'exponentiel :''' f(n) : Si n >= 0 alors '''f(n) = a^n''' si n < 0 alors c(n) = 0 * '''La fonction cosinus discret :''' g(n) : Si n >= 0 alors '''g(n) = cos(kn)''' si n < 0 alors c(n) = 0 * '''La fonction sinus discret :''' h(n) : Si n >= 0 alors '''h(n) = sin(kn)''' si n < 0 alors c(n) = 0 : ---- {{AutoCat}} srwd65jp28krso5eap11sche8hzyh11 Mathc initiation/a582 0 81064 772140 725847 2026-09-13T10:47:40Z Xhungab 23827 772140 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a584#* Les suites usuelles :| Sommaire]] {{Partie{{{type|}}}|Transformées en Z usuelles, des signaux causales discrets :}} Pour simplifier l'écriture j'ai écrit le signal f(n) au lieu du signal causale discret f(n) u(n). '''Le signal : f(n)''' '''Transformée en Z : F(z)''' Domaine de convergence '''δ(n) = 1''' '''1''' C '''u(n) = 1''' '''z/(z-1)''' |z| > 1 '''r(n) = n''' '''z/(z-1)^2''' |z| > 1 '''c(n) = n^2''' '''z(z+1)/(z-1)^3''' |z| > 1 '''f(n) = a^n''' '''z/(z-a)''' |z| > |a| '''g(n) = cos(kn)''' '''[z^2-z cos(k)]/[z^2-2z cos(k)+1]''' |z| > 1 '''h(n) = sin(kn)''' '''[z sin(k)]/[z^2-2z cos(k)+1]''' |z| > 1 : {{AutoCat}} n012qxc2wcumkvk0ojnitew5z1u9jgx Mathc initiation/a583 0 81065 772141 725848 2026-09-13T10:48:02Z Xhungab 23827 772141 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a584#* Les suites usuelles :| Sommaire]] {{Partie{{{type|}}}|Propriétés des transformées en Z :}} Soit f(n) u(n) un signal causal discret : '''* La transformée en Z est un opérateur linéaire :''' '''Z[a f(n) + b g(n)] = a Z[f(n)] + b Z[g(n)] = a F(z) + b G(z)''' '''* Multiplication par une exponentielle : [[Mathc initiation/a585|Exemples]] ''' a^n f(n) u(n) Si Z[f(n)] = F(z) alors '''Z[a^n f(n)] = F(z/a)''' '''* Multiplication par la variable d'évolution : [[Mathc initiation/a588|Exemples]] ''' n f(n) u(n) Si Z[f(n)] = F(z) alors '''Z[n f(n)] = -z F'(z)''' '''* Le retard de no unités : [[Mathc initiation/a589|Exemples]] ''' f(n-no) u(n-no) est un signal causal retardé de no unités. Image (L'invité retardé, de 12h, arrivera à 12h+no minutes) Si Z[f(n)] = F(z) alors '''Z[f(n-no)] = z^(-no) F(z)''' '''* L'avance d'une unité : [[Mathc initiation/a590|Exemples]] ''' f(n+1) u(n+1) est un signal causal avancé de 1 unité. Image (L'invité en avance, de 12h, arrivera à 12h-1 minute, 11h59 minutes) Si Z[f(n)] = F(z) alors '''Z[f(n+1)] = z^(1) [F(z)-f(0)]''' '''* L'avance de deux unités : [[Mathc initiation/a591|Exemples]]''' f(n+2) u(n+2) est un signal causal avancé de 2 unité. Image (L'invité en avance, de 12h, arrivera à 12h-2 minutes, 11h58 minutes) Si Z[f(n)] = F(z) alors '''Z[f(n+2)] = z^(2) [F(z)-f(0)-f(1)z^(-1)]''' : {{AutoCat}} o3tuz3c9u6va40zaeh0sks3gmr3hqu4 Mathc initiation/a608 0 81108 772133 771403 2026-09-13T10:42:24Z Xhungab 23827 772133 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3|Sommaire]] : '''Résoudre l'équation : ''' y(t) ' ' - 9 y(t) = 0 *** y(0) = 1 y(0)' = 3 '''Utilisons la transformée de Laplace''' : L{y(t) ' '} + 9 L{y(t)} = L{0} [s**2 Y(s) - s y(0) - y(0)'] + 9 Y(s) = 0 *** y(0) = 1 y(0)' = 3 [s**2 Y(s) - s 1 - 3 ] + 9 Y(s) = 0 s**2 Y(s) + 9 Y(s) - s - 3 = 0 Y(s) (s**2 + 9) = s + 3 Y(s) = (s+3)/(s**2+9) Y(s) = (s)/(s**2+9) + (3)/(s**2+9) '''Utilisons la transformée inverse de Laplace :''' L<sup>-1</sup>{Y(s)} = L<sup>-1</sup>{(s)/(s**2+9)} + L<sup>-1</sup>{(3)/(s**2+9)} y(t) = cos(3t) + sin(3t) '''Remarque :''' * L<sup>-1</sup>{('''3''')/(s**2+9)} = sin(3t) * L<sup>-1</sup>{('''1''')/(s**2+9)} = 1/3 sin(3t) {{AutoCat}} 4utyg0w1nbq3r1qjnzurditcvvdx4vy Mathc initiation/a613 0 81127 772135 771951 2026-09-13T10:42:56Z Xhungab 23827 772135 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3|Sommaire]] : {{Partie{{{type|}}}|Résoudre un sytème d'équations différentielles}} : X_1'(t) + 3 X_1(t) + X_2(t) = e^(-5t) X_2'(t) + X_1(t) + 5 X_2(t) = e^(-3t) Avec X_1(0) = 0 et X_2(0) = 0 '''Ecrivons la transformé de Laplace du système :''' sx_1(s) - X_1(0) + 3x_1(s) + x_2(s) = 1/(s+5) sx_2(s) - X_2(0) + x_1(s) + 5 x_2(s) = 1/(s+3) sx_1(s) + 3x_1(s) + x_2(s) = 1/(s+5) sx_2(s) + x_1(s) + 5 x_2(s) = 1/(s+3) (s+3)x_1(s) + x_2(s) = 1/(s+5) x_1(s) + (s+5)x_2(s) = 1/(s+3) '''Utilisons l'algorithme de Cramer pour resoudre le système :''' |1/(s+5) 1 | |1/(s+3) (s+5)| 1 - 1/(s+3) ((s+3)-1)/(s+3) s+2 x_1(s) = ------------- = ------------ = --------------- = ------------------- |(s+3) 1 | (s+3)(s+5)-1 (s+3)(s+5)-1 (s+3)((s+3)(s+5)-1) | 1 (s+5)| |(s+3) 1/(s+5)| | 1 1/(s+3)| 1 - 1/(s+5) ((s+5)-1)/(s+5) s+4 x_2(s) = -------------- = ------------ = --------------- = ------------------- |(s+3) 1 | (s+3)(s+5)-1 (s+3)(s+5)-1 (s+5)((s+3)(s+5)-1) | 1 (s+5) | s+2 x_1(s) = ----------------------- s^3 + 11 s^2+ 38 s + 42 s+4 x_2(s) = ------------------------ s^3 + 13 s^2 + 54 s + 70 '''Méthodes pour les fractions partielles pour x_1(s) avec octave''' s+2 N x_1(s) = ----------------------- = - s^3 + 11 s^2+ 38 s + 42 D Commande : N = [1,2]; D = [1,11,38,42]; [r, p, k, e] = residue (N, D) Résultat r = [-0.5000, 1.0000, -0.5000] Numérateur p = [-5.4142, -3.0000, -2.5858] Dénominateur (s-p) k = [](0x0) e = [ 1, 1, 1] Puissance de (s-p)^e s+2 -0.5 1.0 -0.5 x_1(s) = ----------------------- = ----------- + -------- + ----------- s^3 + 11 s^2+ 38 s + 42 s-(-5.4142) s-(-3.0) s-(-2.5858) '''Utilisons la méthode inverse de la transformé de Laplace''' X_1(t) = -0.5*exp(-5.4142*t) + exp(-3*t)- 0.5*exp(-2.5858*t) '''Méthodes pour les fractions partielles pour x_2(s) avec octave''' s+4 x_2(s) = ------------------------ s^3 + 13 s^2 + 54 s + 70 Commande : N = [1,4]; D = [1,13,54,70]; [r, p, k, e] = residue (N, D) Résultat r = [-1.2071, 1.0000, 0.2071] Numérateur p = [-5.4142, -5.0000, -2.5858] Dénominateur (s-p) k = [](0x0) e = [ 1, 1, 1] Puissance de (s-p)^e s+4 -1.2071 1.0000 0.2071 x_2(s) = ------------------------ = ----------- + -------- + ----------- s^3 + 13 s^2 + 54 s + 70 s-(-5.4142) s-(-5.0) s-(-2.5858) '''Utilisons la méthode inverse de la transformé de Laplace''' X_2(t) = -1.2071*exp(-5.4142*t) + exp(-5*t)- 0.2071*exp(-2.5858*t) '''Dessiner avec Gnuplot les fonctions X_1(t) et X_2(t)''' plot [-.5:10] [-.5:.1]\ -0.5*exp(-5.4142*x) + exp(-3*x)- 0.5*exp(-2.5858*x),\ -1.2071*exp(-5.4142*x) + exp(-5*x)- 0.2071*exp(-2.5858*x) reset : . : {{AutoCat}} f8yv7dmniqcf5xx0cfecyd5bnu0l2ue Mathc initiation/a00ad 0 81407 772129 771401 2026-09-13T10:41:12Z Xhungab 23827 772129 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t)'+y(t)=1 avec y(0) = 0|Sommaire]] : '''Résoudre l'équation : ''' y(t)' + 3 y(t) = 6 y(0) = 0 '''Utilisons la transformée de Laplace''' : L{y(t)'} + 3 L{y(t)} = L{6} sY(s) - y(0) + 3 Y(s) = 6/s y(0) = 0 sY(s) - 0 + 3 Y(s) = 6/s Y(s) (s + 3) = 6/s Y(s) = 6/s 1/(s + 3) '''Utilisons la méthode des fractions partielles.''' '''[[Mathc initiation/a00ap|Voir explication Ici]]''' 1 6 A B Y(s) = - ------- = --- + ------- s (s + 3) s (s + 3) si s = 0 A = 2 si s = -3 B = -2 donc 1 6 2 2 Y(s) = - ------- = --- - ------- s (s + 3) s (s + 3) '''Utilisons la transformée inverse de Laplace :''' 2 2 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{ - } - L<sup>-1</sup>{ ------ } s s-(-3) ----------------------- | y(t) = 2 - 2 exp(-3t) | ----------------------- '''Vérifions :''' y(t)' + 3 y(t) = 6 (2-2 exp(-3t))' + 3 (2-2 exp(-3t)) = 6 6 exp(-3t) + 6 - 6 exp(-3t) = 6 6 = 6 {{AutoCat}} nwsba8mkj0etncnoz1e4t1a5xu9wa18 Fonctionnement d'un ordinateur/L'accélération matérielle de la virtualisation 0 82429 772086 763699 2026-09-12T17:03:08Z Mewtow 31375 /* Les Virtual-8086 mode extensions */ 772086 wikitext text/x-wiki La virtualisation est l'ensemble des techniques qui permettent de faire tourner plusieurs systèmes d'exploitation en même temps. Le terme est polysémique, mais c'est la définition que nous allons utiliser pour ce qui nous intéresse. La virtualisation demande d'utiliser un logiciel dit '''hyperviseur''', qui permet de faire tourner plusieurs OS en même temps. Les hyperviseurs sont en quelque sorte situés sous le système d'exploitation. On peut les voir comme une sorte de sous-système d'exploitation, de système d'exploitation pour les systèmes d'exploitation. A ce propos, les OS virtualisés sont appelés des ''OS invités'', alors que l'hyperviseur est parfois appelé l'''OS hôte''. [[File:Diagramme ArchiHyperviseur.png|centre|vignette|upright=2|Différence entre système d'exploitation et hyperviseur.]] Les processeurs modernes intègrent des techniques pour accélérer la virtualisation. Les techniques en question sont assez variées, allant d'un niveau de privilège en plus des modes noyau/utilisateur à des modifications de la mémoire virtuelle, en passant à des modifications liées aux interruptions matérielles. Mais pour comprendre tout cela, il va falloir faire quelques explications sur la virtualisation elle-même. ==La virtualisation : généralités== Pour faire tourner plusieurs OS en même temps, l'hyperviseur recourt à de nombreux stratagèmes. Il doit partager le processeur, la RAM et les entrées-sorties entre plusieurs OS. Le partage de la RAM demande concrètement des modifications assez légères de la mémoire virtuelle, qu'on verra en temps voulu. Le partage du processeur est assez simple : les OS s'exécutent à tour de rôle sur le processeur, chacun pendant un temps défini, fixe. Une fois leur temps d'exécution passé, ils laissent la main à l'OS suivant. C'est l’hyperviseur qui s'occupe de tout cela, grâce à une interruption commandée à un ''timer''. Ce système de partage est une forme de '''multiplexage'''. A ce propos, il s'agit de la même solution que les OS utilisent pour faire tourner plusieurs programmes en même temps sur un processeur/cœur unique. La gestion des entrées-sorties demande d'utiliser des techniques d''''émulation''', plus complexes à expliquer. Un hyperviseur peut parfaitement simuler du matériel qui n'est pas installé sur l'ordinateur. Par exemple, il peut faire croire à un OS qu'une carte réseau obsolète, datant d'il y a 20 ans, est installée sur l'ordinateur, alors que ce n'est pas le cas. Les commandes envoyées par l'OS à cette carte réseau fictive sont en réalité traitées par une vraie carte réseau par l’hyperviseur. Pour cela, l’hyperviseur intercepte les commandes envoyées aux entrées-sorties, et les traduit en commandes compatibles avec les entrées-sorties réellement installées sur l'ordinateur. ===Les machines virtuelles=== L'exemple avec la carte réseau est un cas particulier, l'hyperviseur faisant beaucoup de choses dans le genre. L'hyperviseur peut faire croire à l'ordinateur qu'il a plus ou moins de RAM que ce qui est réellement installé, par exemple. L'hyperviseur implémente ce qu'on appelle des '''machines virtuelles'''. Il s'agit d'une sorte de faux matériel, simulé par un logiciel. Un logiciel qui s’exécute dans une machine virtuelle aura l'impression de s’exécuter sur un matériel et/ou un O.S différent du matériel sur lequel il est en train de s’exécuter. : Dans ce qui suit, nous parlerons de V.M (virtual machine), pour parler des machines virtuelles. [[File:VM-monitor-french.png|centre|vignette|upright=2|Machines virtuelles avec la virtualisation.]] Avec la virtualisation, plusieurs machines virtuelles sont gérées par l'hyperviseur, chacune étant réservée à un système d'exploitation. D'ailleurs, hyperviseurs sont parfois appelés des ''Virtual Machine Manager''. Nous utiliserons d'ailleurs l'abréviation VMM dans les schémas qui suivent. Il existe deux types d'hyperviseurs, qui sont nommés type 1 et type 2. Le premier type s'exécute directement sur le matériel, alors que le second est un logiciel qui s’exécute sur un OS normal. Pour ce qui nous concerne, la distinction n'est pas très importante. [[File:Ansatz der Systemvirtualisierung zur Schaffung virtueller Betriebsumgebungen.png|centre|vignette|upright=2.5|Comparaison des différentes techniques de virtualisation : sans virtualisation à gauche, virtualisation de type 1 au milieu, de type 2 à droite.]] La virtualisation est une des utilisations possibles, mais il y en a d'autres. La plus intéressante est celle des émulateurs. Ces derniers sont des logiciels qui permettent de simuler le fonctionnement d'anciens ordinateurs ou consoles de jeux. L'émulateur crée une machine virtuelle qui est réservée à un programme, à savoir le jeu à émuler. Il y a une différence de taille entre un émulateur et un hyperviseur. L'émulation émule une machine virtuelle totalement différente, alors que la virtualisation doit émuler les entrées-sorties mais pas le processeur. Avec un hyperviseur, le système d'exploitation s'exécute sur le processeur lui-même. Le code de l'OS est compatible avec le processeur de la machine, dans le sens où il est compilé pour le jeu d'instruction du processeur de la machine réelle. Les instructions de l'OS s'exécutent directement. Par contre, un émulateur exécute un jeu qui est programmé pour une machine dont le processeur est totalement différent. Le jeu d'instruction de la machine virtuelle et celui du vrai processeur n'est pas le même. L'émulation implique donc de traduire les instructions à exécuter dans la V.M par des instructions exécutables par le processeur. Ce n'est pas le cas avec la virtualisation, le jeu d'instruction étant le même. ===La méthode ''trap and emulate'' basique=== Pour être considéré comme un logiciel de virtualisation, un logiciel doit remplir trois critères : * L'équivalence : l'O.S virtualisé et les applications qui s’exécutent doivent se comporter comme s'ils étaient exécutés sur le matériel de base, sans virtualisation. * Le contrôle des ressources : tout accès au matériel par l'O.S virtualisé doit être intercepté par la machine virtuelle et intégralement pris en charge par l'hyperviseur. * L'efficacité : La grande partie des instructions machines doit s’exécuter directement sur le processeur, afin de garder des performances correctes. Ce critère n'est pas respecté par les émulateurs matériels, qui doivent simuler le jeu d'instruction du processeur émulé. Remplir ces trois critères est possible sous certaines conditions, établies par les théorèmes de Popek et Goldberg. Ces théorèmes se basent sur des hypothèses précises. De fait, la portée de ces théorèmes est limitée, notamment pour le critère de performance. Ils partent notamment du principe que l'ordinateur utilise la segmentation pour la mémoire virtuelle, et non la pagination. Il part aussi du principe que les interruptions ont un cout assez faible, qu'elles sont assez rares. Mais laissons ces détails de côté, le cœur de ces théorèmes repose sur une hypothèse simple : la présence de différents types d'instructions machines. Pour rappel, il faut distinguer les instructions privilégiées de celles qui ne le sont pas. Les instructions privilégiées ne peuvent s'exécuter que en mode noyau, les programmes en mode utilisateur ne peuvent pas les exécuter. Parmi les instructions privilégiées on peut distinguer un sous-groupe appelé les '''instructions systèmes'''. Le premier type regroupe les '''instructions d'accès aux entrées-sorties''', aussi appelées instructions sensibles à la configuration. Le second type est celui des '''instructions de configuration du processeur''', qui agissent sur les registres de contrôle du processeur, aussi appelées instructions sensibles au comportement. Elles servent notamment à gérer la mémoire virtuelle, mais pas que. La théorie de Popek et Goldberg dit qu'il est possible de virtualiser un O.S à une condition : que les instructions systèmes soient toutes des instructions privilégiées, c’est-à-dire exécutables seulement en mode noyau. Virtualiser un O.S demande simplement de le démarrer en mode utilisateur. Quand l'O.S fait un accès au matériel, il le fait via une instruction privilégiée. Vu que l'OS est en mode utilisateur, cela déclenche une exception matérielle, qui émule l'instruction privilégiée. L'hyperviseur n'est ni plus ni moins qu'un ensemble de routines d'interruptions, chaque routine simulant le fonctionnement du matériel émulé. Par exemple, un accès au disque dur sera émulé par une routine d'interruption, qui utilisera les appels systèmes fournit par l'OS pour accéder au disque dur réellement présent dans l'ordinateur. Cette méthode est souvent appelée la méthode ''trap and emulate''. [[File:Virtualisation avec la méthode trap-and-emulate.png|centre|vignette|upright=2.0|Virtualisation avec la méthode trap-and-emulate]] La méthode ''trap and emulate'' ne fonctionne que si certaines contraintes sont respectées. Un premier problème est que beaucoup de jeux d'instructions anciens ne respectent pas la règle "les instructions systèmes sont toutes privilégiées". Par exemple, ce n'est pas le cas sur les processeurs x86 32 bits. Sur ces CPU, les instructions qui manipulent les drapeaux d'interruption ne sont pas toutes des instructions privilégiées, idem pour les instructions qui manipulent les registres de segmentation, celles liées aux ''call gates'', etc. A cause de cela, il est impossible d'utiliser la méthode du ''trap and emulate''. La seule solution qui ne requiert pas de techniques matérielles est de traduire à la volée les instructions systèmes problématiques en appels systèmes équivalents, grâce à des techniques de '''réécriture de code'''. Enfin, certaines instructions dites '''sensibles au contexte''' ont un comportement différent entre le mode noyau et le mode utilisateur. En présence de telles instructions, la méthode ''trap and emulate'' ne fonctionne tout simplement pas. Grâce à ces instructions, le système d’exploitation ou un programme applicatif peut savoir s'il s'exécute en mode utilisateur ou noyau, ou hyperviseur, ou autre. La virtualisation impose l'usage de la mémoire virtuelle, sans quoi plusieurs OS ne peuvent pas se partager la même mémoire physique. De plus, il ne faut pas que la mémoire physique, non-virtuelle, puisse être adressée directement. Et cette contrainte est violée, par exemple sur les architectures MIPS qui exposent des portions de la mémoire physique dans certaines zones fixées à l'avance de la mémoire virtuelle. L'OS est compilé pour utiliser ces zones de mémoire pour accéder aux entrées-sorties mappées en mémoire, entre autres. En théorie, on peut passer outre le problème en marquant ces zones de mémoire comme inaccessibles, toute lecture/écriture à ces adresses déclenche alors une exception traitée par l'hyperviseur. Mais le cout en performance est alors trop important. Quelques hyperviseurs ont été conçus pour les architectures MIPS, dont le projet de recherche DISCO, mais ils ne fonctionnaient qu'avec des systèmes d'exploitation recompilés, de manière à passer outre ce problème. Les OS étaient recompilés afin de ne pas utiliser les zones mémoire problématiques. De plus, les OS étaient modifiés pour améliorer les performances en virtualisation. Les OS disposaient notamment d'appels systèmes spéciaux, appelés des ''hypercalls'', qui exécutaient des routines de l'hyperviseur directement. Les appels systèmes faisant appel à des instructions systèmes étaient ainsi remplacés par des appels système appelant directement l'hyperviseur. Le fait de modifier l'OS pour qu'il communique avec un hyperviseur, dont il a connaissance de l'existence, s'appelle la '''para-virtualisation'''. [[File:Virtualization - Para vs Full.png|centre|vignette|upright=2.5|Virtualization - Para vs Full]] ==La virtualisation du processeur== La virtualisation demande de partager le matériel entre plusieurs machines virtuelles. Précisément, il faut partager : le processeur, la mémoire RAM, les entrées-sorties. Les trois sont gérés différemment. Par exemple, la virtualisation des entrées-sorties est gérée par l’hyperviseur, parfois aidé par le ''chipset'' de la carte mère. Virtualiser des entrées-sorties demande d'émuler du matériel inexistant, mais aussi de dupliquer des entrées-sorties de manière à ce le matériel existe dans chaque VM. Partager la mémoire RAM entre plusieurs VM est assez simple avec la mémoire virtuelle, bien que cela demande quelques adaptations. Maintenant, voyons ce qu'il en est pour le processeur. ===Le niveau de privilège hyperviseur=== Sur certains CPU modernes, il existe un niveau de privilège appelé le '''niveau de privilège hyperviseur''' qui est utilisé pour les techniques de virtualisation. Le niveau de privilège hyperviseur est réservé à l’hyperviseur et il a des droits d'accès spécifiques. Il n'est cependant pas toujours activé. Par exemple, si aucun hyperviseur n'est installé sur la machine, le processeur dispose seulement des niveaux de privilège noyau et utilisateur, le mode noyau n'ayant alors aucune limitation précise. Mais quand le niveau de privilège hyperviseur est activé, une partie des manipulations est bloquée en mode noyau et n'est possible qu'en mode hyperviseur. Le fonctionnement se base sur la différence entre instruction privilégiée et instruction système. Les instructions privilégiées peuvent s'exécuter en niveau noyau, alors que les instructions systèmes ne peuvent s'exécuter qu'en niveau hyperviseur. L'idée est que quand le noyau d'un OS exécute une instruction système, une exception matérielle est levée. L'exception bascule en mode hyperviseur et laisse la main à une routine de l'hyperviseur. L'hyperviseur fait alors des manipulations précise pour que l'instruction système donne le même résultat que si elle avait été exécutée par l'ordinateur simulé par la machine virtuelle. [[File:Virtualisation avec un mode hyperviseur.png|centre|vignette|upright=2|Virtualisation avec un mode hyperviseur.]] Il est ainsi possible d'émuler des entrées-sorties avec un cout en performance assez léger. Précisément, ce mode hyperviseur améliore les performances de la méthode du ''trap-and-emulate''. La méthode ''trap-and-emulate'' basique exécute une exception matérielle pour toute instruction privilégiée, qu'elle soit une instruction système ou non. Mais avec le niveau de privilège hyperviseur, seules les instructions systèmes déclenchent une exception, pas les instructions privilégiées non-système. Les performances sont donc un peu meilleures, pour un résultat identique. Après tout, les entrées-sorties et la configuration du processeur suffisent à émuler une machine virtuelle, les autres instructions noyau ne le sont pas. Sur les processeurs ARM, il est possible de configurer quelles instructions sont détournées vers le mode hyperviseur et celles qui restent en mode noyau. En clair, on peut configurer quelles sont les instructions systèmes et celles qui sont simplement privilégiées. Et il en est de même pour les interruptions : on peut configurer si elles exécutent la routine de l'OS normal en mode noyau, ou si elles déclenchent une exception matérielle qui redirige vers une routine de l’hyperviseur. En l'absence d'hyperviseur, toutes les interruptions redirigent vers la routine de l'OS normale, vers le mode noyau. Il faut noter que le mode hyperviseur n'est compatible qu'avec les hyperviseurs de type 1, à savoir ceux qui s'exécutent directement sur le matériel. Par contre, elle n'est pas compatible avec les hyperviseurs de type 2, qui sont des logiciels qui s'exécutent comme tout autre logiciel, au-dessus d'un système d'exploitation sous-jacent. ===L'Intel VT-X et l'AMD-V=== Les processeurs ARM de version v8 et plus incorporent un mode hyperviseur, mais pas les processeurs x86. À la place, ils incorporent des technologies alternatives nommées Intel VT-X ou l'AMD-V. Les deux ajoutent de nouvelles instructions pour gérer l'entrée et la sortie d'un mode réservé à l’hyperviseur. Mais ce mode réservé à l'hyperviseur n'est pas un niveau de privilège comme l'est le mode hyperviseur. L'Intel VT-X et l'AMD-V dupliquent le processeur en deux modes de fonctionnement : un mode racine pour l'hyperviseur, un mode non-racine pour l'OS et les applications. Fait important : les niveaux de privilège sont dupliqués eux aussi ! Par exemple, il y a un mode noyau racine et un mode noyau non-racine, idem pour le mode utilisateur, idem pour le mode système (pour le BIOS/UEFI). De même, les modes réel, protégé, v8086 ou autres, sont eux aussi dupliqués en un exemplaire racine et un exemplaire non-racine. L'avantage est que les systèmes d'exploitation virtualisés s'exécutent bel et bien en mode noyau natif, l'hyperviseur a à sa disposition un mode noyau séparé. D'ailleurs, les deux modes ont des registres d'interruption différents. Le mode racine et le mode non-racine ont chacun leurs espaces d'adressage séparés de 64 bit, avec leur propre table des pages. Et cela demande des adaptations au niveau de la TLB. La transition entre mode racine et non-racine se fait lorsque le processeur exécute une instruction système ou lors de certaines interruptions. Au minimum, toute exécution d'une instruction système fait commuter le processeur mode racine et lance l'exécution des routines de l’hyperviseur adéquates. Les interruptions matérielles et exceptions font aussi passer le CPU en mode racine, afin que l’hyperviseur puisse gérer le matériel. De plus, afin de gérer le partage de la mémoire entre OS, certains défauts de page déclenchent l'entrée en mode racine. Les ''hypercalls'' de la para-virtualisation sont supportés grâce à aux instructions ''vmcall'' et ''vmresume'' qui permettent respectivement d'appeler une routine de l’hyperviseur ou d'en sortir. La transition demande de sauvegarder/restaurer les registres du processeur, comme avec les interruptions. Mais cette sauvegarde est réalisée automatiquement par le processeur, elle n'est pas faite par les routines de l'hyperviseur. L’implémentation de cette sauvegarde/restauration se fait surtout via le microcode du processeur, car elle demande beaucoup d'étapes. Elle est en conséquence très lente. Le processeur sauvegarde l'état de chaque machine virtuelle en mémoire RAM, dans une structure de données appelée la ''Virtual Machine Control Structure'' (VMCS). Elle mémorise surtout les registres du processeur à l'instant t. Lorsque le processeur démarre l'exécution d'une VM sur le processeur, cette VMCS est recopiée dans les registres pour rétablir la VM à l'endroit où elle s'était arrêtée. Lorsque la VM est interrompue et doit laisser sa place à l'hyperviseur, les registres et l'état du processeur sont sauvegardés dans la VMCS adéquate. ==La virtualisation de la mémoire : mémoire virtuelle et MMU== Avec la virtualisation, les différentes machines virtuelles, les différents OS doivent se partager la mémoire physique, en plus d'être isolés les uns des autres. L'idée est d'utiliser la mémoire virtuelle pour cela. L'espace d'adressage physique vu par chaque OS est en réalité un espace d'adressage fictif, qui ne correspond pas à la mémoire physique. Les adresses physiques manipulées par l'OS sont en réalité des adresses intermédiaires entre les adresses physiques liées à la RAM, et les adresses virtuelles vues par les processus. Pour les distinguer, nous parlerons d'adresses physiques de l'hôte pour parler des adresses de la RAM, et des adresses physiques invitées pour parler des adresses manipulées par les OS virtualisés. Sans accélération matérielle, la traduction des adresses physiques invitées en adresses hôte est réalisée par une seconde table des pages, appelée la ''shadow page table'', ce qui donnerait '''table des pages cachée''' en français. La table des pages cachée est prise en charge par l'hyperviseur. Toute modification de la table des pages cachée est réalisée par l'hyperviseur, les OS ne savent même pas qu'elle existe. [[File:Shadowpagetables.png|centre|vignette|upright=2|Table des pages cachée.]] ===La MMU et la virtualisation : les tables des pages emboitées=== Une autre solution demande un support matériel des tables des pages emboitées, à savoir qu'il y a un arbre de table des pages, chaque consultation de la première table des pages renvoie vers une seconde, qui renvoie vers une troisième, et ainsi de suite jusqu'à tomber sur la table des pages finale qui renvoie l'adresse physique réelle. L'idée est l'utiliser une seule table des pages, mais d'ajouter un ou deux niveaux supplémentaires. Pour l'exemple, prenons le cas des processeurs x86. Sans virtualisation, l'OS utilise une table des pages de 4 niveaux. Avec, la table des pages a un niveau en plus, qui sont ajoutés à la fin de la dernière table des pages normale. Les niveaux ajoutés s'occupent de la traduction des adresses physiques invitées en adresses physiques hôte. On parle alors de '''table des pages étendues''' pour désigner ce nouveau format de table des pages conçu pour la virtualisation. Il faut que le processeur soit modifié de manière à parcourir automatiquement les niveaux ajoutés, ce qui demande quelques modifications de la TLB et du ''page table walker''. Les modifications en question ne font que modifier le format normal de la table des pages, et sont donc assez triviales. Elles ont été implémentées sur les processeurs AMD et Intel. AMD a introduit les tables des pages étendues sur ses processeurs Opteron, destinés aux serveurs, avec sa technologie ''Rapid Virtualization Indexing''. Intel, quant à lui, a introduit la technologie sur les processeurs i3, i5 et i7, sous le nom ''Extended Page Tables''. Les processeurs ARM ne sont pas en reste avec la technologie ''Stage-2 page-tables'', qui est utilisée en mode hyperviseur. ===La virtualisation de l'IO-MMU=== Si la MMU du processeur est modifiée pour gérer des tables des pages étendues, il en est de même pour les IO-MMU des périphériques et contrôleurs DMA.Les périphériques doivent idéalement intégrer une IO-MMU pour faciliter la virtualisation. La raison est globalement la même que pour le partage de la mémoire. Les pilotes de périphériques utilisent des adresses qui sont des adresses physiques sans virtualisation, mais qui deviennent des adresses virtuelles avec. Quand le pilote de périphérique configure un contrôleur DMA, pour transférer des données de la RAM vers un périphérique, il utilisera des adresses virtuelles qu'il croit physique pour adresser les données en RAM. Pour éviter tout problème, le contrôleur DMA doit traduire les adresses qu'il reçoit en adresses physiques. Pour cela, il y a besoin d'une IO-MMU intégrée au contrôleur DMA, qui est configurée par l'hyperviseur. Toute IO-MMU a sa propre table des pages et l'hyperviseur configure les table des pages pour chaque périphérique. Ainsi, le pilote de périphérique manipule des adresses virtuelles, qui sont traduites en adresses physiques directement par le matériel lui-même, sans intervention logicielle. Pour gérer la virtualisation, on fait la même chose qu'avec une table des pages emboitée habituelle : on l'étend en ajoutant des niveaux. L'IO-MMU peut fonctionner dans un mode normal, sans virtualisation, où les adresses virtuelles reçues du ''driver'' sont traduite avec une table des pages normale, non-emboitée. Mais elle a aussi un mode virtualisation qui utilise des tables de pages étendues. ==La virtualisation des entrées-sorties== Virtualiser les entrées-sorties est simple sur le principe. Un OS communique avec le matériel soit via des ports IO, soit avec des entrées-sorties mappées en mémoire. Le périphérique répond avec des interruptions ou via des transferts DMA. Virtualiser les périphériques demande alors d'émuler les ports IO, les entrées-sorties mappées en mémoire, le DMA et les interruptions. ===La virtualisation logicielle des interruptions=== Émuler les ports IO est assez simple, vu que l'OS lit ou écrit dedans grâce à des instructions IO spécialisées. Vu que ce sont des instructions système, la méthode ''trap and emulate'' suffit. Pour les entrées-sorties mappées en mémoire, l'hyperviseur a juste à marquer les adresses mémoires concernées comme étant réservées/non-allouées/autre. Tout accès à ces adresses lèvera une exception matérielle d'accès mémoire interdit, que l’hyperviseur intercepte et gère via ''trap and emulate''. L'émulation du DMA est triviale, vu que l'hyperviseur a accès direct à celui-ci, sans compter que l'usage d'une IO-MMU résout beaucoup de problèmes. La gestion des interruptions matérielles, les fameuses IRQ, est quant à elle plus complexe. Les interruptions matérielles ne sont pas à prendre en compte pour toutes les machines virtuelles. Par exemple, si une machine virtuelle n'a pas de carte graphique, pas besoin qu'elle prenne en compte les interruptions provenant de la carte graphique. La gestion des interruptions matérielles n'est pas la même si l'ordinateur grée des cartes virtuelles ou s'il se débrouille avec une carte physique unique. Lors d'une interruption matérielle, le processeur exécute la routine adéquate de l'hyperviseur. Celle-ci enregistre qu'il y a eu une IRQ et fait quelques traitements préliminaires. Ensuite, elle laisse la main au système d'exploitation concerné, qui exécute alors sa routine d'interruption. Une fois la routine de l'OS terminée, l'OS dit au contrôleur d'interruption qu'il a terminé son travail. Mais cela demande d'interagir avec le contrôleur d'interruption, ce qui déclenche une exception qui appelle l'hyperviseur. L'hyperviseur signale au contrôleur d'interruption que l'interruption matérielle a été traitée. Il rend alors définitivement la main au système d'exploitation. Le processus complet demande donc plusieurs changements entre mode hyperviseur et OS, ce qui est assez couteux en performances. Vu que le matériel simulé varie d'une machine virtuelle à l'autre, chaque machine virtuelle a son propre vecteur d'interruption. Par exemple, si une machine virtuelle n'a pas de carte graphique son vecteur d'interruption ne pointera pas vers les routines d'interruption d'un quelconque GPU. L'hyperviseur gère les différents vecteurs d'interruption de chaque VM et traduit les interruptions reçues en interruptions destinées aux VM/OS. Si la méthode ''trap and emulate'' fonctionne, ses performances ne sont cependant pas forcément au rendez-vous. Tous les matériels ne se prêtent pas tous bien à la virtualisation, surtout les périphériques anciens. Pour éliminer une partie de ces problèmes, il existe différentes techniques, accélérées en matériel ou non. Elles permettent aux machines virtuelles de communiquer directement avec les périphériques, sans passer par l'hyperviseur. ===La virtualisation des périphériques avec l'affectation directe=== Virtualiser les entrées-sorties avec de bonnes performances est plus complexe. En pratique, cela demande une intervention du matériel. Le ''chipset'' de la carte mère, les différents contrôleurs d'interruption et bien d'autres circuits doivent être modifiés. Diverses techniques permettent de faciliter le partage des entrées-sorties entre machines virtuelles. La première est l''''affectation directe''', qui alloue un périphérique à une machine virtuelle et pas aux autres. Par exemple, il est possible d'assigner la carte graphique à une machine virtuelle tournant sur Windows, mais les autres machines virtuelles ne verront même pas la carte graphique. Même l'hyperviseur n'a pas accès directement à ce matériel. L'affectation directe est très utile sur les serveurs, qui disposent souvent de plusieurs cartes réseaux et peuvent en assigner une à chaque machine virtuelle. Mais dans la plupart des cas, elle ne marche pas. De plus, sur les périphériques sans IO-MMU, elle ouvre la porte à des attaques DMA, où une machine virtuelle accède à la mémoire physique de la machine en configurant le contrôleur DMA de son périphérique assigné. L'affectation directe est certes limitée, mais elle se marie bien avec certaines de virtualisation matérielles, intégrées dans de nombreux périphériques. Il existe des périphériques qui sont capables de se virtualiser tout seuls, à savoir qu'ils peuvent se dédoubler en plusieurs '''périphériques virtuels'''. Par exemple, prenons une carte réseau avec cette propriété. Il n'y a qu'une seule carte réseau dans l'ordinateur, mais elle peut donner l'illusion qu'il y en a 8-16 d'installés dans l'ordinateur. Il faut alors faire la différence entre la carte réseau physique et les 8-16 cartes réseau virtuelles. L'idée est d'utiliser l'affectation directe, chaque machine virtuelle/OS ayant une carte réseau virtuelle d'affectée, avec affectation directe. [[File:Virtualisation matérielle des périphériques.png|centre|vignette|upright=2|Virtualisation matérielle des périphériques]] Pour les périphériques PCI-Express, le fait de se dupliquer en plusieurs périphériques virtuels est permis par la technologie '''''Single-root input/output virtualization''''', abrévié en SRIOV. Elle est beaucoup, utilisée sur les cartes réseaux, pour plusieurs raisons. Déjà, ce sont des périphériques beaucoup utilisés sur les serveurs, qui utilisent beaucoup la virtualisation. Dupliquer des cartes réseaux et utiliser l'affectation directe rend la configuration des serveurs bien plus simple. De plus, la plupart des cartes réseaux sont sous-utilisées, même par les serveurs. Une carte réseau est souvent utilisée à environ 10% de ses capacités par une VM unique, ce qui fait qu'utiliser 10 cartes réseaux virtuelles permet d'utiliser les capacités de la carte réseau à 100%. Il est possible de faire une analogie entre les processeurs multithreadés et les périphériques virtuels. Un processeur multithreadé est dupliqué en plusieurs processeurs virtuels, un périphérique virtualisé est dupliqué en plusieurs périphériques virtuels. L'implémentation des deux techniques est similaire sur le principe, mais les détails varient selon qu'on parle d'une carte réseau, d'une carte graphique, d'une carte son, etc. Pour gérer plusieurs périphériques virtuels, le périphérique physique contient plusieurs copies de ses registres de commande/données, plusieurs files de commandes, etc. De plus, le périphérique physique contient divers circuits d'arbitrage, qui gèrent comment le matériel est utilisé. Ils donnent accès à tour de rôle à chaque VM aux ressources non-dupliquées. [[File:Implémentation d'une carte réseau gérant plusieurs cartes réseaux virtuelles.png|centre|vignette|upright=2|Implémentation d'une carte réseau gérant plusieurs cartes réseaux virtuelles]] Dans le cas le plus simple, le matériel traite les commandes provenant des différentes VM dans l'ordre d'arrivée, une par une, il n'y a pas d'arbitrage pour éviter qu'une VM monopolise le matériel. Plus évolué, le matériel peut faire de l'affectation au tour par tour, en traitant chaque VM dans l'ordre durant un certain temps. Le matériel peut aussi utiliser des algorithmes d'ordonnancement/répartition plus complexes. Par exemple, les cartes graphiques modernes utilisent des algorithmes de répartition/ordonnancement accélérés en matériel, implémentés dans le GPU lui-même. ===La virtualisation des interruptions=== La gestion des interruptions matérielles peut aussi être accélérée en matériel, en complément des techniques de périphériques virtuels vues plus haut. Par exemple, il est possible de gérer des ''exitless interrupts'', qui ne passent pas du tout par l'hyperviseur. Mais cela demande d'utiliser l'affectation directe, en complément de l'usage de périphériques virtuels. Tout périphérique virtuel émet des interruptions distinctes des autres périphérique virtuel. Pour distinguer les interruptions provenant de cartes virtuelles de celles provenant de cartes physiques, on les désigne sous le terme d''''interruptions virtuelles'''. Une interruption virtuelle est destinée à une seule machine virtuelle : celle à laquelle est assignée la carte virtuelle. Les autres machines virtuelles ne reçoivent pas ces interruptions. Les interruptions virtuelles ne sont pas traitées par l'hyperviseur, seulement par l'OS de la machine virtuelle assignée. Une subtilité a lieu sur les processeurs à plusieurs cœurs. Il est possible d'assigner un cœur à chaque machine virtuelle, possiblement plusieurs. Par exemple, un processeur octo-coeur peut exécuter 8 machines virtuelles simultanément. Avec l'affectation directe ou à tour de rôle, l'interruption matérielle est donc destinée à une machine virtuelle, donc à un cœur. L'IRQ doit donc être redirigée vers un cœur bien précis et ne pas être envoyée aux autres. Les contrôleurs d'interruption modernes déterminent à quelles machines virtuelles sont destinées telle ou telle interruption, et peuvent leur envoyer directement, sans passer par l'hyperviseur. Grâce à cela, l'affectation directe à tour de rôle ont de bonnes performances. En plus de ce support des interruptions virtuelles, le contrôleur d'interruption peut aussi être virtualisé, à savoir être dupliqué en plusieurs '''contrôleurs d'interruption virtuels'''. Sur les systèmes à processeur x86, le contrôleur d'interruption virtualisé est l'APIC (''Advanced Programmable Interrupt Controller''). Diverses technologies de vAPIC, aussi dites d'APIC virtualisé, permettent à chaque machine virtuelle d'avoir une copie virtuelle de l'APIC. Pour ce faire, tous les registres de l'APIC sont dupliqués en autant d'exemplaires que d'APIC virtuels supportés. Il existe un équivalent sur les processeurs ARM, où le contrôleur d'interruption est nommé le ''Generic Interrupt Controller'' (GIC) et peut aussi être virtualisé. La virtualisation de l'APIC permet d'éviter d'avoir à passer par l'hyperviseur pour gérer les interruptions. Par exemple, quand un OS veut prévenir qu'il a fini de traiter une interruption, il doit communiquer avec le contrôleur d'interruption. Sans virtualisation du contrôleur d'interruption, cela demande de passer par l'intermédiaire de l'hyperviseur. Mais s'il est virtualisé, l'OS peut communiquer directement avec le contrôleur d'interruption virtuel qui lui est associé, sans que l'hyperviseur n'ait à faire quoique ce soit. De plus, la virtualisation du contrôleur d'interruption permet de gérer des interruptions inter-processeurs dites postées, qui ne font pas appel à l'hyperviseur, ainsi que des interruptions virtuelles émises par les IO-MMU. Sur les plateformes ARM, les ''timers'' sont aussi virtualisés. ==Annexe : le mode virtuel 8086 des premiers CPU Intel== Les premiers processeurs x86 étaient rudimentaires. Le 8086 utilisait une forme très simple de segmentation, sans aucune forme de protection mémoire, ni même de mémoire virtuelle, dont le but était d'adresser plus de 64 kibioctets de mémoire avec un processeur 16 bits. Sur le processeur 286, la segmentation s'améliora et ajouta un support complet de la mémoire virtuelle et de la protection mémoire. L'espace d'adressage en mode protégé est passé de 24 bits sur le CPU 286, à 32 bits sur le 386 et les CPU suivants. Pour bien faire la différence, la segmentation du 8086 fut appelée le mode réel, et la nouvelle forme de segmentation fut appelée le mode protégé. Les programmes conçus pour le mode réel ne pouvaient pas s'exécuter en mode protégé. En clair, tous les programmes conçus pour le 8086 devaient fonctionner en mode réel, qui était supporté sur le 286 et les processeurs suivant. Pour corriger les problèmes observés sur le 286, le 386 a ajouté un '''mode 8086 virtuel''', une technique de virtualisation qui permet à des programmes de s'exécuter en mode réel dans une machine virtuelle dédiée appelée la '''VM V86'''. Notez que nous utiliserons l'abréviation V86 pour parler du mode virtuel 8086, ainsi que de tout ce qui est lié à ce mode. ===La virtualisation du DOS et la mémoire étendue=== Utiliser le mode V86 demande d'avoir un programme 8086 à lancer, mais aussi d'utiliser un '''hyperviseur V86'''. L’hyperviseur V86 est un véritable hyperviseur, qui s’exécute en mode noyau, exécute des routines d'interruption, gère les exceptions matérielles, etc. Il réside en mémoire dans une zone non-adressable en mode réel, mais accessible en mode protégé, celui-ci permettant d'adresser plus de RAM. L'hyperviseur est forcément exécuté en mode protégé. Le système d'exploitation DOS s'exécutait en mode réel, ce qui fait qu'il pouvait être émulé par le mode V86. Il était ainsi possible de lancer une ou plusieurs sessions DOS à partir d'un système d'exploitation multitâche comme Windows. Windows. Beaucoup de personnes nées avant les années 2000 ont sans doute profité de cette possibilité pour lancer des applications DOS sous Windows. Les applications étaient en réalité lancées dans une machine virtuelle grâce au mode V86. Windows implémentait un hyperviseur V86 de type 2, à savoir que c'était un logiciel qui s'exécutait sur un OS sous-jacent, ici [[File:Hyperviseur.svg|centre|vignette|upright=2|Hyperviseur]] Les applications DOS dans une VM V86 ne peuvent pas adresser plus d'un mébioctet de mémoire. L'ordinateur peut cependant avoir plus de mémoire RAM, notamment pour gérer l'hyperviseur V86. Diverses techniques permettaient aux applications DOS d'utiliser la mémoire au-delà du mébioctet, appelée la '''mémoire étendue'''. Les logiciels DOS accédaient à la mémoire étendue en passant par un intermédiaire logiciel, qui lui-même communiquait avec l'hyperviseur V86. L'intermédiaire est appelé le ''Extended Memory Manager'' (EMM), et il est concrètement implémenté par un driver sur DOS (HIMEM.SYS). Les applications DOS ne pouvaient pas adresser la mémoire étendue, mais pouvaient échanger des données avec l'EMM. Les logiciels peuvent ainsi déplacer des données dans la mémoire étendue pour les garder au chaud, puis les rapatrier dans la mémoire conventionnelle quand ils en avaient besoin. L'intermédiaire ''Extended Memory Manager'' s'occupe d’échanger des données entre mémoire conventionnelle et mémoire étendue. Pour cela, il switche entre mode réel et protégé à la demande, quand il doit lire ou écrire en mémoire étendue. Il ne faut pas confondre mémoire étendue et ''expanded memory''. Pour rappel, l'''expanded memory'' est un système de commutation de banque, qui autorise un va-et-vient entre une carte d'extension et une page de 64 kibioctets mappé en mémoire haute. Elle fonctionne sans mode protégé, sans virtualisation, sans mode V86. La mémoire étendue ne gère pas de commutation de banque et demande que la RAM en plus soit installée dans l'ordinateur, pas sur une carte d'extension. Par contre, il est possible d'émuler l'''expanded memory'' sans carte d'extension, en utilisant la mémoire étendue. Quelques ''chipsets'' de carte mère intégraient des techniques cela. Une émulation logicielle était aussi possible. L'émulation logicielle se basait sur une réécriture de l'interruption 67h utilisée pour adresser la technologie ''expanded memory''. L'hyperviseur V86 pouvait s'en charger, il avait juste à réécrire son allocateur de mémoire pour gérer cette interruption et quelques autres détails. ===Le fonctionnement du mode virtuel 8086 de base=== En mode V86, la segmentation du mode protégé est désactivée, seule la segmentation du mode réel est utilisée. Il y a quelques subtilités liées à la ligne A20 du bus d'adresse, déjà abordées auparavant dans ce cours. Sur les CPU 286 et ultérieurs, le processeur peut adresser 1 mébioctet (2^20 adresses), plus 64 kibioctets qui ne sont pas adressables sur le 8086. Le tout permet donc d'adresser les adresses allant de 0 à 0x010FFEFH. Et ces adresses sont utilisées pour les programmes en mode réel. Les adresses au-delà de l'adresse 0x010FFEFH sont typiquement le lieu de résidence de l’hyperviseur en RAM. Par contre, la pagination peut être activée par l’hyperviseur, afin d’exécuter plusieurs logiciels en mode réel simultanément. La mémoire virtuelle par pagination peut aussi être utile si l'ordinateur a peu de mémoire RAM, pas assez pour faire tourner le logiciel : l'espace d'adressage vu par le logiciel est un espace virtuel de grande taille, ce qui permet de lancer le logiciel, au prix de performances dégradées. Enfin, la gestion des entrées-sorties mappées en mémoire est aussi simplifiée. De plus, cela permettait d'adresser plus de mémoire RAM grâce aux adresses plus longues du mode protégé. Il faut noter que dans le mode 8086 virtuel, les programmes peuvent utiliser les registres ajoutés sur le 386 et ultérieurs. Par exemple, le 8086 n'a que 4 registres de segment, alors que le 286 en a 6. Les programmes en mode 8086 virtuel peuvent utiliser les deux registres de segment supplémentaires. Il en est de même pour d'autres registres ajoutés par le 286, comme des registres de contrôle, des registres de debug, et quelques autres. Il en est de même pour les instructions ajoutées par le 286, le 386 et ultérieur, qui sont exécutables en mode virtuel 8086. Et elles sont nombreuses. La compatibilité n'était pas parfaite, il y avait quelques petites différences entre ce mode V86 et le mode réel du 8086, idem avec le mode réel du 286. Mais la grande majorité des applications n'avait aucun problème. Les problèmes étaient concentrés sur quelques instructions précises, notamment celles avec un préfixe LOCK. ===L'implémentation matérielle du mode virtuel 8086=== Le processeur est configuré en mode V86, le bit VM du registre d'état spécifique est mis à 1. Le processeur utilise ce bit lorsqu'une instruction utilise les registres de segments, afin de savoir comment calculer les adresses, le calcul n'étant pas le même en mode réel et en mode protégé. Quelques instructions machines dépendent aussi de la valeur de ce bit, mais cela est traité au décodage de l'instruction, et plus précisément dans le microcode. La plupart des instructions sont en double dans le microcode : il y a une version utilisant la segmentation en mode réel, une autre utilisant la pagination segmentée du mode protégé. Pour être plus précis, ces instructions sont coupées en deux dans le microcode : un microcode qui lit une opérande et dépend de la mémoire virtuelle, un microcode qui exécute le reste de l'instruction. La première partie n'est pas la même suivant qu'on est en mode réel ou protégé. Mais la seconde partie est la même dans les deux modes et est partagée entre les deux. En clair, les instructions ont deux points d'entrées : un pour le mode réel, un autre pour le mode protégé. Les deux lisent la table des segments/pages, font des tests de protection mémoire, puis branchent vers le microcode partagé. Pour faire la différence, un bit du processeur indique si le CPU est en mode réel ou protégé, et ce bit est utilisé pour adresser le microcode. Il est appelé le bit P et vaut 1 en mode protégé, 0 en mode réel. Le mode virtuel 8086 combine de bit PE avec le bit VM. Le bit utilisé pour adresser le microcode est calculé avec l'équation logique suivante : <math>\text{P} . \overline{\text{VM}}</math>. Ainsi, le bit qui adresse le microcode est mis à 0 quand le bit VM est à 1, ce qui adresse le microcode du mode réel. Les instructions liées au interruption étaient émulées en mode virtuel 8086. Par exemple, les instructions CTI et STI, qui activaient ou désactivaient les interruptions, n'étaient pas exécutées en mode virtuel 8086. Leur exécution entrainait la levée d'une exception matérielle, qui les émulait en matériel. Mais, il fallait un hyperviseur 8086 pour gérer la situation, notamment pour maintenir un registre d'interruption virtuel. ===Les ''Virtual-8086 mode extensions''=== A partir du processeur Pentium, les processeurs x86 ont introduit des optimisations du mode V86, afin de rendre la virtualisation plus rapide. L'ensemble de ces optimisations est regroupé sous le terme de '''''Virtual-8086 mode extensions''''', abrévié en VME. Les optimisations du VMA étaient, pour certaines, utiles au-delà de la virtualisation et étaient activables indépendamment du reste du VME. Le VME introduisait des optimisations quant au traitement des interruptions, à savoir la gestion des interruptions virtuelles. De plus, le VME modifie la gestion de l'''interrupt flag'' du registre d'état. Pour rappel, ce bit permet d'activer ou de désactiver les interruptions masquables. Modifier le bit ''interrupt flag'' permettait de désactiver les interruptions masquables ou au contraire de les activer. Il se trouve que ce bit était accesible par les programmes exécutés en mode réel, qui pouvaient en faire ce qu'ils voulaient. Le mode réel n'étant pas prévu pour la multi-programmation, ce n'était pas un problème. Mais en mode V86, toute modification de ce bit se répercute sur les autres VM en mode V86. Pour éviter les problèmes, le VME a ajouté de quoi virtualiser cet ''interrupt flag'', avec une copie par machine virtuelle V86. Chaque programme modifiait sa propre copie de l'''interrupt flag'' sans altérer celle des autres programmes exécutés en mode V86, et surtout sans déclencher une exception matérielle gérée par l'hyperviseur. Bien qu'elles aient été introduites sur les processeurs Pentium, elles n'ont réellement été rendues publiques qu'après la sortie des processeurs de microarchitecture P6. Avant d'être rendue publique, la documentation du VME était une annexe de la documentation officielle, la fameuse annexe H. Elle était mentionnée dans la documentation officielle, mais était indisponible au grand public, seules quelques entreprises sous NDA y avait accès. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les réseaux de neurones matériels | prevText=Les réseaux de neurones matériels | next=Le matériel réseau | nextText=Le matériel réseau }} </noinclude> 9yudwbd45b213end6b3dzgxbsawikow 772087 772086 2026-09-12T17:03:30Z Mewtow 31375 /* Les Virtual-8086 mode extensions */ 772087 wikitext text/x-wiki La virtualisation est l'ensemble des techniques qui permettent de faire tourner plusieurs systèmes d'exploitation en même temps. Le terme est polysémique, mais c'est la définition que nous allons utiliser pour ce qui nous intéresse. La virtualisation demande d'utiliser un logiciel dit '''hyperviseur''', qui permet de faire tourner plusieurs OS en même temps. Les hyperviseurs sont en quelque sorte situés sous le système d'exploitation. On peut les voir comme une sorte de sous-système d'exploitation, de système d'exploitation pour les systèmes d'exploitation. A ce propos, les OS virtualisés sont appelés des ''OS invités'', alors que l'hyperviseur est parfois appelé l'''OS hôte''. [[File:Diagramme ArchiHyperviseur.png|centre|vignette|upright=2|Différence entre système d'exploitation et hyperviseur.]] Les processeurs modernes intègrent des techniques pour accélérer la virtualisation. Les techniques en question sont assez variées, allant d'un niveau de privilège en plus des modes noyau/utilisateur à des modifications de la mémoire virtuelle, en passant à des modifications liées aux interruptions matérielles. Mais pour comprendre tout cela, il va falloir faire quelques explications sur la virtualisation elle-même. ==La virtualisation : généralités== Pour faire tourner plusieurs OS en même temps, l'hyperviseur recourt à de nombreux stratagèmes. Il doit partager le processeur, la RAM et les entrées-sorties entre plusieurs OS. Le partage de la RAM demande concrètement des modifications assez légères de la mémoire virtuelle, qu'on verra en temps voulu. Le partage du processeur est assez simple : les OS s'exécutent à tour de rôle sur le processeur, chacun pendant un temps défini, fixe. Une fois leur temps d'exécution passé, ils laissent la main à l'OS suivant. C'est l’hyperviseur qui s'occupe de tout cela, grâce à une interruption commandée à un ''timer''. Ce système de partage est une forme de '''multiplexage'''. A ce propos, il s'agit de la même solution que les OS utilisent pour faire tourner plusieurs programmes en même temps sur un processeur/cœur unique. La gestion des entrées-sorties demande d'utiliser des techniques d''''émulation''', plus complexes à expliquer. Un hyperviseur peut parfaitement simuler du matériel qui n'est pas installé sur l'ordinateur. Par exemple, il peut faire croire à un OS qu'une carte réseau obsolète, datant d'il y a 20 ans, est installée sur l'ordinateur, alors que ce n'est pas le cas. Les commandes envoyées par l'OS à cette carte réseau fictive sont en réalité traitées par une vraie carte réseau par l’hyperviseur. Pour cela, l’hyperviseur intercepte les commandes envoyées aux entrées-sorties, et les traduit en commandes compatibles avec les entrées-sorties réellement installées sur l'ordinateur. ===Les machines virtuelles=== L'exemple avec la carte réseau est un cas particulier, l'hyperviseur faisant beaucoup de choses dans le genre. L'hyperviseur peut faire croire à l'ordinateur qu'il a plus ou moins de RAM que ce qui est réellement installé, par exemple. L'hyperviseur implémente ce qu'on appelle des '''machines virtuelles'''. Il s'agit d'une sorte de faux matériel, simulé par un logiciel. Un logiciel qui s’exécute dans une machine virtuelle aura l'impression de s’exécuter sur un matériel et/ou un O.S différent du matériel sur lequel il est en train de s’exécuter. : Dans ce qui suit, nous parlerons de V.M (virtual machine), pour parler des machines virtuelles. [[File:VM-monitor-french.png|centre|vignette|upright=2|Machines virtuelles avec la virtualisation.]] Avec la virtualisation, plusieurs machines virtuelles sont gérées par l'hyperviseur, chacune étant réservée à un système d'exploitation. D'ailleurs, hyperviseurs sont parfois appelés des ''Virtual Machine Manager''. Nous utiliserons d'ailleurs l'abréviation VMM dans les schémas qui suivent. Il existe deux types d'hyperviseurs, qui sont nommés type 1 et type 2. Le premier type s'exécute directement sur le matériel, alors que le second est un logiciel qui s’exécute sur un OS normal. Pour ce qui nous concerne, la distinction n'est pas très importante. [[File:Ansatz der Systemvirtualisierung zur Schaffung virtueller Betriebsumgebungen.png|centre|vignette|upright=2.5|Comparaison des différentes techniques de virtualisation : sans virtualisation à gauche, virtualisation de type 1 au milieu, de type 2 à droite.]] La virtualisation est une des utilisations possibles, mais il y en a d'autres. La plus intéressante est celle des émulateurs. Ces derniers sont des logiciels qui permettent de simuler le fonctionnement d'anciens ordinateurs ou consoles de jeux. L'émulateur crée une machine virtuelle qui est réservée à un programme, à savoir le jeu à émuler. Il y a une différence de taille entre un émulateur et un hyperviseur. L'émulation émule une machine virtuelle totalement différente, alors que la virtualisation doit émuler les entrées-sorties mais pas le processeur. Avec un hyperviseur, le système d'exploitation s'exécute sur le processeur lui-même. Le code de l'OS est compatible avec le processeur de la machine, dans le sens où il est compilé pour le jeu d'instruction du processeur de la machine réelle. Les instructions de l'OS s'exécutent directement. Par contre, un émulateur exécute un jeu qui est programmé pour une machine dont le processeur est totalement différent. Le jeu d'instruction de la machine virtuelle et celui du vrai processeur n'est pas le même. L'émulation implique donc de traduire les instructions à exécuter dans la V.M par des instructions exécutables par le processeur. Ce n'est pas le cas avec la virtualisation, le jeu d'instruction étant le même. ===La méthode ''trap and emulate'' basique=== Pour être considéré comme un logiciel de virtualisation, un logiciel doit remplir trois critères : * L'équivalence : l'O.S virtualisé et les applications qui s’exécutent doivent se comporter comme s'ils étaient exécutés sur le matériel de base, sans virtualisation. * Le contrôle des ressources : tout accès au matériel par l'O.S virtualisé doit être intercepté par la machine virtuelle et intégralement pris en charge par l'hyperviseur. * L'efficacité : La grande partie des instructions machines doit s’exécuter directement sur le processeur, afin de garder des performances correctes. Ce critère n'est pas respecté par les émulateurs matériels, qui doivent simuler le jeu d'instruction du processeur émulé. Remplir ces trois critères est possible sous certaines conditions, établies par les théorèmes de Popek et Goldberg. Ces théorèmes se basent sur des hypothèses précises. De fait, la portée de ces théorèmes est limitée, notamment pour le critère de performance. Ils partent notamment du principe que l'ordinateur utilise la segmentation pour la mémoire virtuelle, et non la pagination. Il part aussi du principe que les interruptions ont un cout assez faible, qu'elles sont assez rares. Mais laissons ces détails de côté, le cœur de ces théorèmes repose sur une hypothèse simple : la présence de différents types d'instructions machines. Pour rappel, il faut distinguer les instructions privilégiées de celles qui ne le sont pas. Les instructions privilégiées ne peuvent s'exécuter que en mode noyau, les programmes en mode utilisateur ne peuvent pas les exécuter. Parmi les instructions privilégiées on peut distinguer un sous-groupe appelé les '''instructions systèmes'''. Le premier type regroupe les '''instructions d'accès aux entrées-sorties''', aussi appelées instructions sensibles à la configuration. Le second type est celui des '''instructions de configuration du processeur''', qui agissent sur les registres de contrôle du processeur, aussi appelées instructions sensibles au comportement. Elles servent notamment à gérer la mémoire virtuelle, mais pas que. La théorie de Popek et Goldberg dit qu'il est possible de virtualiser un O.S à une condition : que les instructions systèmes soient toutes des instructions privilégiées, c’est-à-dire exécutables seulement en mode noyau. Virtualiser un O.S demande simplement de le démarrer en mode utilisateur. Quand l'O.S fait un accès au matériel, il le fait via une instruction privilégiée. Vu que l'OS est en mode utilisateur, cela déclenche une exception matérielle, qui émule l'instruction privilégiée. L'hyperviseur n'est ni plus ni moins qu'un ensemble de routines d'interruptions, chaque routine simulant le fonctionnement du matériel émulé. Par exemple, un accès au disque dur sera émulé par une routine d'interruption, qui utilisera les appels systèmes fournit par l'OS pour accéder au disque dur réellement présent dans l'ordinateur. Cette méthode est souvent appelée la méthode ''trap and emulate''. [[File:Virtualisation avec la méthode trap-and-emulate.png|centre|vignette|upright=2.0|Virtualisation avec la méthode trap-and-emulate]] La méthode ''trap and emulate'' ne fonctionne que si certaines contraintes sont respectées. Un premier problème est que beaucoup de jeux d'instructions anciens ne respectent pas la règle "les instructions systèmes sont toutes privilégiées". Par exemple, ce n'est pas le cas sur les processeurs x86 32 bits. Sur ces CPU, les instructions qui manipulent les drapeaux d'interruption ne sont pas toutes des instructions privilégiées, idem pour les instructions qui manipulent les registres de segmentation, celles liées aux ''call gates'', etc. A cause de cela, il est impossible d'utiliser la méthode du ''trap and emulate''. La seule solution qui ne requiert pas de techniques matérielles est de traduire à la volée les instructions systèmes problématiques en appels systèmes équivalents, grâce à des techniques de '''réécriture de code'''. Enfin, certaines instructions dites '''sensibles au contexte''' ont un comportement différent entre le mode noyau et le mode utilisateur. En présence de telles instructions, la méthode ''trap and emulate'' ne fonctionne tout simplement pas. Grâce à ces instructions, le système d’exploitation ou un programme applicatif peut savoir s'il s'exécute en mode utilisateur ou noyau, ou hyperviseur, ou autre. La virtualisation impose l'usage de la mémoire virtuelle, sans quoi plusieurs OS ne peuvent pas se partager la même mémoire physique. De plus, il ne faut pas que la mémoire physique, non-virtuelle, puisse être adressée directement. Et cette contrainte est violée, par exemple sur les architectures MIPS qui exposent des portions de la mémoire physique dans certaines zones fixées à l'avance de la mémoire virtuelle. L'OS est compilé pour utiliser ces zones de mémoire pour accéder aux entrées-sorties mappées en mémoire, entre autres. En théorie, on peut passer outre le problème en marquant ces zones de mémoire comme inaccessibles, toute lecture/écriture à ces adresses déclenche alors une exception traitée par l'hyperviseur. Mais le cout en performance est alors trop important. Quelques hyperviseurs ont été conçus pour les architectures MIPS, dont le projet de recherche DISCO, mais ils ne fonctionnaient qu'avec des systèmes d'exploitation recompilés, de manière à passer outre ce problème. Les OS étaient recompilés afin de ne pas utiliser les zones mémoire problématiques. De plus, les OS étaient modifiés pour améliorer les performances en virtualisation. Les OS disposaient notamment d'appels systèmes spéciaux, appelés des ''hypercalls'', qui exécutaient des routines de l'hyperviseur directement. Les appels systèmes faisant appel à des instructions systèmes étaient ainsi remplacés par des appels système appelant directement l'hyperviseur. Le fait de modifier l'OS pour qu'il communique avec un hyperviseur, dont il a connaissance de l'existence, s'appelle la '''para-virtualisation'''. [[File:Virtualization - Para vs Full.png|centre|vignette|upright=2.5|Virtualization - Para vs Full]] ==La virtualisation du processeur== La virtualisation demande de partager le matériel entre plusieurs machines virtuelles. Précisément, il faut partager : le processeur, la mémoire RAM, les entrées-sorties. Les trois sont gérés différemment. Par exemple, la virtualisation des entrées-sorties est gérée par l’hyperviseur, parfois aidé par le ''chipset'' de la carte mère. Virtualiser des entrées-sorties demande d'émuler du matériel inexistant, mais aussi de dupliquer des entrées-sorties de manière à ce le matériel existe dans chaque VM. Partager la mémoire RAM entre plusieurs VM est assez simple avec la mémoire virtuelle, bien que cela demande quelques adaptations. Maintenant, voyons ce qu'il en est pour le processeur. ===Le niveau de privilège hyperviseur=== Sur certains CPU modernes, il existe un niveau de privilège appelé le '''niveau de privilège hyperviseur''' qui est utilisé pour les techniques de virtualisation. Le niveau de privilège hyperviseur est réservé à l’hyperviseur et il a des droits d'accès spécifiques. Il n'est cependant pas toujours activé. Par exemple, si aucun hyperviseur n'est installé sur la machine, le processeur dispose seulement des niveaux de privilège noyau et utilisateur, le mode noyau n'ayant alors aucune limitation précise. Mais quand le niveau de privilège hyperviseur est activé, une partie des manipulations est bloquée en mode noyau et n'est possible qu'en mode hyperviseur. Le fonctionnement se base sur la différence entre instruction privilégiée et instruction système. Les instructions privilégiées peuvent s'exécuter en niveau noyau, alors que les instructions systèmes ne peuvent s'exécuter qu'en niveau hyperviseur. L'idée est que quand le noyau d'un OS exécute une instruction système, une exception matérielle est levée. L'exception bascule en mode hyperviseur et laisse la main à une routine de l'hyperviseur. L'hyperviseur fait alors des manipulations précise pour que l'instruction système donne le même résultat que si elle avait été exécutée par l'ordinateur simulé par la machine virtuelle. [[File:Virtualisation avec un mode hyperviseur.png|centre|vignette|upright=2|Virtualisation avec un mode hyperviseur.]] Il est ainsi possible d'émuler des entrées-sorties avec un cout en performance assez léger. Précisément, ce mode hyperviseur améliore les performances de la méthode du ''trap-and-emulate''. La méthode ''trap-and-emulate'' basique exécute une exception matérielle pour toute instruction privilégiée, qu'elle soit une instruction système ou non. Mais avec le niveau de privilège hyperviseur, seules les instructions systèmes déclenchent une exception, pas les instructions privilégiées non-système. Les performances sont donc un peu meilleures, pour un résultat identique. Après tout, les entrées-sorties et la configuration du processeur suffisent à émuler une machine virtuelle, les autres instructions noyau ne le sont pas. Sur les processeurs ARM, il est possible de configurer quelles instructions sont détournées vers le mode hyperviseur et celles qui restent en mode noyau. En clair, on peut configurer quelles sont les instructions systèmes et celles qui sont simplement privilégiées. Et il en est de même pour les interruptions : on peut configurer si elles exécutent la routine de l'OS normal en mode noyau, ou si elles déclenchent une exception matérielle qui redirige vers une routine de l’hyperviseur. En l'absence d'hyperviseur, toutes les interruptions redirigent vers la routine de l'OS normale, vers le mode noyau. Il faut noter que le mode hyperviseur n'est compatible qu'avec les hyperviseurs de type 1, à savoir ceux qui s'exécutent directement sur le matériel. Par contre, elle n'est pas compatible avec les hyperviseurs de type 2, qui sont des logiciels qui s'exécutent comme tout autre logiciel, au-dessus d'un système d'exploitation sous-jacent. ===L'Intel VT-X et l'AMD-V=== Les processeurs ARM de version v8 et plus incorporent un mode hyperviseur, mais pas les processeurs x86. À la place, ils incorporent des technologies alternatives nommées Intel VT-X ou l'AMD-V. Les deux ajoutent de nouvelles instructions pour gérer l'entrée et la sortie d'un mode réservé à l’hyperviseur. Mais ce mode réservé à l'hyperviseur n'est pas un niveau de privilège comme l'est le mode hyperviseur. L'Intel VT-X et l'AMD-V dupliquent le processeur en deux modes de fonctionnement : un mode racine pour l'hyperviseur, un mode non-racine pour l'OS et les applications. Fait important : les niveaux de privilège sont dupliqués eux aussi ! Par exemple, il y a un mode noyau racine et un mode noyau non-racine, idem pour le mode utilisateur, idem pour le mode système (pour le BIOS/UEFI). De même, les modes réel, protégé, v8086 ou autres, sont eux aussi dupliqués en un exemplaire racine et un exemplaire non-racine. L'avantage est que les systèmes d'exploitation virtualisés s'exécutent bel et bien en mode noyau natif, l'hyperviseur a à sa disposition un mode noyau séparé. D'ailleurs, les deux modes ont des registres d'interruption différents. Le mode racine et le mode non-racine ont chacun leurs espaces d'adressage séparés de 64 bit, avec leur propre table des pages. Et cela demande des adaptations au niveau de la TLB. La transition entre mode racine et non-racine se fait lorsque le processeur exécute une instruction système ou lors de certaines interruptions. Au minimum, toute exécution d'une instruction système fait commuter le processeur mode racine et lance l'exécution des routines de l’hyperviseur adéquates. Les interruptions matérielles et exceptions font aussi passer le CPU en mode racine, afin que l’hyperviseur puisse gérer le matériel. De plus, afin de gérer le partage de la mémoire entre OS, certains défauts de page déclenchent l'entrée en mode racine. Les ''hypercalls'' de la para-virtualisation sont supportés grâce à aux instructions ''vmcall'' et ''vmresume'' qui permettent respectivement d'appeler une routine de l’hyperviseur ou d'en sortir. La transition demande de sauvegarder/restaurer les registres du processeur, comme avec les interruptions. Mais cette sauvegarde est réalisée automatiquement par le processeur, elle n'est pas faite par les routines de l'hyperviseur. L’implémentation de cette sauvegarde/restauration se fait surtout via le microcode du processeur, car elle demande beaucoup d'étapes. Elle est en conséquence très lente. Le processeur sauvegarde l'état de chaque machine virtuelle en mémoire RAM, dans une structure de données appelée la ''Virtual Machine Control Structure'' (VMCS). Elle mémorise surtout les registres du processeur à l'instant t. Lorsque le processeur démarre l'exécution d'une VM sur le processeur, cette VMCS est recopiée dans les registres pour rétablir la VM à l'endroit où elle s'était arrêtée. Lorsque la VM est interrompue et doit laisser sa place à l'hyperviseur, les registres et l'état du processeur sont sauvegardés dans la VMCS adéquate. ==La virtualisation de la mémoire : mémoire virtuelle et MMU== Avec la virtualisation, les différentes machines virtuelles, les différents OS doivent se partager la mémoire physique, en plus d'être isolés les uns des autres. L'idée est d'utiliser la mémoire virtuelle pour cela. L'espace d'adressage physique vu par chaque OS est en réalité un espace d'adressage fictif, qui ne correspond pas à la mémoire physique. Les adresses physiques manipulées par l'OS sont en réalité des adresses intermédiaires entre les adresses physiques liées à la RAM, et les adresses virtuelles vues par les processus. Pour les distinguer, nous parlerons d'adresses physiques de l'hôte pour parler des adresses de la RAM, et des adresses physiques invitées pour parler des adresses manipulées par les OS virtualisés. Sans accélération matérielle, la traduction des adresses physiques invitées en adresses hôte est réalisée par une seconde table des pages, appelée la ''shadow page table'', ce qui donnerait '''table des pages cachée''' en français. La table des pages cachée est prise en charge par l'hyperviseur. Toute modification de la table des pages cachée est réalisée par l'hyperviseur, les OS ne savent même pas qu'elle existe. [[File:Shadowpagetables.png|centre|vignette|upright=2|Table des pages cachée.]] ===La MMU et la virtualisation : les tables des pages emboitées=== Une autre solution demande un support matériel des tables des pages emboitées, à savoir qu'il y a un arbre de table des pages, chaque consultation de la première table des pages renvoie vers une seconde, qui renvoie vers une troisième, et ainsi de suite jusqu'à tomber sur la table des pages finale qui renvoie l'adresse physique réelle. L'idée est l'utiliser une seule table des pages, mais d'ajouter un ou deux niveaux supplémentaires. Pour l'exemple, prenons le cas des processeurs x86. Sans virtualisation, l'OS utilise une table des pages de 4 niveaux. Avec, la table des pages a un niveau en plus, qui sont ajoutés à la fin de la dernière table des pages normale. Les niveaux ajoutés s'occupent de la traduction des adresses physiques invitées en adresses physiques hôte. On parle alors de '''table des pages étendues''' pour désigner ce nouveau format de table des pages conçu pour la virtualisation. Il faut que le processeur soit modifié de manière à parcourir automatiquement les niveaux ajoutés, ce qui demande quelques modifications de la TLB et du ''page table walker''. Les modifications en question ne font que modifier le format normal de la table des pages, et sont donc assez triviales. Elles ont été implémentées sur les processeurs AMD et Intel. AMD a introduit les tables des pages étendues sur ses processeurs Opteron, destinés aux serveurs, avec sa technologie ''Rapid Virtualization Indexing''. Intel, quant à lui, a introduit la technologie sur les processeurs i3, i5 et i7, sous le nom ''Extended Page Tables''. Les processeurs ARM ne sont pas en reste avec la technologie ''Stage-2 page-tables'', qui est utilisée en mode hyperviseur. ===La virtualisation de l'IO-MMU=== Si la MMU du processeur est modifiée pour gérer des tables des pages étendues, il en est de même pour les IO-MMU des périphériques et contrôleurs DMA.Les périphériques doivent idéalement intégrer une IO-MMU pour faciliter la virtualisation. La raison est globalement la même que pour le partage de la mémoire. Les pilotes de périphériques utilisent des adresses qui sont des adresses physiques sans virtualisation, mais qui deviennent des adresses virtuelles avec. Quand le pilote de périphérique configure un contrôleur DMA, pour transférer des données de la RAM vers un périphérique, il utilisera des adresses virtuelles qu'il croit physique pour adresser les données en RAM. Pour éviter tout problème, le contrôleur DMA doit traduire les adresses qu'il reçoit en adresses physiques. Pour cela, il y a besoin d'une IO-MMU intégrée au contrôleur DMA, qui est configurée par l'hyperviseur. Toute IO-MMU a sa propre table des pages et l'hyperviseur configure les table des pages pour chaque périphérique. Ainsi, le pilote de périphérique manipule des adresses virtuelles, qui sont traduites en adresses physiques directement par le matériel lui-même, sans intervention logicielle. Pour gérer la virtualisation, on fait la même chose qu'avec une table des pages emboitée habituelle : on l'étend en ajoutant des niveaux. L'IO-MMU peut fonctionner dans un mode normal, sans virtualisation, où les adresses virtuelles reçues du ''driver'' sont traduite avec une table des pages normale, non-emboitée. Mais elle a aussi un mode virtualisation qui utilise des tables de pages étendues. ==La virtualisation des entrées-sorties== Virtualiser les entrées-sorties est simple sur le principe. Un OS communique avec le matériel soit via des ports IO, soit avec des entrées-sorties mappées en mémoire. Le périphérique répond avec des interruptions ou via des transferts DMA. Virtualiser les périphériques demande alors d'émuler les ports IO, les entrées-sorties mappées en mémoire, le DMA et les interruptions. ===La virtualisation logicielle des interruptions=== Émuler les ports IO est assez simple, vu que l'OS lit ou écrit dedans grâce à des instructions IO spécialisées. Vu que ce sont des instructions système, la méthode ''trap and emulate'' suffit. Pour les entrées-sorties mappées en mémoire, l'hyperviseur a juste à marquer les adresses mémoires concernées comme étant réservées/non-allouées/autre. Tout accès à ces adresses lèvera une exception matérielle d'accès mémoire interdit, que l’hyperviseur intercepte et gère via ''trap and emulate''. L'émulation du DMA est triviale, vu que l'hyperviseur a accès direct à celui-ci, sans compter que l'usage d'une IO-MMU résout beaucoup de problèmes. La gestion des interruptions matérielles, les fameuses IRQ, est quant à elle plus complexe. Les interruptions matérielles ne sont pas à prendre en compte pour toutes les machines virtuelles. Par exemple, si une machine virtuelle n'a pas de carte graphique, pas besoin qu'elle prenne en compte les interruptions provenant de la carte graphique. La gestion des interruptions matérielles n'est pas la même si l'ordinateur grée des cartes virtuelles ou s'il se débrouille avec une carte physique unique. Lors d'une interruption matérielle, le processeur exécute la routine adéquate de l'hyperviseur. Celle-ci enregistre qu'il y a eu une IRQ et fait quelques traitements préliminaires. Ensuite, elle laisse la main au système d'exploitation concerné, qui exécute alors sa routine d'interruption. Une fois la routine de l'OS terminée, l'OS dit au contrôleur d'interruption qu'il a terminé son travail. Mais cela demande d'interagir avec le contrôleur d'interruption, ce qui déclenche une exception qui appelle l'hyperviseur. L'hyperviseur signale au contrôleur d'interruption que l'interruption matérielle a été traitée. Il rend alors définitivement la main au système d'exploitation. Le processus complet demande donc plusieurs changements entre mode hyperviseur et OS, ce qui est assez couteux en performances. Vu que le matériel simulé varie d'une machine virtuelle à l'autre, chaque machine virtuelle a son propre vecteur d'interruption. Par exemple, si une machine virtuelle n'a pas de carte graphique son vecteur d'interruption ne pointera pas vers les routines d'interruption d'un quelconque GPU. L'hyperviseur gère les différents vecteurs d'interruption de chaque VM et traduit les interruptions reçues en interruptions destinées aux VM/OS. Si la méthode ''trap and emulate'' fonctionne, ses performances ne sont cependant pas forcément au rendez-vous. Tous les matériels ne se prêtent pas tous bien à la virtualisation, surtout les périphériques anciens. Pour éliminer une partie de ces problèmes, il existe différentes techniques, accélérées en matériel ou non. Elles permettent aux machines virtuelles de communiquer directement avec les périphériques, sans passer par l'hyperviseur. ===La virtualisation des périphériques avec l'affectation directe=== Virtualiser les entrées-sorties avec de bonnes performances est plus complexe. En pratique, cela demande une intervention du matériel. Le ''chipset'' de la carte mère, les différents contrôleurs d'interruption et bien d'autres circuits doivent être modifiés. Diverses techniques permettent de faciliter le partage des entrées-sorties entre machines virtuelles. La première est l''''affectation directe''', qui alloue un périphérique à une machine virtuelle et pas aux autres. Par exemple, il est possible d'assigner la carte graphique à une machine virtuelle tournant sur Windows, mais les autres machines virtuelles ne verront même pas la carte graphique. Même l'hyperviseur n'a pas accès directement à ce matériel. L'affectation directe est très utile sur les serveurs, qui disposent souvent de plusieurs cartes réseaux et peuvent en assigner une à chaque machine virtuelle. Mais dans la plupart des cas, elle ne marche pas. De plus, sur les périphériques sans IO-MMU, elle ouvre la porte à des attaques DMA, où une machine virtuelle accède à la mémoire physique de la machine en configurant le contrôleur DMA de son périphérique assigné. L'affectation directe est certes limitée, mais elle se marie bien avec certaines de virtualisation matérielles, intégrées dans de nombreux périphériques. Il existe des périphériques qui sont capables de se virtualiser tout seuls, à savoir qu'ils peuvent se dédoubler en plusieurs '''périphériques virtuels'''. Par exemple, prenons une carte réseau avec cette propriété. Il n'y a qu'une seule carte réseau dans l'ordinateur, mais elle peut donner l'illusion qu'il y en a 8-16 d'installés dans l'ordinateur. Il faut alors faire la différence entre la carte réseau physique et les 8-16 cartes réseau virtuelles. L'idée est d'utiliser l'affectation directe, chaque machine virtuelle/OS ayant une carte réseau virtuelle d'affectée, avec affectation directe. [[File:Virtualisation matérielle des périphériques.png|centre|vignette|upright=2|Virtualisation matérielle des périphériques]] Pour les périphériques PCI-Express, le fait de se dupliquer en plusieurs périphériques virtuels est permis par la technologie '''''Single-root input/output virtualization''''', abrévié en SRIOV. Elle est beaucoup, utilisée sur les cartes réseaux, pour plusieurs raisons. Déjà, ce sont des périphériques beaucoup utilisés sur les serveurs, qui utilisent beaucoup la virtualisation. Dupliquer des cartes réseaux et utiliser l'affectation directe rend la configuration des serveurs bien plus simple. De plus, la plupart des cartes réseaux sont sous-utilisées, même par les serveurs. Une carte réseau est souvent utilisée à environ 10% de ses capacités par une VM unique, ce qui fait qu'utiliser 10 cartes réseaux virtuelles permet d'utiliser les capacités de la carte réseau à 100%. Il est possible de faire une analogie entre les processeurs multithreadés et les périphériques virtuels. Un processeur multithreadé est dupliqué en plusieurs processeurs virtuels, un périphérique virtualisé est dupliqué en plusieurs périphériques virtuels. L'implémentation des deux techniques est similaire sur le principe, mais les détails varient selon qu'on parle d'une carte réseau, d'une carte graphique, d'une carte son, etc. Pour gérer plusieurs périphériques virtuels, le périphérique physique contient plusieurs copies de ses registres de commande/données, plusieurs files de commandes, etc. De plus, le périphérique physique contient divers circuits d'arbitrage, qui gèrent comment le matériel est utilisé. Ils donnent accès à tour de rôle à chaque VM aux ressources non-dupliquées. [[File:Implémentation d'une carte réseau gérant plusieurs cartes réseaux virtuelles.png|centre|vignette|upright=2|Implémentation d'une carte réseau gérant plusieurs cartes réseaux virtuelles]] Dans le cas le plus simple, le matériel traite les commandes provenant des différentes VM dans l'ordre d'arrivée, une par une, il n'y a pas d'arbitrage pour éviter qu'une VM monopolise le matériel. Plus évolué, le matériel peut faire de l'affectation au tour par tour, en traitant chaque VM dans l'ordre durant un certain temps. Le matériel peut aussi utiliser des algorithmes d'ordonnancement/répartition plus complexes. Par exemple, les cartes graphiques modernes utilisent des algorithmes de répartition/ordonnancement accélérés en matériel, implémentés dans le GPU lui-même. ===La virtualisation des interruptions=== La gestion des interruptions matérielles peut aussi être accélérée en matériel, en complément des techniques de périphériques virtuels vues plus haut. Par exemple, il est possible de gérer des ''exitless interrupts'', qui ne passent pas du tout par l'hyperviseur. Mais cela demande d'utiliser l'affectation directe, en complément de l'usage de périphériques virtuels. Tout périphérique virtuel émet des interruptions distinctes des autres périphérique virtuel. Pour distinguer les interruptions provenant de cartes virtuelles de celles provenant de cartes physiques, on les désigne sous le terme d''''interruptions virtuelles'''. Une interruption virtuelle est destinée à une seule machine virtuelle : celle à laquelle est assignée la carte virtuelle. Les autres machines virtuelles ne reçoivent pas ces interruptions. Les interruptions virtuelles ne sont pas traitées par l'hyperviseur, seulement par l'OS de la machine virtuelle assignée. Une subtilité a lieu sur les processeurs à plusieurs cœurs. Il est possible d'assigner un cœur à chaque machine virtuelle, possiblement plusieurs. Par exemple, un processeur octo-coeur peut exécuter 8 machines virtuelles simultanément. Avec l'affectation directe ou à tour de rôle, l'interruption matérielle est donc destinée à une machine virtuelle, donc à un cœur. L'IRQ doit donc être redirigée vers un cœur bien précis et ne pas être envoyée aux autres. Les contrôleurs d'interruption modernes déterminent à quelles machines virtuelles sont destinées telle ou telle interruption, et peuvent leur envoyer directement, sans passer par l'hyperviseur. Grâce à cela, l'affectation directe à tour de rôle ont de bonnes performances. En plus de ce support des interruptions virtuelles, le contrôleur d'interruption peut aussi être virtualisé, à savoir être dupliqué en plusieurs '''contrôleurs d'interruption virtuels'''. Sur les systèmes à processeur x86, le contrôleur d'interruption virtualisé est l'APIC (''Advanced Programmable Interrupt Controller''). Diverses technologies de vAPIC, aussi dites d'APIC virtualisé, permettent à chaque machine virtuelle d'avoir une copie virtuelle de l'APIC. Pour ce faire, tous les registres de l'APIC sont dupliqués en autant d'exemplaires que d'APIC virtuels supportés. Il existe un équivalent sur les processeurs ARM, où le contrôleur d'interruption est nommé le ''Generic Interrupt Controller'' (GIC) et peut aussi être virtualisé. La virtualisation de l'APIC permet d'éviter d'avoir à passer par l'hyperviseur pour gérer les interruptions. Par exemple, quand un OS veut prévenir qu'il a fini de traiter une interruption, il doit communiquer avec le contrôleur d'interruption. Sans virtualisation du contrôleur d'interruption, cela demande de passer par l'intermédiaire de l'hyperviseur. Mais s'il est virtualisé, l'OS peut communiquer directement avec le contrôleur d'interruption virtuel qui lui est associé, sans que l'hyperviseur n'ait à faire quoique ce soit. De plus, la virtualisation du contrôleur d'interruption permet de gérer des interruptions inter-processeurs dites postées, qui ne font pas appel à l'hyperviseur, ainsi que des interruptions virtuelles émises par les IO-MMU. Sur les plateformes ARM, les ''timers'' sont aussi virtualisés. ==Annexe : le mode virtuel 8086 des premiers CPU Intel== Les premiers processeurs x86 étaient rudimentaires. Le 8086 utilisait une forme très simple de segmentation, sans aucune forme de protection mémoire, ni même de mémoire virtuelle, dont le but était d'adresser plus de 64 kibioctets de mémoire avec un processeur 16 bits. Sur le processeur 286, la segmentation s'améliora et ajouta un support complet de la mémoire virtuelle et de la protection mémoire. L'espace d'adressage en mode protégé est passé de 24 bits sur le CPU 286, à 32 bits sur le 386 et les CPU suivants. Pour bien faire la différence, la segmentation du 8086 fut appelée le mode réel, et la nouvelle forme de segmentation fut appelée le mode protégé. Les programmes conçus pour le mode réel ne pouvaient pas s'exécuter en mode protégé. En clair, tous les programmes conçus pour le 8086 devaient fonctionner en mode réel, qui était supporté sur le 286 et les processeurs suivant. Pour corriger les problèmes observés sur le 286, le 386 a ajouté un '''mode 8086 virtuel''', une technique de virtualisation qui permet à des programmes de s'exécuter en mode réel dans une machine virtuelle dédiée appelée la '''VM V86'''. Notez que nous utiliserons l'abréviation V86 pour parler du mode virtuel 8086, ainsi que de tout ce qui est lié à ce mode. ===La virtualisation du DOS et la mémoire étendue=== Utiliser le mode V86 demande d'avoir un programme 8086 à lancer, mais aussi d'utiliser un '''hyperviseur V86'''. L’hyperviseur V86 est un véritable hyperviseur, qui s’exécute en mode noyau, exécute des routines d'interruption, gère les exceptions matérielles, etc. Il réside en mémoire dans une zone non-adressable en mode réel, mais accessible en mode protégé, celui-ci permettant d'adresser plus de RAM. L'hyperviseur est forcément exécuté en mode protégé. Le système d'exploitation DOS s'exécutait en mode réel, ce qui fait qu'il pouvait être émulé par le mode V86. Il était ainsi possible de lancer une ou plusieurs sessions DOS à partir d'un système d'exploitation multitâche comme Windows. Windows. Beaucoup de personnes nées avant les années 2000 ont sans doute profité de cette possibilité pour lancer des applications DOS sous Windows. Les applications étaient en réalité lancées dans une machine virtuelle grâce au mode V86. Windows implémentait un hyperviseur V86 de type 2, à savoir que c'était un logiciel qui s'exécutait sur un OS sous-jacent, ici [[File:Hyperviseur.svg|centre|vignette|upright=2|Hyperviseur]] Les applications DOS dans une VM V86 ne peuvent pas adresser plus d'un mébioctet de mémoire. L'ordinateur peut cependant avoir plus de mémoire RAM, notamment pour gérer l'hyperviseur V86. Diverses techniques permettaient aux applications DOS d'utiliser la mémoire au-delà du mébioctet, appelée la '''mémoire étendue'''. Les logiciels DOS accédaient à la mémoire étendue en passant par un intermédiaire logiciel, qui lui-même communiquait avec l'hyperviseur V86. L'intermédiaire est appelé le ''Extended Memory Manager'' (EMM), et il est concrètement implémenté par un driver sur DOS (HIMEM.SYS). Les applications DOS ne pouvaient pas adresser la mémoire étendue, mais pouvaient échanger des données avec l'EMM. Les logiciels peuvent ainsi déplacer des données dans la mémoire étendue pour les garder au chaud, puis les rapatrier dans la mémoire conventionnelle quand ils en avaient besoin. L'intermédiaire ''Extended Memory Manager'' s'occupe d’échanger des données entre mémoire conventionnelle et mémoire étendue. Pour cela, il switche entre mode réel et protégé à la demande, quand il doit lire ou écrire en mémoire étendue. Il ne faut pas confondre mémoire étendue et ''expanded memory''. Pour rappel, l'''expanded memory'' est un système de commutation de banque, qui autorise un va-et-vient entre une carte d'extension et une page de 64 kibioctets mappé en mémoire haute. Elle fonctionne sans mode protégé, sans virtualisation, sans mode V86. La mémoire étendue ne gère pas de commutation de banque et demande que la RAM en plus soit installée dans l'ordinateur, pas sur une carte d'extension. Par contre, il est possible d'émuler l'''expanded memory'' sans carte d'extension, en utilisant la mémoire étendue. Quelques ''chipsets'' de carte mère intégraient des techniques cela. Une émulation logicielle était aussi possible. L'émulation logicielle se basait sur une réécriture de l'interruption 67h utilisée pour adresser la technologie ''expanded memory''. L'hyperviseur V86 pouvait s'en charger, il avait juste à réécrire son allocateur de mémoire pour gérer cette interruption et quelques autres détails. ===Le fonctionnement du mode virtuel 8086 de base=== En mode V86, la segmentation du mode protégé est désactivée, seule la segmentation du mode réel est utilisée. Il y a quelques subtilités liées à la ligne A20 du bus d'adresse, déjà abordées auparavant dans ce cours. Sur les CPU 286 et ultérieurs, le processeur peut adresser 1 mébioctet (2^20 adresses), plus 64 kibioctets qui ne sont pas adressables sur le 8086. Le tout permet donc d'adresser les adresses allant de 0 à 0x010FFEFH. Et ces adresses sont utilisées pour les programmes en mode réel. Les adresses au-delà de l'adresse 0x010FFEFH sont typiquement le lieu de résidence de l’hyperviseur en RAM. Par contre, la pagination peut être activée par l’hyperviseur, afin d’exécuter plusieurs logiciels en mode réel simultanément. La mémoire virtuelle par pagination peut aussi être utile si l'ordinateur a peu de mémoire RAM, pas assez pour faire tourner le logiciel : l'espace d'adressage vu par le logiciel est un espace virtuel de grande taille, ce qui permet de lancer le logiciel, au prix de performances dégradées. Enfin, la gestion des entrées-sorties mappées en mémoire est aussi simplifiée. De plus, cela permettait d'adresser plus de mémoire RAM grâce aux adresses plus longues du mode protégé. Il faut noter que dans le mode 8086 virtuel, les programmes peuvent utiliser les registres ajoutés sur le 386 et ultérieurs. Par exemple, le 8086 n'a que 4 registres de segment, alors que le 286 en a 6. Les programmes en mode 8086 virtuel peuvent utiliser les deux registres de segment supplémentaires. Il en est de même pour d'autres registres ajoutés par le 286, comme des registres de contrôle, des registres de debug, et quelques autres. Il en est de même pour les instructions ajoutées par le 286, le 386 et ultérieur, qui sont exécutables en mode virtuel 8086. Et elles sont nombreuses. La compatibilité n'était pas parfaite, il y avait quelques petites différences entre ce mode V86 et le mode réel du 8086, idem avec le mode réel du 286. Mais la grande majorité des applications n'avait aucun problème. Les problèmes étaient concentrés sur quelques instructions précises, notamment celles avec un préfixe LOCK. ===L'implémentation matérielle du mode virtuel 8086=== Le processeur est configuré en mode V86, le bit VM du registre d'état spécifique est mis à 1. Le processeur utilise ce bit lorsqu'une instruction utilise les registres de segments, afin de savoir comment calculer les adresses, le calcul n'étant pas le même en mode réel et en mode protégé. Quelques instructions machines dépendent aussi de la valeur de ce bit, mais cela est traité au décodage de l'instruction, et plus précisément dans le microcode. La plupart des instructions sont en double dans le microcode : il y a une version utilisant la segmentation en mode réel, une autre utilisant la pagination segmentée du mode protégé. Pour être plus précis, ces instructions sont coupées en deux dans le microcode : un microcode qui lit une opérande et dépend de la mémoire virtuelle, un microcode qui exécute le reste de l'instruction. La première partie n'est pas la même suivant qu'on est en mode réel ou protégé. Mais la seconde partie est la même dans les deux modes et est partagée entre les deux. En clair, les instructions ont deux points d'entrées : un pour le mode réel, un autre pour le mode protégé. Les deux lisent la table des segments/pages, font des tests de protection mémoire, puis branchent vers le microcode partagé. Pour faire la différence, un bit du processeur indique si le CPU est en mode réel ou protégé, et ce bit est utilisé pour adresser le microcode. Il est appelé le bit P et vaut 1 en mode protégé, 0 en mode réel. Le mode virtuel 8086 combine de bit PE avec le bit VM. Le bit utilisé pour adresser le microcode est calculé avec l'équation logique suivante : <math>\text{P} . \overline{\text{VM}}</math>. Ainsi, le bit qui adresse le microcode est mis à 0 quand le bit VM est à 1, ce qui adresse le microcode du mode réel. Les instructions liées au interruption étaient émulées en mode virtuel 8086. Par exemple, les instructions CTI et STI, qui activaient ou désactivaient les interruptions, n'étaient pas exécutées en mode virtuel 8086. Leur exécution entrainait la levée d'une exception matérielle, qui les émulait en matériel. Mais, il fallait un hyperviseur 8086 pour gérer la situation, notamment pour maintenir un registre d'interruption virtuel. ===Les ''Virtual-8086 mode extensions''=== A partir du processeur Pentium, les processeurs x86 ont introduit des optimisations du mode V86, afin de rendre la virtualisation plus rapide. L'ensemble de ces optimisations est regroupé sous le terme de '''''Virtual-8086 mode extensions''''', abrévié en VME. Les optimisations du VMA étaient, pour certaines, utiles au-delà de la virtualisation et étaient activables indépendamment du reste du VME. Le VME introduisait des optimisations quant au traitement des interruptions, à savoir la gestion des interruptions virtuelles. De plus, le VME modifie la gestion de l'''interrupt flag'' du registre d'état. Pour rappel, ce bit permet d'activer ou de désactiver les interruptions masquables. Modifier le bit ''interrupt flag'' permettait de désactiver les interruptions masquables ou au contraire de les activer. Il se trouve que ce bit était accesible par les programmes exécutés en mode réel, qui pouvaient en faire ce qu'ils voulaient. Le mode réel n'étant pas prévu pour la multi-programmation, ce n'était pas un problème. Mais en mode V86, toute modification de ce bit se répercute sur les autres VM en mode V86. Pour éviter les problèmes, le VME a ajouté de quoi virtualiser cet ''interrupt flag'', avec une copie par machine virtuelle V86. Chaque programme modifiait sa propre copie de l'''interrupt flag'' sans altérer celle des autres programmes exécutés en mode V86, et surtout sans déclencher une exception matérielle gérée par l'hyperviseur. Bien qu'elles aient été introduites sur les processeurs Pentium, elles n'ont réellement été rendues publiques qu'après la sortie des processeurs de microarchitecture P6. Avant d'être rendue publique, la documentation du VME était une annexe de la documentation officielle, la fameuse annexe H. Elle était mentionnée dans la documentation officielle, mais était indisponible au grand public, seules quelques entreprises sous NDA y avait accès. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les architectures neuromorphiques | prevText=Les réseaux de neurones matériels | next=Le matériel réseau | nextText=Le matériel réseau }} </noinclude> 2vai3rkr679yo3dr0s38oa81aszt7l3 Fonctionnement d'un ordinateur/Les ISA optimisés pour la compilation/interprétation 0 83651 772082 765826 2026-09-12T17:02:13Z Mewtow 31375 /* Les jeux d'instructions dédiés à un langage de programmation */ 772082 wikitext text/x-wiki De nos jours, la majorité des programmeurs programment dans des langages de haut niveau. Il est très rare pour eux d'avoir à utiliser de l'assembleur, et encore moins un langage machine. Les programmes écrits dans un langage de haut niveau sont traduits en langage machine par un logiciel appelé le compilateur. [[File:Compilation.PNG|centre|vignette|upright=2.5|Compilateur : principe.]] Il se trouve que quelques rares processeurs sont conçus pour faciliter le travail du compilateur. Et ce sont ces processeurs que nous allons voir dans ce qui suit. Ils représentent une catégorie de jeux d'instruction à part, qui n'a pas vraiment de nom. ==La compilation et l’interprétation== Un compilateur traduit donc du code source, écrit dans un langage de haut niveau, vers du langage machine. La traduction est rarement directe. En général, le compilateur traduit le code source en assembleur, qui est lui-même traduit en langage machine. L'assembleur est une représentation textuelle du langage machine alors que le code machine est du binaire exécutable par le processeur. La traduction se fait donc en deux étapes, la '''compilation''' proprement dite et l''''assemblage''', réalisées respectivement par un compilateur et un assembleur. Il faut parfois rajouter une troisième phase d'édition des liens, que nous passons volontairement sous silence. {| |[[File:Code C.png|vignette|200px|Le code source, ici en C.]] |[[File:Assem.png|vignette|250px|Le code assembleur.]] |[[File:Binary file - hello world (C programming).png|vignette|150px|Le code machine.]] |} ===L'interprétation et la compilation à la volée=== Une alternative à la compilation est l''''interprétation''', qui transforme le code source en code machine à la volée. Avec l'interprétation, le code source est passé à un logiciel appelé l''''interpréteur''', qui exécute le code source ligne de code par ligne de code. Une ligne de code est traduite en code machine, qui est exécutée, puis l'interpréteur passe à la ligne suivante. [[File:Kaantotulkkaus.png|centre|vignette|upright=3|Compilation versus interprétation.]] Un défaut de l'interprétation est son cout en performance, qui est assez important. Aussi, l'interprétation stricte a évolué vers un hybride entre interprétation et compilation. L'idée est qu'une partie peu importante du code source est interprétée, alors que le code important est compilé juste avant d'être exécuté. Pour le dire autrement, le code source est partiellement compilé à la volée, juste avant son exécution. Aussi, on parle de '''compilation à la volée'''. Le terme en anglais est ''Just In Time compilation'', abrévié en JIT. En soi, le JIT est associé à de l'interprétation, les JIT sont en réalité des hybrides interpréteurs-compilateurs. Un point important est que compiler du code à la volée est assez lourd, cela a un cout en performance. Par contre, le code compilé s'exécute plus vite que du code interprété. Si on exécute le code compilé une seule fois, le cout de la compilation l'emporte sur le gain à l'exécution. Mais le code compilé est réutilisé autant de fois que nécessaire. Le gain à l'exécution est donc multiplié par le nombre d'exécutions, alors que le cout de la compilation est répartit sur plusieurs exécutions, il est amorti. Les portions du code sont choisies de manière à avoir un gain en performance maximal. L'idée générale est que le code exécuté très souvent est compilé, alors que du code exécuté pas souvent est interprété. Typiquement, les boucles les plus souvent exécutées sont compilées, le code exécuté une seule fois est interprété. ===Les langages intermédiaires=== Les compilateurs modernes passent par un '''langage intermédiaire''' pour faire la transformation en code machine. Le compilateur traduit le langage de haut niveau en langage intermédiaire, puis traduit le langage intermédiaire en code machine cible. Le langage intermédiaire est parfois appelé le '''''bytecode''''', et ce terme recouvre aussi le code écrit avec du ''bytecode''. L'interprétation aussi peut passer par l'intermédiaire d'un un ''bytecode'', ce n'est pas limité aux compilateurs proprement dit. {| |[[File:Intermediate representation scheme.png|centre|vignette|upright=1.5|Représentation intermédiaire d'un compilateur.]] |[[File:Code interpreter scheme.png|centre|vignette|upright=1.5|Fonctionnement d'un interpréteur.]] |} Faire ainsi a de nombreux avantages, le principal étant d'avoir un compilateur capable de traduire un langage de haut niveau vers plusieurs jeux d'instructions différents. Cela permet d'avoir, par exemple, un compilateur qui traduit du C soit en code machine x86, soit en code machine pour un CPU ARM, soit pour un CPU POWERPC, etc. [[File:Compiler design.svg|centre|vignette|upright=3|Compiler design]] Pour l'interprétation, l'usage d'un ''bytecode'' a d'autres avantages. Pour l'exploiter, il faut distribuer non pas le code source, mais le ''bytecode''. En clair, l'interpréteur ne prend pas en entrée le code source, mais du ''bytecode'' déjà compilé. La traduction est alors beaucoup plus simple, car le code source a déjà été partiellement compilé, par la traduction en ''bytecode''. Interpréter du code source est en effet assez compliqué : il faut effectuer des étapes d'analyse lexicale, sémantique, et bien d'autres. Avec du ''bytecode'', ces étapes ont été réalisées lors de la compilation du ''bytecode'', l'interpréteur a alors peut de choses à faire. L'interprétation du ''bytecode'' se fait instruction par instruction, au niveau du ''bytecode''. Une instruction du ''bytecode'' est traduite en une instruction machine équivalente, qui est exécutée. Si l'instruction est un peu complexe, il exécute une fonction/procédure qui fait la même chose. Pour résumer, le ''bytecode'' est ensuite traduit à la volée et exécuté instruction par instruction par un logiciel appelé l'interpréteur. [[File:Control table.png|centre|vignette|upright=2|Control table]] Le langage intermédiaire peut être vu comme l'assembleur d'un processeur, n'existe pas forcément dans la réalité, mais dont le jeu d'instruction est décrit en détail. Le processeur en question est appelé une '''machine abstraite''', ou encore une ''machine virtuelle''. Nous utiliserons le terme de machine abstraite dans ce qui suit. La machine abstraite n'est pas la même suivant que l'on cible la compilation ou l'interprétation/JIT. Pour l'interprétation/JIT, la machine abstraite est souvent une machine à pile, car cela simplifie grandement la traduction en code machine final. L'interprétation demande que la traduction du ''bytecode'' en code machine soit la plus simple possible. Et cela demande de prendre en compte pas mal de détails. Par exemple, les différents jeux d'instruction existants n'ont pas le même nombre de registres, ce qui pose problème lors de la traduction du ''bytecode''. Lors de la transformation en code machine, un algorithme d'allocation de registres se débrouille pour traduire le code intermédiaire en code qui utilise un nombre limité de registres. Pour améliorer cette allocation de registres, il y a deux solutions niveau ''bytecode'' : soit utiliser un nombre illimité de registres, soit utiliser une machine à pile. Pour les machines à pile, il existe un algorithme simple et rapide pour traduire un code écrit pour une machine à pile en un code écrit pour un processeur avec des registres, qui se débrouille pas trop mal pour allouer efficacement les registres. C'est un avantage assez important pour les langages interprétés. ==Les processeurs qui exécutent du bytecode== Le ''bytecode'' est un code machine, ce qui signifie qu'il peut en théorie s'exécuter sur un processeur qui implémente le jeu d’instruction associé. Si le jeu d'instruction d'un ''bytecode'' est souvent une description censée être fictive, elle n'en reste pas moins un jeu d'instruction et des caractéristiques précises, qu'on peut l'implémenter en matériel ! Néanmoins, tous les ''bytecode'' ne sont pas égaux de ce point de vue. Certains sont faciles à implémenter en matériel, d'autres non. Les ''bytecodes'' implémentés en matériel sont ceux dont les machines abstraites sont des machines à pile. Un premier exemple est celui des processeurs Pascal MicroEngine, qui exécutaient directement le bytecode du langage Pascal, le fameux UCSD P-code. Un second exemple est la '''machine SECD''', qui sert de langage intermédiaire pour certains compilateurs de langages fonctionnels. Elle a été implémentée en matériel par plusieurs équipes, notamment par les chercheurs de l'université de Calgary en 1989. Dans le même genre, quelques processeurs simples étaient capables d’exécuter directement le ''bytecode'' du langage FORTH. Le FORTH, un des premiers langages à pile de haut niveau, possède de nombreuses implémentations hardware et est un des rares langages de haut niveau dont le ''bytecode'' a été utilisé comme langage machine sur certains processeurs. Par exemple, on peut citer le processeur FC16, capable d’exécuter nativement du ''bytecode'' FORTH. ===Les processeurs Java=== Le cas le plus impressionnant est celui de la machine virtuelle Java, qui est un design de processeur comme un autre. En temps normal, le ''bytecode'' Java est compilé ou interprété, mais certains processeurs exécutaient du ''bytecode'' Java directement, sans interprétation ni compilation. Ils sont appelés des '''processeurs Java'''. On peut citer les processeurs ARM disposant de l'extension Jazelle, du JEMCore et du aJ-100 de aJile Systems, le picoJava II de Sun, et quelques autres. Il y a aussi eu quelques projets de recherche ou processeurs open source, comme Komodo, jamuth, le ''Java Optimized Processor'' et quelques autres projets du même genre. L'implémentation de la machine virtuelle Java n'était cependant pas complète. Quelques instructions complexes n'étaient pas gérées par le processeur et devaient être émulées en logiciel. Mais la grosse majorité des instructions l'était. Les instructions non-supportées étaient émulées avec la méthode ''trap and emulate'', à savoir qu'un opcode inconnu déclenchait une exception matérielle ''opcode invalide'', dont la routine pouvait émuler les instructions qui doivent l'être. Le processeur aJ-100 de aJile est capable d'exécuter la quasi-totalité des instructions de la JVM Java, seules deux instructions faisant exception. Les '''accélérateurs Java''' sont une solution intermédiaire, qui permet de traduire à la volée du ''bytecode'' Java en instructions RISC, exécutées sur un autre processeur. Il s'agit formellement de traduction binaire, mais je préfère en parler ici. L'idée est de combiner un processeur RISC avec un coprocesseur Java. Le coprocesseur lit le ''bytecode'' Java et le traduit en instructions RISC, ces dernières étant exécutées sur le processeur RISC. Le JA108 de Nozomi était un coprocesseur de ce genre, au même titre que le coprocesseur JSTAR de JEDI. L'extension Jazelle de certains CPU ARM fonctionnait vraisemblablement sur un principe similaire, sauf que le coprocesseur était intégré dans le processeur ARM, entre le cache d'instruction et le décodeur d'instructions ARM. L'intérêt des processeurs Java n'est pas qu'une question de performance. Certes, ils permettent d’exécuter plus vite les programmes compilés en ''bytecode'', comme des programmes Java pour la JVM Java. Mais l'intérêt est aussi de faire des économies de mémoire RAM et ROM. Je rappelle que la machine virtuelle Java est une machine à pile, ce qui fait que sa densité de code est excellente. Les programmes en ''bytecode'' Java sont donc très petits, et prennent peu de place en mémoire ROM. De plus, utiliser un processeur Java permet de se passer d'interpréteur ou de JIT Java, ce qui économise encore plus de mémoire. ===Transformer un processeur RISC en machine à pile=== La plupart des processeurs Java utilisent en interne une architecture à registre généraux, qui émule une machine à registre en microcode. Quelques registres sont réservés pour l'état de la machine virtuelle, avec au minimum un registre réservé pour le pointeur de pile, un autre pour un pointeur vers un ''pool'' de constantes, et quelques autres. D'autres registres servent à mémoriser le haut de la pile, à savoir le sommet de la pile et quelques opérandes situées juste en-dessous. Par exemple, le processeur picoJava II gardait les 64 opérandes au sommet de la pile dans 64 registres généraux, séparés des registres pour les pointeurs et l'état de la JVM. Une optimisation possible, envisagée sur les processeurs picoJava, était une sorte de macro-fusion sous stéroïde. L'idée était de fusionner certaines séries d'instructions Java en une seule instruction machine. Typiquement, pour faire une opération arithmétique, une machine à pile empile deux opérandes et exécute une opération, ce qui prend trois instructions machine. La spécification picoJava 1 a proposé d'envoyer directement la seconde opérande en entrée de l'ALU, ce qui fusionnait l'empilement de la seconde opérande et l'opération arithmétique. Le processeur picoJava II va plus loin et fusionne les trois instructions en une seule instruction RISC, agissant sur des registres. Mais la majorité des processeurs Java ne faisaient pas cela, car cela complexifie grandement le décodeur. Les processeurs ''bigfoot'' de DCT utilisaient un système différent pour émuler une pile avec des registres. Leur banc de registre de 64 bits était coupé en deux : les 16 premiers registres étaient utilisés pour la pile, les 48 suivants étaient utilisés pour autre chose. L'idée est que le registre 0 mémorise un emplacement vide, le registre 1 contient le sommet de la pile, le registre 2 l'opérande sous le sommet de la pile, et ainsi de suite. Les 15 premières opérandes de la pile sont donc mémorisées dans les registres. Les instructions écrivent leur résultat dans le registre adéquat, puis tous les registres sont décalés pour que le résultat passe dans le registre R1. Par exemple, les instructions PUSH chargent une opérande dans le registre 0, puis tous les registres sont décalés de un rang, pour que l'opérande chargée soit dans le registre 1. Le registre 0 devient alors le registre numéro 1, le registre 1 devient le 2, et ainsi de suite. Par contre, les opérations arithmétiques font autrement. Une instruction d'addition, par exemple, lit les opérandes dans le registre 1 et 2, puis place son résultat dans le registre 2 (les deux opérandes sont dépilées). Puis, les registres sont décalés d'un rang pour que ce registre 2 devienne le 1. Les registres ne sont en réalité pas décalés, il n'y a pas de transferts entre registres. A la place, les 16 premiers registres utilisaient une forme limitée de renommage de registres, similaire au banc de registre tournant utilisé sur les processeurs EPIC comme l'Itanium. Les numéros de registres sont renommés, décalés, à chaque fois qu'on empile ou dépile une opérande. Pour faire le renommage de registres, processeur contient un ''register stack counter'' de 4 bits, qui est incrémenté à chaque fois qu'on empile une donnée, et est décrémenté quand on dépile une donnée. Quand on veut accéder à un opérande, le numéro de registre architectural associé est traduit en numéro de registre physique, en additionnant le ''register stack counter'' (modulo 16, pour rester sur 4 bits). ==L'accélération de l'interprétation/JIT : le ''Thumb-EE'' d'ARM== Quelques processeurs ont ajouté des instructions pour faciliter le travail des interpréteurs/JIT. Par exemple, en 2005, ARM a ajouté le mode ''Thumb Execution Environment'', qui faisait cela. Il reprenait le jeu d'instruction compact ''thumb'' et ajoutait quelques instructions et modifiait le comportement d'instructions existantes. Le jeu d'instruction ''Thumb-EE'' a été ajouté sur les CPU ARM en 2005, mais a été déprécié en 2011, par manque d'utilité. Mais la tentative mérite qu'on s'attarde dessus. Les CPU de gamme M, déstinés à l'embarqué, n'ont jamais supporté ''Thumb-EE'', vu que de tels processeurs ne sont pas conçus pour exécuter du code interprété/JIT. Le mode ''Thumb-EE'' est un mode d'exécution, séparé de l'ARM normal. Ainsi, une instruction ''Thumb-EE'' et une instruction ARM peuvent avoir le même encodage en binaire, mais se comporter différemment. Le processeur est à tout moment soit en mode ''Thumb-EE'', soit en mode ARM normal, ce qui précise comment ces instructions doivent se comporter. Des instructions ont été ajoutées par ''Thumb-EE'', pour qu'il fasse son travail. L'entrée et la sortie du mode ''Thumb-EE'' se fait avec deux instructions : ENTERX et LEAVEX. Une fois en mode ''Thumb-EE'', le décodage des instructions ''thumb'' se fait avec les règles du ''Thumb-EE'', et non celles du ''thumb'' normal. Une première différence entre ''thumb'' normal et ''Thumb-EE'' est l'ajout de ce qui s'appelle un ''null check'' pour les instructions mémoire. Le ''null check'' est utilisé pour les instructions en mode d'adressage "base + indice" ou "Base + décalage", ou tout autre mode d'adressage avec un registre de base utilisés dans des calculs d'adresse. L'idée est de vérifier si l'adresse de base vaut zéro ou non. Si c'est le cas, le processeur lève une exception matérielle, qui est traitée par l'interprétation ou le compilateur JIT. Une telle situation est en effet signe d'une erreur d'adressage mémoire, qui doit être traitée par l'interpréteur. Typiquement, c'est signe qu'un pointeur n'a pas bien été initialisé, ce qui peut arriver avec du code interprété ou JIT. Les interpréteurs/JIT traitent généralement la situation en ajoutant un test avant toute instruction mémoire, pour vérifier si le pointeur accédé vaut zéro ou non. Avec ''Thumb-EE'', pas besoin d'ajouter les tests en questions : ils sont réalisés automatiquement lors de chaque instruction mémoire. : Les registres pour la pile, comme le pointeur de pile et le pointeur de ''frame'', sont aussi concernés. L'instruction CHKA vérifie que les accès à un tableau ne débordent pas en dehors du tableau en question. Par exemple, pour un tableau de 1024 éléments, elle vérifie si l'indice est compris entre 0 et 1024. Pour cela, elle vérifie si l'indice de tableau est bien dans l'intervalle adéquat et lève une exception matérielle si ce n'est pas le cas. Son utilité se comprend quand on sait que tous les accès à un tableau sont vérifiés par l'interpréteur. L'interpréteur est censé ajouter des instructions pour vérifier les indices, à savoir deux ou trois branchements. Avec CHKA, le test se fait en une seule instruction. D'autres modifications mineures de l'encodage des instructions sont aussi présentes, ainsi que des modifications pour les instructions LOAD/STORE. Précisément, dans les modes "base + indice" et "base + décalage", le décalage et l'indice subissent maintenant des décalages. L'idée est de simplifier le calcul d'adresse. De quoi économiser quelques instructions lors des calculs d'adresse, ce qui facilite le travail de l'interpréteur/JIT. Et des instructions LOAD/STORE précises voient leur comportement modifié pour faciliter la gestion de la pile de Java ou l'exécution des méthodes locales. Pour faciliter le travail de l'interpréteur, deux instructions HBP et HBLP ont été ajoutées. Elles branchent vers une fonction qui gère les exceptions logicielles (une fonctionnalité présente dans de nombreux langages, comme Java). La première effectue un branchement vers la fonction en question, la seconde sauvegarde l'adresse de retour avant de faire ce branchement. Les deux peuvent brancher vers 256 fonctions pré-déterminées, sans avoir à présenter leur adresse. ==La traduction binaire accélérée par le matériel== Plus haut, nous avons surtout parlé des compilateurs et des interpréteurs. Cependant, nous devons aussi parler de la '''traduction binaire'''. Elle traduit un programme écrit dans un code machine vers un autre code machine. Par exemple, elle traduit un programme compilé pour un CPU x86 vers un code machine ARM. En général, le système d'exploitation est généralement compilé pour le jeu d'instruction natif, mais il exécute des applications prévues pour le x86. Les applications sont traduites par le système d'exploitation, avant d'exécuter le code traduit. : Nous parlerons dans la suite de code machine source et de code machine cible, pour parler respectivement du code à traduire et du code obtenu après traduction. Idem avec d'autres termes comme architecture cible/source, ou jeu d'instruction cible/source. La traduction binaire est surtout utilisée pour des questions d'émulation ou de compatibilité. Par exemple, lorsque les Macintosh sont passés de processeurs Power PC vers des processeurs x86, le système d'exploitation Mac OS utilisait la traduction binaire pour convertir les anciennes applications Power PC vers du code x86. Les utilisateurs n'y ont vu que du feu. Le système de traduction binaire était appelé Rosetta 1. Par la suite, lors de la transition de processeurs x86 vers des processeurs Apple, Rosetta 2 a vu le jour. La traduction binaire a surtout été utilisée pour traduire du code x86 vers un autre jeu d'instruction. Il faut dire que le x86 est le jeu d'instruction dominant. De nombreuses entreprises ont eu pour ambition de briser l'hégémonie du x86 sur PC, en remplaçant le x86 par un jeu d'instruction plus performant, tout en gardant une compatibilité maximale. La traduction binaire était la seule solution pratique. Elle était le plus souvent intégralement réalisée en logiciel, comme c'était le cas sur les architectures Itanium avec le ''IA-32 Execution Layer''. ===Les généralités sur la traduction binaire assistée en matériel=== L'architecture source est presque tout le temps une architecture CISC, assez ancienne, qu'on souhaite émuler. Le choix de l'architecture cible se porte souvent sur une architecture VLIW, fort différente de l'architecture source, et ce pour obtenir une économie de matériel conséquente. Pour s'exécuter rapidement, le code traduit doit exploiter le parallélisme d'instruction, à savoir exécuter plusieurs instructions en même temps dans des unités de calcul séparées. Il est possible d'utiliser un processeur superscalaire avec exécution dans le désordre pour cela, mais au prix d'un cout important en transistors. Alors qu'en utilisant un CPU VLIW, c'est le traducteur binaire qui fait tout le travail d'extraction du parallélisme d'instruction. Et après tout, quitte à avoir un traducteur binaire, autant lui refiler le boulot d'optimisation. Compiler du code à la volée est certes assez lourd, mais qu'il existe des algorithmes efficaces pour regrouper des instructions indépendantes dans une seule instruction VLIW. Au passage, le processeur VLIW a plus de registres que le processeur source. Cela permet de faire du renommage de registres directement en logiciel. Le traducteur binaire n'hésite pas à changer les noms de registres entre instructions source et instruction VLIW cible, afin de supprimer des dépendances de données. En conséquence, cela ouvre des opportunités de parallélisme, qui sont exploitées lors du regroupement des opérations en instructions VLIW. Vous pourriez penser que le choix d'un CPU VLIW pour émuler du CISC est tout sauf optimal. Vous devez penser que la traduction binaire est d'autant plus simple que l'architecture source et cibles sont semblables. Dans les faits, ce n'est pas tellement traduire les instructions qui pose problème, mais plus la gestion du registre d'état, des exceptions matérielles, de la mémoire virtuelle, la différence entre gros-boutisme et petit-boutisme, de même que des différences d'adressage pour les périphériques. Le premier problème est la gestion des conditions, notamment en présence d'un registre d'état. En pratique, la traduction binaire s'utilise pour traduire du code CISC vers du code RISC ou VLIW. Les architectures source ont donc un registre d'état, qui est mis à jour non seulement par des instructions de test, mais aussi des instructions arithmétiques. L'architecture cible n'a elle pas de registre d'état, mais des registres à prédicats. La traduction de l'un vers l'autre est alors quelque peu compliquée. Et elle est d'autant plus compliquée que le registre d'état est la source de dépendances d'instruction implicites, qui réduisent les performances. Par exemple, si une instruction arithmétique modifie le registre d'état, cela peut impacter l'exécution d'une instruction ultérieure, qui lit ce registre d'état. Pour éliminer ces fausses dépendances, le traducteur binaire doit renommer ce registre en logiciel et détecter les dépendances utiles. Et le compilateur doit gérer les cas où il y a beaucoup de distance entre les deux, voire les cas où l'instruction dépendante n'a pas encore été analysée par le compilateur. Un autre problème est lié à la gestion des exceptions matérielles, et précisément des exceptions précises. Pour rappel, une instruction VLIW regroupe plusieurs opérations, opérations qui correspondraient à une instruction machine sur un CPU pas VLIW. En conséquence, plusieurs instructions du langage machine "source" sont regroupées en une seule instruction VLIW. Et il faut tenir compte du cas où une instruction source lève une exception. Dans le code VLIW, cela signifie qu'une opération lève une exception, et il faut annuler partiellement l'instruction VLIW associée. Et par partiellement, on veut dire que seules les opérations suivantes dans l'ordre du programme source doivent être annulées, puis ré-exécutées. Et c'est un sacré casse-tête ! Les processeurs VLIW utilisent comme solution le mécanisme d'exceptions différées des processeurs EPIC, vu il y a quelques chapitres. Pour résumer, le code est exécuté par blocs d'instruction, délimités par des branchements ou tout autre limite/barrière pertinente dans le code. Un bloc de code est compilé en deux versions : une version rapide sans exceptions matérielles, une version lente qui gère les exceptions précises. La version rapide s'exécute sans exécuter les exceptions. Cependant, les exceptions matérielles sont enregistrées, pour être prises en compte à la toute fin du bloc de code. La version rapide est exécutée en premier et elle mémorise si une exception matérielle a eu lieu. Puis une instruction vérifie si une exception a eu lieu et décide quoi faire. Si aucune exception n'a eu lieu, elle passe à la suite du programme, les résultats du bloc de code sont définitivement acceptés. Mais si une exception a eu lieu, tout est annulé. Le processeur est remis dans l'état initial, puis le code est ré-exécuté instruction par instruction de manière à gérer l'exception correctement. ===La traduction par pré-décodage=== Une première solution serait de faire la traduction binaire dans le cache d'instruction. Lors d'un défaut de cache, le code chargé depuis la RAM est traduit en code machine cible. Et c'est ce code machine cible qui est mémorisé dans le cache d'instruction et exécuté par le processeur. La technique marche sur le papier et n'est qu'une amélioration des techniques de pré-décodage vues il y a quelques chapitres. Cependant, le code obtenu est une traduction assez basique, qui n'incorpore pas d'optimisations dignes de ce nom. De plus, elle gère mal le cas où la taille du code source et cible sont potentiellement très différentes. Concrètement, elle est surtout utile pour traduire du code d'un processeur RISC vers un autre processeur RISC, dont les tailles d'instructions sont similaires. Elle ne permet pas d'émuler plusieurs jeux d'instructions différents, le cout en matériel (un circuit de pré-décodage par jeu d'instruction) serait trop important. ===Le projet DAISY d'IBM=== De très rares processeurs étaient conçus pour accélérer cette traduction binaire, afin de garder de bonnes performances. Les premiers à avoir étudié l'idée étaient IBM, avec leur projet DAISY (''Dynamically Architected Instruction Set from Yorktown''). Le projet de base était de convertir à la volée du code compilé pour des CPU Power PC, vers du code VLIW. Les chercheurs d'IBM avaient développé un algorithme de traduction dynamique efficace, ainsi qu'un processeur VLIW disposant d'optimisations spécifiques à la traduction binaire dynamique, à la volée. De nombreuses idées de ce projet ont été reprises ou re-découvertes par la société Transmetta, avec ses processeurs Crusoe et Efficieon, puis par NVIDIA avec son projet Denver. Les ingénieurs de ce projet ont étudié la possibilité d'émuler plusieurs jeux d'instructions différents sur un même processeur, notamment le s390 d'IBM et le x86. En théorie, cela demande juste d'avoir plusieurs programmes de traduction binaire : un pour le x86, un autre pour le s390, éventuellement un autre pour le Power PC. Mais cela ne s'est pas concrétisé. Mais les ingénieurs ont étudié quelle pourrait être l'architecture VLIW idéale pour ça. Par exemple, il fallait des additions 3-opérandes pour simplifier les calculs d'adresse. Une difficulté était la gestion du registre d'état, dont les bits ne sont pas mis à jour de la même manière sur le x86 et le s390 ou le Power PC. La différence entre gros-boutisme et petit-boutisme était aussi un problème, de même que des différences d'adressage pour les périphériques. Pour que la traduction binaire soit efficace, le processeur VLIW intègre diverses optimisations, comme les exceptions différées et les branchements multi-voies. La principale est la suivante : seul le code des boucles ou fonctions exécutées fréquemment est traduit en code VLIW, le reste du code est interprété. En effet, traduire du code binaire prend plus de temps qu'une simple interprétation. Pour du code qui ne sera exécutée qu'une seule fois, il est plus rapide d'utiliser l'interprétation. Par contre, pour du code exécuté beaucoup de fois, le cout de la traduction binaire est amorti, dilué sur N exécutions, compensé par le gain en temps d'exécution de ce code traduit. Au final, cela permet de ne traduire que le code qui le mérite. La détection du code fréquemment exécuté est réalisée dans le cœur VLIW. L'unité de branchement mémorise les derniers branchements rencontrés et le nombre de fois qu'ils ont été exécutés. Si ils ont été exécutés un certain nombre de fois, l'unité de branchement lève une exception matérielle, qui invoque le traducteur binaire. La routine de cette exception est le traducteur binaire proprement dit. En clair, la traduction binaire est démarrée quand le processeur détecte qu'une fonction a été exécutée plus de N fois, via une exception matérielle dédiée. La mesure du nombre d'exécution d'un branchement se fait dans l'unité de calcul dédiée aux branchements, avec l'aide d'une sorte de ''branch adress buffer'' modifié. Pour rappel, le ''branch adress buffer'' mémorise le ''Program counter'' de chaque branchement récemment rencontré. Ici, chaque entrée du ''branch adress buffer'' est associée à un compteur incrémenté à chaque exécution du branchement. ===Les processeurs Crusoe et Efficieon de Transmetta=== Les processeurs Crusoe Et Efficeron sont deux processeurs VLIW produits par la société Transmetta, une société californienne rachetée par NVIDIA. Ils étaient conçus pour exécuter spécifiquement des programmes x86, système d'exploitation inclus. L'idée derrière ce projet était d'exécuter du code x86 sans que les applications, ni même le système d'exploitation et le BIOS soient au courant ! Les processeurs Transmetta étaient en réalité conçus pour exécuter un programme unique, le ''Code Morphing Software'' (CMS), qui traduisait le code x86 en code VLIW. Transmetta ne voulait pas que son processeur VLIW soit exploité directement, sans le CMS. Il n'avait pas rendu public de compilateur pour traduire du C vers du code VLIW, il n'avait pas donné la documentation du jeu d'instruction VLIW. Des efforts de rétro-ingénieurie, documentés sur le site realworldtech, ont cependant permis de comprendre comment étaient encodées les instructions du processeur Crusoe. Comme pour le projet Daisy, le ''Code Morphing Software'' utilisait à la fois interprétation et traduction binaire, selon les besoins. Les instructions sont interprétées lors de leurs premières exécutions, mais le CMS bascule sur de la traduction en code VLIW après un certain nombre d'exécution. Ainsi, les boucles souvent exécutées sont traduites en code VLIW, alors que le reste du code est interprété. Le choix du code à traduire est le fait du CMS, il utilise des heuristiques complexes pour, qui ne sont pas connues dans le détail. Le ''Code Morphing Software'' est mémorisé dans une EEPROM, ce qui en fait un ''firmware'' situé en dessous du BIOS. Le CMS démarre ensuite le BIOS, qui lui-même démarre le système d'exploitation, qui lui-même démarre les pilotes de périphériques et les programmes. Le CMS se réserve les 16 premiers mébioctets de l'espace d'adressage. L'EEPROM du CMS est mappée dedans, mais n'en utilise que la moitié. Le reste est utilisé comme cache, pour mémoriser le code VLIW traduit par le CMS. Les deux processeurs intégraient aussi deux mémoires SRAM, utilisées par le CMS, appelées la ''local program memory'' (LPM) et la ''local data memory'' (LDM). La première contient du code qui gére les interruptions, la mémoire virtuelle, les exceptions matérielles, les problèmes d'alignement mémoire, et quelques fonctions très fréquemment utilisées par le CMS. La seconde est de la mémoire RAM utilisée par ces fonctions de la ''local program memory''. Les mémoires caches L1 et L2 sont séparées de ces deux mémoires. Le processeur Crusoe et Efficieon étaient des processeurs VLIW très simples. Ils n'avaient même pas de MMU, ni de fonctionnalités importantes sur les CPU x86. Pour Crusoe, les instructions VLIW étaient encodées sur 64 ou 128 bits, et regroupaient entre 2 à 4 opérations. Les instructions LOAD/STORE ne supportaient pas d'adressage indicé, juste de l'adressage indirect à registre. Crusoe avait 5 unités de calcul : deux ALU entières, une unité LOAD/STORE, une unité de branchement, une FPU. Efficieon doublait le nombre d'ALU entière et d'unité LOAD/STORE, les instructions VLIW passaient à 256 bits. Le processeur Crusoe contient 160 registres, dont 64 registres généraux, 32 registres flottants. Les registres généraux font 32 bits, ce qui est cohérent avec le fait que les CPU x86 de l'époque étaient des processeurs 32 bits. Quant aux registres flottants, ils faisaient 80 bits, ce qui colle avec la taille des registres flottants de la FPU x87 utilisée à l'époque. Sur les 64 registres généraux, seuls 48 étaient réellement utilisable pour mémoriser des opérandes. Une partie des registres généraux étaient utilisés pour la gestion de la pile, d'autres pour mémoriser l'état du CPU x86 émulé, un registre était un registre zéro non accesible en écriture. La gestion des exceptions est optimisée avec un système d'exceptions différées, le même que celui décrit plus haut. Le processeur utilise un système similaire, pour effectuer des lectures anticipées, qui a été expliqué dans le chapitre sur les processeurs VLIW/EPIC. Sauf qu'il s'agit là d'une optimisation pour gagner en performances en général, pas une aide utile pour gérer des exceptions précises ou toute autre subtilité de la traduction binaire. Pour gérer les exceptions différées et les lectures anticipées, le processeur mémorise l'état du processeur avant de démarrer un bloc de code. Pour cela, le processeur contient des ''shadow registers'', 48 registres entiers et 16 registres flottants. Vous remarquerez qu'il y a autant de registres entiers que de ''shadow registers'' entiers. Les registres entiers/flottants sont mémorisés dans les ''shadow registers'' avant d'exécuter un bloc de code, afin que le processeur puisse revenir à l'état de base. Une autre fonctionnalité liée est le ''gated store buffer''. Le principe est d'éviter toute écriture en mémoire RAM, tant que le code VLIW n'a pas émis d'instruction ''commit''. L'idée est que les écritures sont conservées dans la ''store queue'' de l'unité LOAD/STORE. Pour rappel, la ''store queue'' met en attente les écritures soit tant que les écritures ne sont pas terminées, soit tant que la RAM est occupée. L'idée est que les écritures sont accumulées dans la ''store queue'' tant que l'instruction ''commit'' n'a pas eu lieu. Le ''store queue'' est "déversé dans la RAM" seulement quand l'instruction ''commit'' s'exécute. ===Les CPU NVIDIA Denver=== Nvidia a tenté quelque chose de similaire avec son projet Denver. NVIDIA a racheté l'entreprise Transmetta, ses brevets, et a tenté de refaire la même chose. Le projet initial était de traduire du code x86 vers un jeu d'instruction VLIW propriétaire, comme l'a fait Transmetta. Mais NVIDIA n'a pas réussi à acquérir la licence du jeu d'instruction x86 et s'est rabattu sur le jeu d'instruction ARM. Le processeur né de ce projet est le Tegra K1-64 CPU. Il s'agit d'un processeur composé d'un cœur VLIW, couplé à deux décodeurs d'instructions ARM. Les deux décodeurs ARM traduisent une paire d'instructions ARM consécutives en instructions VLIW, pour les exécuter sur le cœur VLIW. Le CPU peut fonctionner selon deux modes : ARM et VLIW. En somme, le processeur supporte deux jeux d'instruction : le jeu d'instruction ARM, et un jeu d'instruction VLIW. En mode ARM, les instructions ARM sont chargées depuis le cache, traduites en VLIW par les décodeurs ARM, puis exécutées par le cœur VLIW. En mode optimisé, le CPU exécute des instructions VLIW chargées depuis le cache d'instruction, les décodeurs ne sont pas utilisés. : Le CPU supporte en réalité deux jeux d'instruction ARM : ARM8 et 7. Mais ils correspondent au même mode pour le CPU. Un point important est que le processeur peut changer très rapidement de mode, en à peine quelques cycles d'horloges. On n'est clairement pas dans le cas des CPU x86, qui mettent des plombes pour passer du mode 32 à 64 bits et inversement. La commutation est tellement rapide qu'on peut considérer que le processeur supporte deux jeux d'instruction simultanément. Et le support simultané de deux jeux d'instruction facilite l'implémentation de la traduction binaire. Encore une fois, inutile de traduire du code qui ne sera exécutée qu'une seule fois, mieux vaut l'exécuter directement dans le mode ARM. Surtout que le processeur supporte un mode ARM qui permet d'exécuter du code ARM sans perte de performance. Par contre, le code fréquemment utilisé, notamment dans des boucles critiques, est traduit en VLIW. Au final, les performances sont optimisées, en limitant le travail du logiciel traducteur binaire. La détection du code fréquemment exécuté se fait différemment que pour les processeurs Transmetta et Daisy. L'unité de branchement ne détecte pas directement le code beaucoup exécuté, même si elle a un rôle à jouer. A la place, la détection est réalisée en logiciel, par un ''thread'' dédié, qui s'exécute sur un cœur séparé. Il détecte le code fréquemment utilisé en regardent les branchements exécutés récemment. Pour cela, le processeur mémorise l'historique des branchements pris récemment et copie cette historique dans une mémoire tampon dédiée, partagée entre tous les cœurs. Vu qu'elle est partagée, le ''thread'' de détection a accès à l'historique sans pertes de performances, seule la copie de l'historique dans ce tampon a un cout en performance, pas son partage. Le code VLIW obtenu après traduction binaire est mémorisé dans la mémoire RAM, dans une portion spécialement réservée pour. Elle fait 128 mébioctets, et est appelée le '''cache d'optimisation''' par NVIDIA. Le cache d'optimisation est protégé en écriture et seul le traducteur binaire peut écrire dedans. Au passage, le traducteur binaire est du code VLIW, ce qui fait qu'il est placé dans le cache d'optimisation. Le processeur détecte automatiquement quand une fonction pour laquelle le code compilé équivalent est disponible. Pour cela, l'unité de chargement contient une table de correspondance entre l'adresse de la fonction ARM, et l'adresse de son équivalent compilé. Quand une fonction est appelée, l'unité de chargement regarde l'adresse de destination du branchement. Si l'adresse est dans cette table, elle récupère l'adresse de la fonction compilée et branche vers celle-ci. Le processeur dispose d'un cache d'instruction de 128 kibioctets, ce qui est très important, mais nécessaire vu la taille des instructions VLIW. Le coeur VLIW dispose de ses propres décodeurs, d'un ''scoreboard'', de 7 unités de calcul et de registres. Pour les unités de calcul, il a deux FPU, deux ALU, une unité de branchement, et deux unités LOAD-STORE faisant aussi ALU. Un point important est que le CPU dispose de 64 registres entiers et de 64 registres flottants. C'est deux fois plus que supporte le jeu d'instruction ARM. En mode ARM, seule la moitié des registres est utilisée. Mais en mode optimisé, le traducteur binaire utilise bien les 64 registres, grâce à une sorte de renommage de registres logicielle. Pour simplifier la traduction binaire, le processeur supporte les techniques vues précédemment. Le processeur intègre un ''gated store buffer'' similaire à celui des processeurs Transmetta. Les techniques d'exceptions différées sont aussi supportées, comme sur les processeurs Transmetta. Il a aussi une unité de préchargement décrite par NVIDIA comme agressive, avec support du préchargement de type anticipé (''runahead''). ===L'émulation de la mémoire virtuelle=== Pour finir, il faut parler de la mémoire virtuelle avec la traduction binaire. Sur le processeur source, le processeur gère à la fois des adresses physiques et virtuelles et sa MMU fait la conversion entre les deux. Sur le processeur VLIW, la MMU est simulée par le programme de traduction binaire, partiellement ou totalement. L'implémentation exacte varie suivant que l'on parle du projet Daisy, des processeurs Transmetta ou de Denver. Sur les processeurs Transmetta, il n'y a pas de MMU ni de mémoire virtuelle. A la place, le programme de traduction binaire émule la mémoire virtuelle du processeur source. Le processeur VLIW ne gère que des adresses physiques, rien d'autre. L'espace d'adressage physique du processeur VLIW a la même taille que celui du processeur émulé, ici des processeurs x86. Il est vraisemblable que les adresses physiques utilisées par le processeur x86 sont les mêmes que celles du processeur VLIW. Sur le projet Daisy, le processeur VLIW gère la mémoire virtuelle via pagination, comme les processeurs émulés. Ce qui fait qu'il gère un espace d'adressage virtuel et un espace d'adressage physique. Pour éviter toute confusion, nous parlerons d'adresse physique/virtuelle VLIW pour les adresses physiques/virtuelles du processeur VLIW, d'adresse virtuelle/physique source pour celle du jeu d'instruction traduit, à savoir du Power PC ou du s390, éventuellement de l'x86. Il faut alors faire le lien entre adresses physiques source et adresses virtuelles VLIW. Pour cela, rien de plus simple : il y a correspondance parfaite. L'adresse physique source numéro N correspond à l'adresse virtuelle VLIW numéro N. Cependant, cela signifie que tout l'espace d'adressage virtuel VLIW serait utilisé par le code à traduire. En réalité, il faut ajouter de la place pour le code traduit et le programme de traduction binaire. La conséquence est que l'espace d'adressage virtuel VLIW est plus large que l'espace d'adressage source. L'espace d'adressage virtuel VLIW est découpé en trois sections : une section pour le code Power PC à traduire, une autre pour le code traduit en VLIW, et une dernière réservée au traducteur binaire. Le programme de traduction est placé dans une ROM mappée en mémoire dans la seconde section. Le reste de la seconde section est réservé à une mémoire RAM utilisée par le programme de traduction. [[File:Mémoire virtuelle sur le projet Daisy.png|centre|vignette|upright=1.5|Mémoire virtuelle sur le projet Daisy]] Il faut noter que chaque page physique source, une fois traduite, correspond à N pages virtuelles VLIW. La raison est que le code traduit prend plus de place que le code machine originel. En conséquence, on doit utiliser une page finale plus grande. Pour le reste, des pages contiguës en mémoire physique source sont elles aussi contiguës en mémoire virtuelle VLIW. Le calcul d'adresse est donc simple : l'adresse physique source est multipliée par N, puis on ajoute l'adresse de base à laquelle commence la section pour le code traduit. ==La traduction binaire sur les Burroughs B1700== Nous venons de voir comment accélérer en matériel la traduction binaire, avec des techniques bien spécifiques. Le Burroughs B1700 a procédé autrement et il est intéressant d'étudier en détail son architecture. Son architecture est décrite dans le livre "Interpreting Machines : Architecture and Programming of the Bl700/Bl800 Series", écrit par Elliott I. Organick et James A. Hinds. Une partie de ce qui vfa suivre est un très court résumé de ce livre. : Dans ce qui suit, nous parlerons de traducteur binaire pour parler soit d'un interpréteur pour un langage de programmation de haut niveau, soit pour un logiciel de traduction binaire. Le Burroughs 1700 est un processeur 24 bits, qui a cependant la capacité d'émuler des architectures 8, 16 bits assez simplement, via divers mécanismes. Le Burroughs 1700 incorpore de nombreuses optimisations pour cela. Une partie d'entre elles permet de gérer des opérandes de taille différente de 24 bits, d'autres permettent de gérer des instructions de taille différente de 24 bits, d'autres servent pour les deux. Il incorpore aussi des instructions facilitant le découpage des instructions machines en ''opcode'', adresses et constantes immédiates. ===L'ALU de taille variable=== Les Burroughs B1700 avaient une '''ALU de taille variable''', ce qui veut dire qu'elle pouvait faire des calculs sur un nombre de bits compris entre 0 et 24. Pour cela, les calculs étaient faits avec une ALU de 24 bits, puis les bits de poids fort inutiles étaient masqués. L'ALU de 24 bits pouvait masquer les bits de poids fort du résultat, mais avec des limitations. Elle gérait des opérandes et résultats de 0, 4, 8, 12, 16, 20 et 24 bits. Pour avoir un réglage plus fin, une ALU 4 bits séparée permettait de corriger le résultat. Les registres X et Y étaient reliés à une ALU de 24 bits capable d'effectuer des opérations arithmétiques basiques. Fait étonnant, l'ALU faisait tous les calculs en même temps et fournissait ses résultats dans 7 registres : un registre SUM pour l'addition, un registre DIFFERENCE pour la soustraction, et un registre par opération bit à bit. Les registres pour les opérations bit à bit sont : CMPX et CMPY pour l'opération NOT sur chaque opérande, XANY pour le ET bit à bit, XEOY pour le XOR, XORY pour le OU logique. Les additions et soustractions pouvaient se faire sur des opérandes codés en binaire ou en BCD, suivant le code opération utilisé. A cela, il fallait ajouter deux registres de "résultat" MSKX et MSKY. Ils fournissaient un masque dépendant de la taille du résultat en bits. C'est ce registre qui permettait de gérer des données de 0, 4, 8, 12, 16, 20, et 24 bits, alors que l'ALU faisait 24 bits. Le masque dans ce registre pouvait servir d'opérande dans une opération de masquage ultérieure, pour corriger le résultat. L'ALU prenait en opérande les registres X et Y, mais aussi un registre CYF pour la retenue entrante. En sortie, il fournissait aussi deux retenues sortantes : une pour l'addition et une autre pour la soustraction. Elles étaient mémorisées dans les registres CYL et CYD, respectivement. L'ALU fournissait aussi 12 conditions, qui alimentait un registre d'état. Le registre d'état était segmenté en trois registres appelés XYST, XYCN et BICN. Les registres X et Y sont des registres pour les opérandes, mais il y a aussi deux autres registres de 24 bits. Il s'agit des registres T et L, qui sont des registres généraux. Les registres T et L étaient découpés en 6 sous-registres de 4 bits, nommés LA LB LC LD LE et LF pour le registre L, TA TB TC TD TE et TF pour le registre T. Ils étaient adressables comme n'importe quel registre. Le processeur contenait de nombreux autres registres de 4 bits, dont les sous-registres de T et L. En tout, il y a 27 registres de 4 bits adressables ! Et le processeur disposait d'une ALU 4 bits pour manipuler ces registres de 4 bits. L'ALU 4 bits est capable de faire des MOV entre registres de 4 bits, des opérations bit à bit, et peut aussi tester si un bit vaut 0 ou 1. La dernière possibilité est très utile pour implémenter les branchements. De plus, cela permettait de faire des opérations de masquage, notamment pour appliquer un masquage supplémentaire à celui de l'ALU. Par exemple, pour gérer des opérations sur 14 bits, on effectue une opération sur 16 bits avec l'ALU, et on masque les 2 bits manquants avec l'ALU 4 bits. ===Une architecture bit-adressable=== Le CPU Burroughs B1700 était '''bit-adressable'''. En clair, il pouvait adresser la mémoire bit par bit, si nécessaire. Un avantage est que cela facilitait la traduction binaire des instructions machine, mais nous détaillerons cela plus bas. Un autre avantage est que cela permettait d'émuler des architectures dont la taille des registres/''byte''/mots était très différente. Et cet avantage mérite quelques explications immédiates. Le processeur était un CPU 24 bits, mais il pouvait émuler des processeurs 16 bits, 8 bits, 4 bits, 1 bit, 9 bits, ou toute autre valeur. Pour cela, le processeur lisait des mots de 24 bits et utilisant un ''barrel shifter'' pour sélectionner les bits adéquats. Par exemple, pour un accès de 16 bits, la donnée lue en mémoire était masquée de manière à ne garder que les 16 bits de poids faible. Le ''barrel shifter''/circuit de masquage était placé directement avant le bus mémoire, sur le trajet des données/instructions. Le ''barrel shifter'' était commandé par un registre ''Field Unit'', qui précisait quelle était la taille des données à charger. Les instructions source , à traduire, peuvent faire 16 bit avec tel jeu d'instruction, 8 bits avec un autre, 32 bits sur un autre, etc. Elles peuvent aussi être de longueur fixe ou variable ! Le B1700 utilisait une architecture bit-adressable pour gérer ces contraintes. En effet, avec un CPU bit-adressable, les contraintes d'alignement des instructions disparaissent ! ===Des registres d’interfaçage mémoire adressables=== Pour communiquer avec la mémoire, il avait trois registres séparés : READ, WRITE, MAR. READ contient la donnée lue lors d'une lecture, WRITE est pour une donnée à écrire lors d’une écriture, MAR contient l'adresse à lire ou en cours de lecture. Il s'agit de registres d’interfaçage mémoire, les mêmes que ceux vus dans le chapitre sur le chemin de données du CPU. Une instruction LOAD est donc émulée en deux instructions machines : une instruction MOV pour copier l'adresse dans le registre READ, une instruction de lecture proprement dite. L'écriture demande d'ajouter une seconde instruction MOV pour copier la donnée à écrire, et la lecture est remplacée par une écriture. Le fait que ces registres d’interfaçage mémoire et IO soit adressable est peu commun, et c'est plus quelque chose qu'on attend d'un microcode que d'instructions machines. D'ailleurs, l'implémentation des instructions LOAD/STORE ressemble à ce qui est effectué par le séquenceur d'un CPU. Le séquenceur est d'ordinaire celui qui séquence la copie des adresses/données dans les registres d’interfaçage, puis lance la lecture/écriture. Ici, c'est réalisé via des instructions machines. Il faut bien comprendre que les registres d’interfaçage mémoire ont été promus au rang de registres architecturaux, sur ce processeur. De même, pour communiquer avec les entrées-sorties, il disposait de deux registres CMND et DATA : CMND pour envoyer une commande à une entrée-sortie, DATA pour lire ou écrire une donnée. Il y avait aussi un registre U, qui mémorisait une donnée lue depuis le lecteur de cassette. ===Le code machine du Burroughs B1700=== Le processeur utilise des instructions de 16 bits de long, qui sont copiées dans registre d'instruction M de 16 bits. Le ''program counter'' est appelé le registre A. Les instructions du processeur font 16 bits de long, et elles sont alignées en RAM sur 16 bits, ce qui fait que les 4 bits de poids fort de ce registre valent 0, seuls les 14 bits de poids fort sont utiles. Les adresses mentionnées plus haut, qui adressent les micro-opérations en mémoire RAM, sont des adresses de mots de 16 bits, pas les adresses de bit individuels. Fait intéressant, il était possible de faire un OU logique entre l'instruction lue et un registre du processeur, le résultat étant mémorisé dans le registre M. Cela permettait de faire du code automodifiant, pour émuler des modes d'adressage complexe. Cela permettait par exemple de remplacer une adresse dans une micro-opération. L'adresse est alors surimposée avec un OU dans le champ d'adresse, alors que le reste de l'instruction n'est pas modifié. Afin de gérer les interruptions, ces dernières étaient partiellement détectées en logiciel. Une interruption doit être prise en compte à la toute fin de l'exécution d'une instruction source, quand celle-ci a fini son travail. Mais vu qu'ici, les instructions sont émulées avec des séries d'instructions cibles, il y a un problème : il est possible d'interrompre une instruction émulée en plein milieu. Pour éviter cela, le processeur ne déclenche pas les interruptions matérielles immédiatement, elles sont mises en attente. Une instruction dédiée vérifie si une interruption est en attente, et l'exécute alors cas échéant. L'instruction en question est utilisée en dernier, dans la suite d'instruction qui émule l'instruction source. ===La traduction binaire sur le Burroughs B1700=== Les Burroughs B1700 intégraient une pile d'adresse de retour, capable de mémoriser 16 adresses de 24 bits, ainsi que 4 registres généraux, nommés X, Y, T et L, tous de 24 bits. Un point important est que le registre T avait des possibilités d’extraction spécifiques. Il était possible d'extraire N bits, placés n'importe où dans ce registre, et de les copier dans un autre registre. Le CPU supportait une '''instruction EXTRACT''' pour ça. Nous verrons comment cette possibilité est exploitée pour la traduction binaire dans ce qui suit. Dans ce qui suit, on suppose que l'instruction est composée de '''champs''' : l'opcode, les opérandes, les adresses absolues, les constantes immédiates, les numéros de registre, etc. L'idée est que l'instruction source est chargée dans le registre T, puis découpée en champs, qui sont copiés dans les registres du processeur ou envoyés au microcode. Je rappelle que le registre T est relié à un ''barrel shifter'', différent au précédent, qui permettait de masquer, décaler et extraire une donnée de ce registre. Et il y a la possibilité d'extraire une suite de bit de ce registre T, pour la copier dans un autre registre. Par exemple, prenons une instruction composée d'un opcode, d'une constante immédiate et d'une adresse immédiate. Premièrement, elle est chargée dans le registre T. Deuxièmement, la constante immédiate est extraite du registre T et copiée dans le registre X. Troisièmement, l'adresse est extraite et est copiée dans le registre d’interfaçage mémoire, une lecture est démarrée, et l'opérande lu est copiée dans le registre Y. Enfin, l'instruction équivalente à l'opcode est exécutée par le microcode. Le tout prend plusieurs instructions : une première pour lire l'opcode, une seconde pour lire le premier opérande, une troisième pour lire la seconde opérande, une quatrième pour tout exécuter. Notons que suivant la taille des champs, on peut en charger plusieurs à la fois. Par exemple, imaginons qu'on ait chargé 24 bits, contenant un opcode de 8 bits et une constante immédiate de 16 bits : le registre T est découpé en un opcode et une constante, avec deux instructions EXTRACT. L'architecture est bit-adressable, car elle gère des champs qui ne font pas forcément 8 ou 16 bits. Par exemple, certains jeux d'instructions ont des opcodes codés sur 6 ou 7 bits, voire 9-10 bits. Utiliser une architecture bit-adressable règle ce problème d'alignement. On peut lire un champ depuis la mémoire RAM en précisant l'adresse de son premier bit, pas besoin de gérer des accès non-alignés. Par exemple, prenons une instruction source avec un opcode de 7 bits, suivi par une adresse de 12 bits et une constante immédiate de 15 bits. On peut charger 7 + 12 bits en un premier accès, pour extraite l'opcode et l'adresse, suivi par un second accès de 15 bits pour extraire la constante immédiate. Pour charger un champ, il faut connaitre plusieurs informations : l'adresse de son premier bit, sa taille. Pour cela, le B1700 contient deux registres, nommés ''Field Adress'' (FA) et ''Field Length'' (FL), qui indiquent l'adresse du premier bit et la taille de l'instruction à charger. Le premier fait 24 bits, ce qui permet de gérer des adresses de 24 bits. N'oubliez pas que le processeur est bit-adressable, ce qui permet d'adresser 16 Mébi-bits, soit 2 mébioctets. Le registre pour la taille fait lui 16 bits, ce qui permet de gérer des instructions de 65536 bits, soit 8192 octets ! Leur nom commence par ''field'', car le processeur peut gérer des instructions de taille variable et/ou plus longues que 24 bits. Dans ce cas, le chargement de l'instruction se fait champ par champ. Pour donner un exemple, prenons une instruction composée de 20 champs de 12 bits chacun. Les champs sont chargés un par un dans le registre T. Le registre FA est alors initialisé avec l'adresse de l'instruction, il est incrémenté de 12 à chaque cycle. Le registre FL est initialisé avec la taille de l'instruction, soit 20 × 12 = 240 bits, et il est décrémenté de 16 à chaque cycle. Précisons cependant que la taille d'un champ peut être changée d'un cycle à l'autre. Par exemple, le processeur peut charger un opcode de 8 bits, l'interpréter, détecter que l'instruction demande ensuite de charger une adresse de 16 bits. Dans ce cas, le registre FL est immédiatement altéré pour charger 16 bits, au lieu des 8 bits de l'opcode immédiatement précédent. ===Le Burroughs B1726 : le mal-nommé ''split-level control store''=== Le Burroughs B1700 avait plusieurs modèles : le B1726, le B1710 et le B1800. * Le B1710 plaquait le traducteur binaire en mémoire RAM. * Le B1800 avait ajouté un cache dédié au code du traducteur binaire, afin d'améliorer les performances. * Le B1726 utilisait un ''local store'' dédié au traducteur binaire. Le B1726 peut exécuter le traducteur binaire soit depuis le ''local store'', soit depuis la mémoire RAM avec une pénalité en termes de performances. La documentation appelle cela un '''''split-level control store''''', mais le terme est trompeur : la documentation qualifie de microcode le langage machine du Burroughs B1700, ce qui est à l'origine de beaucoup de confusions. Une autre source de confusion est que ce langage machine a quelques propriétés qu'on pourrait attendre d'un microcode, mais certaines sont manquantes. Par exemple, il peut adresser les registres d’interfaçage mémoire, mais c'est parce que ce sont des registres architecturaux sur ce processeur. Ses instructions n'encodent pas de signaux de commande, par contre, elles font 16 bits et adressent les opérandes de manière implicite. Le ''local store'' mémorisait au maximum 2048 instructions machine, ce qui fait que les 2048 premières "adresses" correspondaient au ''local store''. Les suivantes étaient des adresses de mémoire RAM qui contenaient le reste du traducteur binaire. En pratique, l'adresse qui séparait les deux était configurable ! On pouvait limiter la taille du ''local store'' à un multiple de 32 instructions ! Les adresses restantes étaient alors réattribuées à la RAM. Par exemple, on pouvait attribuer 64 adresses au ''local store'', les 2048 - 64 adresses restantes étaient alors attribuées à la mémoire RAM. Un registre limite, nommé TDPM, indiquait quelle était l'adresse de démarcation entre les deux. Le programmeur devait découper le traducteur binaire en segments, certains étant placés dans le ''local store'', les autres étant en mémoire RAM. Mieux que ça, le processeur autorisait d'utiliser la technique de l'''overlaying'' pour le microcode ! Il y avait même une fonction OVERLAY dédiée pour ! OVERLAY avait besoin de trois opérandes : la taille du segment à copier, son adresse source en mémoire RAM, son adresse de destination dans la micro-SRAM. L'interpréteur réservait un "segment" en mémoire RAM, pour les données, dont le processeur connaissait la position. En dehors de ce segment, il n'y a que des instructions machines à traduire, et le traducteur binaire. Le CPU incorporait pour cela deux registres, un pour l'adresse de base du segment de données, un autre pour son adresse de fin. Il incorporait une protection mémoire limitée sur ce segment, à savoir que seul l'interpréteur pouvait lire ou écrire dans ce segment. ==Les jeux d'instructions dédiés à un langage de programmation== De rares processeurs sont conçus pour un langage de programmation en particulier. On appelle ces processeurs, conçus pour des besoins particuliers, des '''processeurs dédiés'''. Par exemple, les fameux ''Burrough E-mode'' B5000/B6000/B7000 étaient spécialement conçus pour exécuter de l'ALGOL-60. Leurs cousins B2000/B3000/B4000 étaient eux conçus pour le COBOL. Des langages fonctionnels ont aussi eu droit à leurs processeurs dédiés. Le prolog en est un bel exemple, avec les superordinateurs de 5ème génération qui lui étaient dédié. On peut aussi citer les machines LISP, dédiés au langage LISP, qui datent des années 1970. Elles étaient capables d’exécuter certaines fonctions de base du langage directement dans leurs circuits : elles possédaient notamment un ''garbage collector'' câblé dans ses circuits ainsi que des instructions machines supportant un typage déterminé à l’exécution. Les processeurs dédiés ont eu leur heure de gloire au début de l'informatique, à une époque où les langages de haut niveau venaient d'être inventés. À cette époque, les compilateurs n'étaient pas performants et ne savaient pas bien optimiser le code machine. Il était alors rationnel, pour l'époque, de rapprocher le code machine cible et le langage de programmation de haut niveau. De nombreuses architectures dédiés ont ainsi été inventées, avant que les concepteurs se rendent compte des défauts de cette approche. Les défauts en question ne sont pas nombreux, mais assez simples à comprendre. Premièrement, elles sont très rapides pour un langage de programmation en particulier, mais sont assez mauvaises pour les autres, d'où un problème de "compatibilité". Ajoutons à cela que les langages de programmation peuvent évoluer, devenir de moins en moins populaires/utilisés, ce qui rend la création d'architectures généralistes plus pertinente. Enfin, les architectures dédiées sont évidemment des processeurs CISC, pour implémenter les nombreuses fonctionnalités des langages évolués. Et les défauts des CISC sont assez rédhibitoires à l'heure actuelle. À l'heure actuelle, les algorithmes des compilateurs se sont améliorés et savent nettement mieux utiliser le matériel. Ils produisent du code machine efficace, ce qui rend les architecture dédiées bien moins intéressantes. Si on ajoute les défauts de ces architectures dédiées, par étonnant que les architectures dédiées aient presque disparues. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les coprocesseurs : FPU et IO | prevText=Les coprocesseurs : FPU et IO | next=Les processeurs de traitement du signal | nextText=Les processeurs de traitement du signal }} </noinclude> lpm621nmtoc5xj38jani94dgfek8qad 772103 772082 2026-09-12T21:58:51Z DavidL 1746 /* L'ALU de taille variable */ 772103 wikitext text/x-wiki De nos jours, la majorité des programmeurs programment dans des langages de haut niveau. Il est très rare pour eux d'avoir à utiliser de l'assembleur, et encore moins un langage machine. Les programmes écrits dans un langage de haut niveau sont traduits en langage machine par un logiciel appelé le compilateur. [[File:Compilation.PNG|centre|vignette|upright=2.5|Compilateur : principe.]] Il se trouve que quelques rares processeurs sont conçus pour faciliter le travail du compilateur. Et ce sont ces processeurs que nous allons voir dans ce qui suit. Ils représentent une catégorie de jeux d'instruction à part, qui n'a pas vraiment de nom. ==La compilation et l’interprétation== Un compilateur traduit donc du code source, écrit dans un langage de haut niveau, vers du langage machine. La traduction est rarement directe. En général, le compilateur traduit le code source en assembleur, qui est lui-même traduit en langage machine. L'assembleur est une représentation textuelle du langage machine alors que le code machine est du binaire exécutable par le processeur. La traduction se fait donc en deux étapes, la '''compilation''' proprement dite et l''''assemblage''', réalisées respectivement par un compilateur et un assembleur. Il faut parfois rajouter une troisième phase d'édition des liens, que nous passons volontairement sous silence. {| |[[File:Code C.png|vignette|200px|Le code source, ici en C.]] |[[File:Assem.png|vignette|250px|Le code assembleur.]] |[[File:Binary file - hello world (C programming).png|vignette|150px|Le code machine.]] |} ===L'interprétation et la compilation à la volée=== Une alternative à la compilation est l''''interprétation''', qui transforme le code source en code machine à la volée. Avec l'interprétation, le code source est passé à un logiciel appelé l''''interpréteur''', qui exécute le code source ligne de code par ligne de code. Une ligne de code est traduite en code machine, qui est exécutée, puis l'interpréteur passe à la ligne suivante. [[File:Kaantotulkkaus.png|centre|vignette|upright=3|Compilation versus interprétation.]] Un défaut de l'interprétation est son cout en performance, qui est assez important. Aussi, l'interprétation stricte a évolué vers un hybride entre interprétation et compilation. L'idée est qu'une partie peu importante du code source est interprétée, alors que le code important est compilé juste avant d'être exécuté. Pour le dire autrement, le code source est partiellement compilé à la volée, juste avant son exécution. Aussi, on parle de '''compilation à la volée'''. Le terme en anglais est ''Just In Time compilation'', abrévié en JIT. En soi, le JIT est associé à de l'interprétation, les JIT sont en réalité des hybrides interpréteurs-compilateurs. Un point important est que compiler du code à la volée est assez lourd, cela a un cout en performance. Par contre, le code compilé s'exécute plus vite que du code interprété. Si on exécute le code compilé une seule fois, le cout de la compilation l'emporte sur le gain à l'exécution. Mais le code compilé est réutilisé autant de fois que nécessaire. Le gain à l'exécution est donc multiplié par le nombre d'exécutions, alors que le cout de la compilation est répartit sur plusieurs exécutions, il est amorti. Les portions du code sont choisies de manière à avoir un gain en performance maximal. L'idée générale est que le code exécuté très souvent est compilé, alors que du code exécuté pas souvent est interprété. Typiquement, les boucles les plus souvent exécutées sont compilées, le code exécuté une seule fois est interprété. ===Les langages intermédiaires=== Les compilateurs modernes passent par un '''langage intermédiaire''' pour faire la transformation en code machine. Le compilateur traduit le langage de haut niveau en langage intermédiaire, puis traduit le langage intermédiaire en code machine cible. Le langage intermédiaire est parfois appelé le '''''bytecode''''', et ce terme recouvre aussi le code écrit avec du ''bytecode''. L'interprétation aussi peut passer par l'intermédiaire d'un un ''bytecode'', ce n'est pas limité aux compilateurs proprement dit. {| |[[File:Intermediate representation scheme.png|centre|vignette|upright=1.5|Représentation intermédiaire d'un compilateur.]] |[[File:Code interpreter scheme.png|centre|vignette|upright=1.5|Fonctionnement d'un interpréteur.]] |} Faire ainsi a de nombreux avantages, le principal étant d'avoir un compilateur capable de traduire un langage de haut niveau vers plusieurs jeux d'instructions différents. Cela permet d'avoir, par exemple, un compilateur qui traduit du C soit en code machine x86, soit en code machine pour un CPU ARM, soit pour un CPU POWERPC, etc. [[File:Compiler design.svg|centre|vignette|upright=3|Compiler design]] Pour l'interprétation, l'usage d'un ''bytecode'' a d'autres avantages. Pour l'exploiter, il faut distribuer non pas le code source, mais le ''bytecode''. En clair, l'interpréteur ne prend pas en entrée le code source, mais du ''bytecode'' déjà compilé. La traduction est alors beaucoup plus simple, car le code source a déjà été partiellement compilé, par la traduction en ''bytecode''. Interpréter du code source est en effet assez compliqué : il faut effectuer des étapes d'analyse lexicale, sémantique, et bien d'autres. Avec du ''bytecode'', ces étapes ont été réalisées lors de la compilation du ''bytecode'', l'interpréteur a alors peut de choses à faire. L'interprétation du ''bytecode'' se fait instruction par instruction, au niveau du ''bytecode''. Une instruction du ''bytecode'' est traduite en une instruction machine équivalente, qui est exécutée. Si l'instruction est un peu complexe, il exécute une fonction/procédure qui fait la même chose. Pour résumer, le ''bytecode'' est ensuite traduit à la volée et exécuté instruction par instruction par un logiciel appelé l'interpréteur. [[File:Control table.png|centre|vignette|upright=2|Control table]] Le langage intermédiaire peut être vu comme l'assembleur d'un processeur, n'existe pas forcément dans la réalité, mais dont le jeu d'instruction est décrit en détail. Le processeur en question est appelé une '''machine abstraite''', ou encore une ''machine virtuelle''. Nous utiliserons le terme de machine abstraite dans ce qui suit. La machine abstraite n'est pas la même suivant que l'on cible la compilation ou l'interprétation/JIT. Pour l'interprétation/JIT, la machine abstraite est souvent une machine à pile, car cela simplifie grandement la traduction en code machine final. L'interprétation demande que la traduction du ''bytecode'' en code machine soit la plus simple possible. Et cela demande de prendre en compte pas mal de détails. Par exemple, les différents jeux d'instruction existants n'ont pas le même nombre de registres, ce qui pose problème lors de la traduction du ''bytecode''. Lors de la transformation en code machine, un algorithme d'allocation de registres se débrouille pour traduire le code intermédiaire en code qui utilise un nombre limité de registres. Pour améliorer cette allocation de registres, il y a deux solutions niveau ''bytecode'' : soit utiliser un nombre illimité de registres, soit utiliser une machine à pile. Pour les machines à pile, il existe un algorithme simple et rapide pour traduire un code écrit pour une machine à pile en un code écrit pour un processeur avec des registres, qui se débrouille pas trop mal pour allouer efficacement les registres. C'est un avantage assez important pour les langages interprétés. ==Les processeurs qui exécutent du bytecode== Le ''bytecode'' est un code machine, ce qui signifie qu'il peut en théorie s'exécuter sur un processeur qui implémente le jeu d’instruction associé. Si le jeu d'instruction d'un ''bytecode'' est souvent une description censée être fictive, elle n'en reste pas moins un jeu d'instruction et des caractéristiques précises, qu'on peut l'implémenter en matériel ! Néanmoins, tous les ''bytecode'' ne sont pas égaux de ce point de vue. Certains sont faciles à implémenter en matériel, d'autres non. Les ''bytecodes'' implémentés en matériel sont ceux dont les machines abstraites sont des machines à pile. Un premier exemple est celui des processeurs Pascal MicroEngine, qui exécutaient directement le bytecode du langage Pascal, le fameux UCSD P-code. Un second exemple est la '''machine SECD''', qui sert de langage intermédiaire pour certains compilateurs de langages fonctionnels. Elle a été implémentée en matériel par plusieurs équipes, notamment par les chercheurs de l'université de Calgary en 1989. Dans le même genre, quelques processeurs simples étaient capables d’exécuter directement le ''bytecode'' du langage FORTH. Le FORTH, un des premiers langages à pile de haut niveau, possède de nombreuses implémentations hardware et est un des rares langages de haut niveau dont le ''bytecode'' a été utilisé comme langage machine sur certains processeurs. Par exemple, on peut citer le processeur FC16, capable d’exécuter nativement du ''bytecode'' FORTH. ===Les processeurs Java=== Le cas le plus impressionnant est celui de la machine virtuelle Java, qui est un design de processeur comme un autre. En temps normal, le ''bytecode'' Java est compilé ou interprété, mais certains processeurs exécutaient du ''bytecode'' Java directement, sans interprétation ni compilation. Ils sont appelés des '''processeurs Java'''. On peut citer les processeurs ARM disposant de l'extension Jazelle, du JEMCore et du aJ-100 de aJile Systems, le picoJava II de Sun, et quelques autres. Il y a aussi eu quelques projets de recherche ou processeurs open source, comme Komodo, jamuth, le ''Java Optimized Processor'' et quelques autres projets du même genre. L'implémentation de la machine virtuelle Java n'était cependant pas complète. Quelques instructions complexes n'étaient pas gérées par le processeur et devaient être émulées en logiciel. Mais la grosse majorité des instructions l'était. Les instructions non-supportées étaient émulées avec la méthode ''trap and emulate'', à savoir qu'un opcode inconnu déclenchait une exception matérielle ''opcode invalide'', dont la routine pouvait émuler les instructions qui doivent l'être. Le processeur aJ-100 de aJile est capable d'exécuter la quasi-totalité des instructions de la JVM Java, seules deux instructions faisant exception. Les '''accélérateurs Java''' sont une solution intermédiaire, qui permet de traduire à la volée du ''bytecode'' Java en instructions RISC, exécutées sur un autre processeur. Il s'agit formellement de traduction binaire, mais je préfère en parler ici. L'idée est de combiner un processeur RISC avec un coprocesseur Java. Le coprocesseur lit le ''bytecode'' Java et le traduit en instructions RISC, ces dernières étant exécutées sur le processeur RISC. Le JA108 de Nozomi était un coprocesseur de ce genre, au même titre que le coprocesseur JSTAR de JEDI. L'extension Jazelle de certains CPU ARM fonctionnait vraisemblablement sur un principe similaire, sauf que le coprocesseur était intégré dans le processeur ARM, entre le cache d'instruction et le décodeur d'instructions ARM. L'intérêt des processeurs Java n'est pas qu'une question de performance. Certes, ils permettent d’exécuter plus vite les programmes compilés en ''bytecode'', comme des programmes Java pour la JVM Java. Mais l'intérêt est aussi de faire des économies de mémoire RAM et ROM. Je rappelle que la machine virtuelle Java est une machine à pile, ce qui fait que sa densité de code est excellente. Les programmes en ''bytecode'' Java sont donc très petits, et prennent peu de place en mémoire ROM. De plus, utiliser un processeur Java permet de se passer d'interpréteur ou de JIT Java, ce qui économise encore plus de mémoire. ===Transformer un processeur RISC en machine à pile=== La plupart des processeurs Java utilisent en interne une architecture à registre généraux, qui émule une machine à registre en microcode. Quelques registres sont réservés pour l'état de la machine virtuelle, avec au minimum un registre réservé pour le pointeur de pile, un autre pour un pointeur vers un ''pool'' de constantes, et quelques autres. D'autres registres servent à mémoriser le haut de la pile, à savoir le sommet de la pile et quelques opérandes situées juste en-dessous. Par exemple, le processeur picoJava II gardait les 64 opérandes au sommet de la pile dans 64 registres généraux, séparés des registres pour les pointeurs et l'état de la JVM. Une optimisation possible, envisagée sur les processeurs picoJava, était une sorte de macro-fusion sous stéroïde. L'idée était de fusionner certaines séries d'instructions Java en une seule instruction machine. Typiquement, pour faire une opération arithmétique, une machine à pile empile deux opérandes et exécute une opération, ce qui prend trois instructions machine. La spécification picoJava 1 a proposé d'envoyer directement la seconde opérande en entrée de l'ALU, ce qui fusionnait l'empilement de la seconde opérande et l'opération arithmétique. Le processeur picoJava II va plus loin et fusionne les trois instructions en une seule instruction RISC, agissant sur des registres. Mais la majorité des processeurs Java ne faisaient pas cela, car cela complexifie grandement le décodeur. Les processeurs ''bigfoot'' de DCT utilisaient un système différent pour émuler une pile avec des registres. Leur banc de registre de 64 bits était coupé en deux : les 16 premiers registres étaient utilisés pour la pile, les 48 suivants étaient utilisés pour autre chose. L'idée est que le registre 0 mémorise un emplacement vide, le registre 1 contient le sommet de la pile, le registre 2 l'opérande sous le sommet de la pile, et ainsi de suite. Les 15 premières opérandes de la pile sont donc mémorisées dans les registres. Les instructions écrivent leur résultat dans le registre adéquat, puis tous les registres sont décalés pour que le résultat passe dans le registre R1. Par exemple, les instructions PUSH chargent une opérande dans le registre 0, puis tous les registres sont décalés de un rang, pour que l'opérande chargée soit dans le registre 1. Le registre 0 devient alors le registre numéro 1, le registre 1 devient le 2, et ainsi de suite. Par contre, les opérations arithmétiques font autrement. Une instruction d'addition, par exemple, lit les opérandes dans le registre 1 et 2, puis place son résultat dans le registre 2 (les deux opérandes sont dépilées). Puis, les registres sont décalés d'un rang pour que ce registre 2 devienne le 1. Les registres ne sont en réalité pas décalés, il n'y a pas de transferts entre registres. A la place, les 16 premiers registres utilisaient une forme limitée de renommage de registres, similaire au banc de registre tournant utilisé sur les processeurs EPIC comme l'Itanium. Les numéros de registres sont renommés, décalés, à chaque fois qu'on empile ou dépile une opérande. Pour faire le renommage de registres, processeur contient un ''register stack counter'' de 4 bits, qui est incrémenté à chaque fois qu'on empile une donnée, et est décrémenté quand on dépile une donnée. Quand on veut accéder à un opérande, le numéro de registre architectural associé est traduit en numéro de registre physique, en additionnant le ''register stack counter'' (modulo 16, pour rester sur 4 bits). ==L'accélération de l'interprétation/JIT : le ''Thumb-EE'' d'ARM== Quelques processeurs ont ajouté des instructions pour faciliter le travail des interpréteurs/JIT. Par exemple, en 2005, ARM a ajouté le mode ''Thumb Execution Environment'', qui faisait cela. Il reprenait le jeu d'instruction compact ''thumb'' et ajoutait quelques instructions et modifiait le comportement d'instructions existantes. Le jeu d'instruction ''Thumb-EE'' a été ajouté sur les CPU ARM en 2005, mais a été déprécié en 2011, par manque d'utilité. Mais la tentative mérite qu'on s'attarde dessus. Les CPU de gamme M, déstinés à l'embarqué, n'ont jamais supporté ''Thumb-EE'', vu que de tels processeurs ne sont pas conçus pour exécuter du code interprété/JIT. Le mode ''Thumb-EE'' est un mode d'exécution, séparé de l'ARM normal. Ainsi, une instruction ''Thumb-EE'' et une instruction ARM peuvent avoir le même encodage en binaire, mais se comporter différemment. Le processeur est à tout moment soit en mode ''Thumb-EE'', soit en mode ARM normal, ce qui précise comment ces instructions doivent se comporter. Des instructions ont été ajoutées par ''Thumb-EE'', pour qu'il fasse son travail. L'entrée et la sortie du mode ''Thumb-EE'' se fait avec deux instructions : ENTERX et LEAVEX. Une fois en mode ''Thumb-EE'', le décodage des instructions ''thumb'' se fait avec les règles du ''Thumb-EE'', et non celles du ''thumb'' normal. Une première différence entre ''thumb'' normal et ''Thumb-EE'' est l'ajout de ce qui s'appelle un ''null check'' pour les instructions mémoire. Le ''null check'' est utilisé pour les instructions en mode d'adressage "base + indice" ou "Base + décalage", ou tout autre mode d'adressage avec un registre de base utilisés dans des calculs d'adresse. L'idée est de vérifier si l'adresse de base vaut zéro ou non. Si c'est le cas, le processeur lève une exception matérielle, qui est traitée par l'interprétation ou le compilateur JIT. Une telle situation est en effet signe d'une erreur d'adressage mémoire, qui doit être traitée par l'interpréteur. Typiquement, c'est signe qu'un pointeur n'a pas bien été initialisé, ce qui peut arriver avec du code interprété ou JIT. Les interpréteurs/JIT traitent généralement la situation en ajoutant un test avant toute instruction mémoire, pour vérifier si le pointeur accédé vaut zéro ou non. Avec ''Thumb-EE'', pas besoin d'ajouter les tests en questions : ils sont réalisés automatiquement lors de chaque instruction mémoire. : Les registres pour la pile, comme le pointeur de pile et le pointeur de ''frame'', sont aussi concernés. L'instruction CHKA vérifie que les accès à un tableau ne débordent pas en dehors du tableau en question. Par exemple, pour un tableau de 1024 éléments, elle vérifie si l'indice est compris entre 0 et 1024. Pour cela, elle vérifie si l'indice de tableau est bien dans l'intervalle adéquat et lève une exception matérielle si ce n'est pas le cas. Son utilité se comprend quand on sait que tous les accès à un tableau sont vérifiés par l'interpréteur. L'interpréteur est censé ajouter des instructions pour vérifier les indices, à savoir deux ou trois branchements. Avec CHKA, le test se fait en une seule instruction. D'autres modifications mineures de l'encodage des instructions sont aussi présentes, ainsi que des modifications pour les instructions LOAD/STORE. Précisément, dans les modes "base + indice" et "base + décalage", le décalage et l'indice subissent maintenant des décalages. L'idée est de simplifier le calcul d'adresse. De quoi économiser quelques instructions lors des calculs d'adresse, ce qui facilite le travail de l'interpréteur/JIT. Et des instructions LOAD/STORE précises voient leur comportement modifié pour faciliter la gestion de la pile de Java ou l'exécution des méthodes locales. Pour faciliter le travail de l'interpréteur, deux instructions HBP et HBLP ont été ajoutées. Elles branchent vers une fonction qui gère les exceptions logicielles (une fonctionnalité présente dans de nombreux langages, comme Java). La première effectue un branchement vers la fonction en question, la seconde sauvegarde l'adresse de retour avant de faire ce branchement. Les deux peuvent brancher vers 256 fonctions pré-déterminées, sans avoir à présenter leur adresse. ==La traduction binaire accélérée par le matériel== Plus haut, nous avons surtout parlé des compilateurs et des interpréteurs. Cependant, nous devons aussi parler de la '''traduction binaire'''. Elle traduit un programme écrit dans un code machine vers un autre code machine. Par exemple, elle traduit un programme compilé pour un CPU x86 vers un code machine ARM. En général, le système d'exploitation est généralement compilé pour le jeu d'instruction natif, mais il exécute des applications prévues pour le x86. Les applications sont traduites par le système d'exploitation, avant d'exécuter le code traduit. : Nous parlerons dans la suite de code machine source et de code machine cible, pour parler respectivement du code à traduire et du code obtenu après traduction. Idem avec d'autres termes comme architecture cible/source, ou jeu d'instruction cible/source. La traduction binaire est surtout utilisée pour des questions d'émulation ou de compatibilité. Par exemple, lorsque les Macintosh sont passés de processeurs Power PC vers des processeurs x86, le système d'exploitation Mac OS utilisait la traduction binaire pour convertir les anciennes applications Power PC vers du code x86. Les utilisateurs n'y ont vu que du feu. Le système de traduction binaire était appelé Rosetta 1. Par la suite, lors de la transition de processeurs x86 vers des processeurs Apple, Rosetta 2 a vu le jour. La traduction binaire a surtout été utilisée pour traduire du code x86 vers un autre jeu d'instruction. Il faut dire que le x86 est le jeu d'instruction dominant. De nombreuses entreprises ont eu pour ambition de briser l'hégémonie du x86 sur PC, en remplaçant le x86 par un jeu d'instruction plus performant, tout en gardant une compatibilité maximale. La traduction binaire était la seule solution pratique. Elle était le plus souvent intégralement réalisée en logiciel, comme c'était le cas sur les architectures Itanium avec le ''IA-32 Execution Layer''. ===Les généralités sur la traduction binaire assistée en matériel=== L'architecture source est presque tout le temps une architecture CISC, assez ancienne, qu'on souhaite émuler. Le choix de l'architecture cible se porte souvent sur une architecture VLIW, fort différente de l'architecture source, et ce pour obtenir une économie de matériel conséquente. Pour s'exécuter rapidement, le code traduit doit exploiter le parallélisme d'instruction, à savoir exécuter plusieurs instructions en même temps dans des unités de calcul séparées. Il est possible d'utiliser un processeur superscalaire avec exécution dans le désordre pour cela, mais au prix d'un cout important en transistors. Alors qu'en utilisant un CPU VLIW, c'est le traducteur binaire qui fait tout le travail d'extraction du parallélisme d'instruction. Et après tout, quitte à avoir un traducteur binaire, autant lui refiler le boulot d'optimisation. Compiler du code à la volée est certes assez lourd, mais qu'il existe des algorithmes efficaces pour regrouper des instructions indépendantes dans une seule instruction VLIW. Au passage, le processeur VLIW a plus de registres que le processeur source. Cela permet de faire du renommage de registres directement en logiciel. Le traducteur binaire n'hésite pas à changer les noms de registres entre instructions source et instruction VLIW cible, afin de supprimer des dépendances de données. En conséquence, cela ouvre des opportunités de parallélisme, qui sont exploitées lors du regroupement des opérations en instructions VLIW. Vous pourriez penser que le choix d'un CPU VLIW pour émuler du CISC est tout sauf optimal. Vous devez penser que la traduction binaire est d'autant plus simple que l'architecture source et cibles sont semblables. Dans les faits, ce n'est pas tellement traduire les instructions qui pose problème, mais plus la gestion du registre d'état, des exceptions matérielles, de la mémoire virtuelle, la différence entre gros-boutisme et petit-boutisme, de même que des différences d'adressage pour les périphériques. Le premier problème est la gestion des conditions, notamment en présence d'un registre d'état. En pratique, la traduction binaire s'utilise pour traduire du code CISC vers du code RISC ou VLIW. Les architectures source ont donc un registre d'état, qui est mis à jour non seulement par des instructions de test, mais aussi des instructions arithmétiques. L'architecture cible n'a elle pas de registre d'état, mais des registres à prédicats. La traduction de l'un vers l'autre est alors quelque peu compliquée. Et elle est d'autant plus compliquée que le registre d'état est la source de dépendances d'instruction implicites, qui réduisent les performances. Par exemple, si une instruction arithmétique modifie le registre d'état, cela peut impacter l'exécution d'une instruction ultérieure, qui lit ce registre d'état. Pour éliminer ces fausses dépendances, le traducteur binaire doit renommer ce registre en logiciel et détecter les dépendances utiles. Et le compilateur doit gérer les cas où il y a beaucoup de distance entre les deux, voire les cas où l'instruction dépendante n'a pas encore été analysée par le compilateur. Un autre problème est lié à la gestion des exceptions matérielles, et précisément des exceptions précises. Pour rappel, une instruction VLIW regroupe plusieurs opérations, opérations qui correspondraient à une instruction machine sur un CPU pas VLIW. En conséquence, plusieurs instructions du langage machine "source" sont regroupées en une seule instruction VLIW. Et il faut tenir compte du cas où une instruction source lève une exception. Dans le code VLIW, cela signifie qu'une opération lève une exception, et il faut annuler partiellement l'instruction VLIW associée. Et par partiellement, on veut dire que seules les opérations suivantes dans l'ordre du programme source doivent être annulées, puis ré-exécutées. Et c'est un sacré casse-tête ! Les processeurs VLIW utilisent comme solution le mécanisme d'exceptions différées des processeurs EPIC, vu il y a quelques chapitres. Pour résumer, le code est exécuté par blocs d'instruction, délimités par des branchements ou tout autre limite/barrière pertinente dans le code. Un bloc de code est compilé en deux versions : une version rapide sans exceptions matérielles, une version lente qui gère les exceptions précises. La version rapide s'exécute sans exécuter les exceptions. Cependant, les exceptions matérielles sont enregistrées, pour être prises en compte à la toute fin du bloc de code. La version rapide est exécutée en premier et elle mémorise si une exception matérielle a eu lieu. Puis une instruction vérifie si une exception a eu lieu et décide quoi faire. Si aucune exception n'a eu lieu, elle passe à la suite du programme, les résultats du bloc de code sont définitivement acceptés. Mais si une exception a eu lieu, tout est annulé. Le processeur est remis dans l'état initial, puis le code est ré-exécuté instruction par instruction de manière à gérer l'exception correctement. ===La traduction par pré-décodage=== Une première solution serait de faire la traduction binaire dans le cache d'instruction. Lors d'un défaut de cache, le code chargé depuis la RAM est traduit en code machine cible. Et c'est ce code machine cible qui est mémorisé dans le cache d'instruction et exécuté par le processeur. La technique marche sur le papier et n'est qu'une amélioration des techniques de pré-décodage vues il y a quelques chapitres. Cependant, le code obtenu est une traduction assez basique, qui n'incorpore pas d'optimisations dignes de ce nom. De plus, elle gère mal le cas où la taille du code source et cible sont potentiellement très différentes. Concrètement, elle est surtout utile pour traduire du code d'un processeur RISC vers un autre processeur RISC, dont les tailles d'instructions sont similaires. Elle ne permet pas d'émuler plusieurs jeux d'instructions différents, le cout en matériel (un circuit de pré-décodage par jeu d'instruction) serait trop important. ===Le projet DAISY d'IBM=== De très rares processeurs étaient conçus pour accélérer cette traduction binaire, afin de garder de bonnes performances. Les premiers à avoir étudié l'idée étaient IBM, avec leur projet DAISY (''Dynamically Architected Instruction Set from Yorktown''). Le projet de base était de convertir à la volée du code compilé pour des CPU Power PC, vers du code VLIW. Les chercheurs d'IBM avaient développé un algorithme de traduction dynamique efficace, ainsi qu'un processeur VLIW disposant d'optimisations spécifiques à la traduction binaire dynamique, à la volée. De nombreuses idées de ce projet ont été reprises ou re-découvertes par la société Transmetta, avec ses processeurs Crusoe et Efficieon, puis par NVIDIA avec son projet Denver. Les ingénieurs de ce projet ont étudié la possibilité d'émuler plusieurs jeux d'instructions différents sur un même processeur, notamment le s390 d'IBM et le x86. En théorie, cela demande juste d'avoir plusieurs programmes de traduction binaire : un pour le x86, un autre pour le s390, éventuellement un autre pour le Power PC. Mais cela ne s'est pas concrétisé. Mais les ingénieurs ont étudié quelle pourrait être l'architecture VLIW idéale pour ça. Par exemple, il fallait des additions 3-opérandes pour simplifier les calculs d'adresse. Une difficulté était la gestion du registre d'état, dont les bits ne sont pas mis à jour de la même manière sur le x86 et le s390 ou le Power PC. La différence entre gros-boutisme et petit-boutisme était aussi un problème, de même que des différences d'adressage pour les périphériques. Pour que la traduction binaire soit efficace, le processeur VLIW intègre diverses optimisations, comme les exceptions différées et les branchements multi-voies. La principale est la suivante : seul le code des boucles ou fonctions exécutées fréquemment est traduit en code VLIW, le reste du code est interprété. En effet, traduire du code binaire prend plus de temps qu'une simple interprétation. Pour du code qui ne sera exécutée qu'une seule fois, il est plus rapide d'utiliser l'interprétation. Par contre, pour du code exécuté beaucoup de fois, le cout de la traduction binaire est amorti, dilué sur N exécutions, compensé par le gain en temps d'exécution de ce code traduit. Au final, cela permet de ne traduire que le code qui le mérite. La détection du code fréquemment exécuté est réalisée dans le cœur VLIW. L'unité de branchement mémorise les derniers branchements rencontrés et le nombre de fois qu'ils ont été exécutés. Si ils ont été exécutés un certain nombre de fois, l'unité de branchement lève une exception matérielle, qui invoque le traducteur binaire. La routine de cette exception est le traducteur binaire proprement dit. En clair, la traduction binaire est démarrée quand le processeur détecte qu'une fonction a été exécutée plus de N fois, via une exception matérielle dédiée. La mesure du nombre d'exécution d'un branchement se fait dans l'unité de calcul dédiée aux branchements, avec l'aide d'une sorte de ''branch adress buffer'' modifié. Pour rappel, le ''branch adress buffer'' mémorise le ''Program counter'' de chaque branchement récemment rencontré. Ici, chaque entrée du ''branch adress buffer'' est associée à un compteur incrémenté à chaque exécution du branchement. ===Les processeurs Crusoe et Efficieon de Transmetta=== Les processeurs Crusoe Et Efficeron sont deux processeurs VLIW produits par la société Transmetta, une société californienne rachetée par NVIDIA. Ils étaient conçus pour exécuter spécifiquement des programmes x86, système d'exploitation inclus. L'idée derrière ce projet était d'exécuter du code x86 sans que les applications, ni même le système d'exploitation et le BIOS soient au courant ! Les processeurs Transmetta étaient en réalité conçus pour exécuter un programme unique, le ''Code Morphing Software'' (CMS), qui traduisait le code x86 en code VLIW. Transmetta ne voulait pas que son processeur VLIW soit exploité directement, sans le CMS. Il n'avait pas rendu public de compilateur pour traduire du C vers du code VLIW, il n'avait pas donné la documentation du jeu d'instruction VLIW. Des efforts de rétro-ingénieurie, documentés sur le site realworldtech, ont cependant permis de comprendre comment étaient encodées les instructions du processeur Crusoe. Comme pour le projet Daisy, le ''Code Morphing Software'' utilisait à la fois interprétation et traduction binaire, selon les besoins. Les instructions sont interprétées lors de leurs premières exécutions, mais le CMS bascule sur de la traduction en code VLIW après un certain nombre d'exécution. Ainsi, les boucles souvent exécutées sont traduites en code VLIW, alors que le reste du code est interprété. Le choix du code à traduire est le fait du CMS, il utilise des heuristiques complexes pour, qui ne sont pas connues dans le détail. Le ''Code Morphing Software'' est mémorisé dans une EEPROM, ce qui en fait un ''firmware'' situé en dessous du BIOS. Le CMS démarre ensuite le BIOS, qui lui-même démarre le système d'exploitation, qui lui-même démarre les pilotes de périphériques et les programmes. Le CMS se réserve les 16 premiers mébioctets de l'espace d'adressage. L'EEPROM du CMS est mappée dedans, mais n'en utilise que la moitié. Le reste est utilisé comme cache, pour mémoriser le code VLIW traduit par le CMS. Les deux processeurs intégraient aussi deux mémoires SRAM, utilisées par le CMS, appelées la ''local program memory'' (LPM) et la ''local data memory'' (LDM). La première contient du code qui gére les interruptions, la mémoire virtuelle, les exceptions matérielles, les problèmes d'alignement mémoire, et quelques fonctions très fréquemment utilisées par le CMS. La seconde est de la mémoire RAM utilisée par ces fonctions de la ''local program memory''. Les mémoires caches L1 et L2 sont séparées de ces deux mémoires. Le processeur Crusoe et Efficieon étaient des processeurs VLIW très simples. Ils n'avaient même pas de MMU, ni de fonctionnalités importantes sur les CPU x86. Pour Crusoe, les instructions VLIW étaient encodées sur 64 ou 128 bits, et regroupaient entre 2 à 4 opérations. Les instructions LOAD/STORE ne supportaient pas d'adressage indicé, juste de l'adressage indirect à registre. Crusoe avait 5 unités de calcul : deux ALU entières, une unité LOAD/STORE, une unité de branchement, une FPU. Efficieon doublait le nombre d'ALU entière et d'unité LOAD/STORE, les instructions VLIW passaient à 256 bits. Le processeur Crusoe contient 160 registres, dont 64 registres généraux, 32 registres flottants. Les registres généraux font 32 bits, ce qui est cohérent avec le fait que les CPU x86 de l'époque étaient des processeurs 32 bits. Quant aux registres flottants, ils faisaient 80 bits, ce qui colle avec la taille des registres flottants de la FPU x87 utilisée à l'époque. Sur les 64 registres généraux, seuls 48 étaient réellement utilisable pour mémoriser des opérandes. Une partie des registres généraux étaient utilisés pour la gestion de la pile, d'autres pour mémoriser l'état du CPU x86 émulé, un registre était un registre zéro non accesible en écriture. La gestion des exceptions est optimisée avec un système d'exceptions différées, le même que celui décrit plus haut. Le processeur utilise un système similaire, pour effectuer des lectures anticipées, qui a été expliqué dans le chapitre sur les processeurs VLIW/EPIC. Sauf qu'il s'agit là d'une optimisation pour gagner en performances en général, pas une aide utile pour gérer des exceptions précises ou toute autre subtilité de la traduction binaire. Pour gérer les exceptions différées et les lectures anticipées, le processeur mémorise l'état du processeur avant de démarrer un bloc de code. Pour cela, le processeur contient des ''shadow registers'', 48 registres entiers et 16 registres flottants. Vous remarquerez qu'il y a autant de registres entiers que de ''shadow registers'' entiers. Les registres entiers/flottants sont mémorisés dans les ''shadow registers'' avant d'exécuter un bloc de code, afin que le processeur puisse revenir à l'état de base. Une autre fonctionnalité liée est le ''gated store buffer''. Le principe est d'éviter toute écriture en mémoire RAM, tant que le code VLIW n'a pas émis d'instruction ''commit''. L'idée est que les écritures sont conservées dans la ''store queue'' de l'unité LOAD/STORE. Pour rappel, la ''store queue'' met en attente les écritures soit tant que les écritures ne sont pas terminées, soit tant que la RAM est occupée. L'idée est que les écritures sont accumulées dans la ''store queue'' tant que l'instruction ''commit'' n'a pas eu lieu. Le ''store queue'' est "déversé dans la RAM" seulement quand l'instruction ''commit'' s'exécute. ===Les CPU NVIDIA Denver=== Nvidia a tenté quelque chose de similaire avec son projet Denver. NVIDIA a racheté l'entreprise Transmetta, ses brevets, et a tenté de refaire la même chose. Le projet initial était de traduire du code x86 vers un jeu d'instruction VLIW propriétaire, comme l'a fait Transmetta. Mais NVIDIA n'a pas réussi à acquérir la licence du jeu d'instruction x86 et s'est rabattu sur le jeu d'instruction ARM. Le processeur né de ce projet est le Tegra K1-64 CPU. Il s'agit d'un processeur composé d'un cœur VLIW, couplé à deux décodeurs d'instructions ARM. Les deux décodeurs ARM traduisent une paire d'instructions ARM consécutives en instructions VLIW, pour les exécuter sur le cœur VLIW. Le CPU peut fonctionner selon deux modes : ARM et VLIW. En somme, le processeur supporte deux jeux d'instruction : le jeu d'instruction ARM, et un jeu d'instruction VLIW. En mode ARM, les instructions ARM sont chargées depuis le cache, traduites en VLIW par les décodeurs ARM, puis exécutées par le cœur VLIW. En mode optimisé, le CPU exécute des instructions VLIW chargées depuis le cache d'instruction, les décodeurs ne sont pas utilisés. : Le CPU supporte en réalité deux jeux d'instruction ARM : ARM8 et 7. Mais ils correspondent au même mode pour le CPU. Un point important est que le processeur peut changer très rapidement de mode, en à peine quelques cycles d'horloges. On n'est clairement pas dans le cas des CPU x86, qui mettent des plombes pour passer du mode 32 à 64 bits et inversement. La commutation est tellement rapide qu'on peut considérer que le processeur supporte deux jeux d'instruction simultanément. Et le support simultané de deux jeux d'instruction facilite l'implémentation de la traduction binaire. Encore une fois, inutile de traduire du code qui ne sera exécutée qu'une seule fois, mieux vaut l'exécuter directement dans le mode ARM. Surtout que le processeur supporte un mode ARM qui permet d'exécuter du code ARM sans perte de performance. Par contre, le code fréquemment utilisé, notamment dans des boucles critiques, est traduit en VLIW. Au final, les performances sont optimisées, en limitant le travail du logiciel traducteur binaire. La détection du code fréquemment exécuté se fait différemment que pour les processeurs Transmetta et Daisy. L'unité de branchement ne détecte pas directement le code beaucoup exécuté, même si elle a un rôle à jouer. A la place, la détection est réalisée en logiciel, par un ''thread'' dédié, qui s'exécute sur un cœur séparé. Il détecte le code fréquemment utilisé en regardent les branchements exécutés récemment. Pour cela, le processeur mémorise l'historique des branchements pris récemment et copie cette historique dans une mémoire tampon dédiée, partagée entre tous les cœurs. Vu qu'elle est partagée, le ''thread'' de détection a accès à l'historique sans pertes de performances, seule la copie de l'historique dans ce tampon a un cout en performance, pas son partage. Le code VLIW obtenu après traduction binaire est mémorisé dans la mémoire RAM, dans une portion spécialement réservée pour. Elle fait 128 mébioctets, et est appelée le '''cache d'optimisation''' par NVIDIA. Le cache d'optimisation est protégé en écriture et seul le traducteur binaire peut écrire dedans. Au passage, le traducteur binaire est du code VLIW, ce qui fait qu'il est placé dans le cache d'optimisation. Le processeur détecte automatiquement quand une fonction pour laquelle le code compilé équivalent est disponible. Pour cela, l'unité de chargement contient une table de correspondance entre l'adresse de la fonction ARM, et l'adresse de son équivalent compilé. Quand une fonction est appelée, l'unité de chargement regarde l'adresse de destination du branchement. Si l'adresse est dans cette table, elle récupère l'adresse de la fonction compilée et branche vers celle-ci. Le processeur dispose d'un cache d'instruction de 128 kibioctets, ce qui est très important, mais nécessaire vu la taille des instructions VLIW. Le coeur VLIW dispose de ses propres décodeurs, d'un ''scoreboard'', de 7 unités de calcul et de registres. Pour les unités de calcul, il a deux FPU, deux ALU, une unité de branchement, et deux unités LOAD-STORE faisant aussi ALU. Un point important est que le CPU dispose de 64 registres entiers et de 64 registres flottants. C'est deux fois plus que supporte le jeu d'instruction ARM. En mode ARM, seule la moitié des registres est utilisée. Mais en mode optimisé, le traducteur binaire utilise bien les 64 registres, grâce à une sorte de renommage de registres logicielle. Pour simplifier la traduction binaire, le processeur supporte les techniques vues précédemment. Le processeur intègre un ''gated store buffer'' similaire à celui des processeurs Transmetta. Les techniques d'exceptions différées sont aussi supportées, comme sur les processeurs Transmetta. Il a aussi une unité de préchargement décrite par NVIDIA comme agressive, avec support du préchargement de type anticipé (''runahead''). ===L'émulation de la mémoire virtuelle=== Pour finir, il faut parler de la mémoire virtuelle avec la traduction binaire. Sur le processeur source, le processeur gère à la fois des adresses physiques et virtuelles et sa MMU fait la conversion entre les deux. Sur le processeur VLIW, la MMU est simulée par le programme de traduction binaire, partiellement ou totalement. L'implémentation exacte varie suivant que l'on parle du projet Daisy, des processeurs Transmetta ou de Denver. Sur les processeurs Transmetta, il n'y a pas de MMU ni de mémoire virtuelle. A la place, le programme de traduction binaire émule la mémoire virtuelle du processeur source. Le processeur VLIW ne gère que des adresses physiques, rien d'autre. L'espace d'adressage physique du processeur VLIW a la même taille que celui du processeur émulé, ici des processeurs x86. Il est vraisemblable que les adresses physiques utilisées par le processeur x86 sont les mêmes que celles du processeur VLIW. Sur le projet Daisy, le processeur VLIW gère la mémoire virtuelle via pagination, comme les processeurs émulés. Ce qui fait qu'il gère un espace d'adressage virtuel et un espace d'adressage physique. Pour éviter toute confusion, nous parlerons d'adresse physique/virtuelle VLIW pour les adresses physiques/virtuelles du processeur VLIW, d'adresse virtuelle/physique source pour celle du jeu d'instruction traduit, à savoir du Power PC ou du s390, éventuellement de l'x86. Il faut alors faire le lien entre adresses physiques source et adresses virtuelles VLIW. Pour cela, rien de plus simple : il y a correspondance parfaite. L'adresse physique source numéro N correspond à l'adresse virtuelle VLIW numéro N. Cependant, cela signifie que tout l'espace d'adressage virtuel VLIW serait utilisé par le code à traduire. En réalité, il faut ajouter de la place pour le code traduit et le programme de traduction binaire. La conséquence est que l'espace d'adressage virtuel VLIW est plus large que l'espace d'adressage source. L'espace d'adressage virtuel VLIW est découpé en trois sections : une section pour le code Power PC à traduire, une autre pour le code traduit en VLIW, et une dernière réservée au traducteur binaire. Le programme de traduction est placé dans une ROM mappée en mémoire dans la seconde section. Le reste de la seconde section est réservé à une mémoire RAM utilisée par le programme de traduction. [[File:Mémoire virtuelle sur le projet Daisy.png|centre|vignette|upright=1.5|Mémoire virtuelle sur le projet Daisy]] Il faut noter que chaque page physique source, une fois traduite, correspond à N pages virtuelles VLIW. La raison est que le code traduit prend plus de place que le code machine originel. En conséquence, on doit utiliser une page finale plus grande. Pour le reste, des pages contiguës en mémoire physique source sont elles aussi contiguës en mémoire virtuelle VLIW. Le calcul d'adresse est donc simple : l'adresse physique source est multipliée par N, puis on ajoute l'adresse de base à laquelle commence la section pour le code traduit. ==La traduction binaire sur les Burroughs B1700== Nous venons de voir comment accélérer en matériel la traduction binaire, avec des techniques bien spécifiques. Le Burroughs B1700 a procédé autrement et il est intéressant d'étudier en détail son architecture. Son architecture est décrite dans le livre "Interpreting Machines : Architecture and Programming of the Bl700/Bl800 Series", écrit par Elliott I. Organick et James A. Hinds. Une partie de ce qui vfa suivre est un très court résumé de ce livre. : Dans ce qui suit, nous parlerons de traducteur binaire pour parler soit d'un interpréteur pour un langage de programmation de haut niveau, soit pour un logiciel de traduction binaire. Le Burroughs 1700 est un processeur 24 bits, qui a cependant la capacité d'émuler des architectures 8, 16 bits assez simplement, via divers mécanismes. Le Burroughs 1700 incorpore de nombreuses optimisations pour cela. Une partie d'entre elles permet de gérer des opérandes de taille différente de 24 bits, d'autres permettent de gérer des instructions de taille différente de 24 bits, d'autres servent pour les deux. Il incorpore aussi des instructions facilitant le découpage des instructions machines en ''opcode'', adresses et constantes immédiates. ===L'ALU de taille variable=== Les Burroughs B1700 avaient une '''ALU de taille variable''', ce qui veut dire qu'elle pouvait faire des calculs sur un nombre de bits compris entre 0 et 24. Pour cela, les calculs étaient faits avec une ALU de 24 bits, puis les bits de poids fort inutiles étaient masqués. L'ALU de 24 bits pouvait masquer les bits de poids fort du résultat, mais avec des limitations. Elle gérait des opérandes et résultats de 0, 4, 8, 12, 16, 20 et 24 bits. Pour avoir un réglage plus fin, une ALU 4 bits séparée permettait de corriger le résultat. Les registres X et Y étaient reliés à une ALU de 24 bits capable d'effectuer des opérations arithmétiques basiques. Fait étonnant, l'ALU faisait tous les calculs en même temps et fournissait ses résultats dans 7 registres : un registre SUM pour l'addition, un registre DIFFERENCE pour la soustraction, et un registre par opération bit à bit. Les registres pour les opérations bit à bit sont : CMPX et CMPY pour l'opération NOT sur chaque opérande, XANY pour le ET bit à bit, XEOY pour le XOR, XORY pour le OU logique. Les additions et soustractions pouvaient se faire sur des opérandes codés en binaire ou en BCD, suivant le code opération utilisé. À cela, il fallait ajouter deux registres de "résultat" MSKX et MSKY. Ils fournissaient un masque dépendant de la taille du résultat en bits. C'est ce registre qui permettait de gérer des données de 0, 4, 8, 12, 16, 20, et 24 bits, alors que l'ALU faisait 24 bits. Le masque dans ce registre pouvait servir d'opérande dans une opération de masquage ultérieure, pour corriger le résultat. L'ALU prenait en opérande les registres X et Y, mais aussi un registre CYF pour la retenue entrante. En sortie, il fournissait aussi deux retenues sortantes : une pour l'addition et une autre pour la soustraction. Elles étaient mémorisées dans les registres CYL et CYD, respectivement. L'ALU fournissait aussi 12 conditions, qui alimentait un registre d'état. Le registre d'état était segmenté en trois registres appelés XYST, XYCN et BICN. Les registres X et Y sont des registres pour les opérandes, mais il y a aussi deux autres registres de 24 bits. Il s'agit des registres T et L, qui sont des registres généraux. Les registres T et L étaient découpés en 6 sous-registres de 4 bits, nommés LA LB LC LD LE et LF pour le registre L, TA TB TC TD TE et TF pour le registre T. Ils étaient adressables comme n'importe quel registre. Le processeur contenait de nombreux autres registres de 4 bits, dont les sous-registres de T et L. En tout, il y a 27 registres de 4 bits adressables ! Et le processeur disposait d'une ALU 4 bits pour manipuler ces registres de 4 bits. L'ALU 4 bits est capable de faire des MOV entre registres de 4 bits, des opérations bit à bit, et peut aussi tester si un bit vaut 0 ou 1. La dernière possibilité est très utile pour implémenter les branchements. De plus, cela permettait de faire des opérations de masquage, notamment pour appliquer un masquage supplémentaire à celui de l'ALU. Par exemple, pour gérer des opérations sur 14 bits, on effectue une opération sur 16 bits avec l'ALU, et on masque les 2 bits manquants avec l'ALU 4 bits. ===Une architecture bit-adressable=== Le CPU Burroughs B1700 était '''bit-adressable'''. En clair, il pouvait adresser la mémoire bit par bit, si nécessaire. Un avantage est que cela facilitait la traduction binaire des instructions machine, mais nous détaillerons cela plus bas. Un autre avantage est que cela permettait d'émuler des architectures dont la taille des registres/''byte''/mots était très différente. Et cet avantage mérite quelques explications immédiates. Le processeur était un CPU 24 bits, mais il pouvait émuler des processeurs 16 bits, 8 bits, 4 bits, 1 bit, 9 bits, ou toute autre valeur. Pour cela, le processeur lisait des mots de 24 bits et utilisant un ''barrel shifter'' pour sélectionner les bits adéquats. Par exemple, pour un accès de 16 bits, la donnée lue en mémoire était masquée de manière à ne garder que les 16 bits de poids faible. Le ''barrel shifter''/circuit de masquage était placé directement avant le bus mémoire, sur le trajet des données/instructions. Le ''barrel shifter'' était commandé par un registre ''Field Unit'', qui précisait quelle était la taille des données à charger. Les instructions source , à traduire, peuvent faire 16 bit avec tel jeu d'instruction, 8 bits avec un autre, 32 bits sur un autre, etc. Elles peuvent aussi être de longueur fixe ou variable ! Le B1700 utilisait une architecture bit-adressable pour gérer ces contraintes. En effet, avec un CPU bit-adressable, les contraintes d'alignement des instructions disparaissent ! ===Des registres d’interfaçage mémoire adressables=== Pour communiquer avec la mémoire, il avait trois registres séparés : READ, WRITE, MAR. READ contient la donnée lue lors d'une lecture, WRITE est pour une donnée à écrire lors d’une écriture, MAR contient l'adresse à lire ou en cours de lecture. Il s'agit de registres d’interfaçage mémoire, les mêmes que ceux vus dans le chapitre sur le chemin de données du CPU. Une instruction LOAD est donc émulée en deux instructions machines : une instruction MOV pour copier l'adresse dans le registre READ, une instruction de lecture proprement dite. L'écriture demande d'ajouter une seconde instruction MOV pour copier la donnée à écrire, et la lecture est remplacée par une écriture. Le fait que ces registres d’interfaçage mémoire et IO soit adressable est peu commun, et c'est plus quelque chose qu'on attend d'un microcode que d'instructions machines. D'ailleurs, l'implémentation des instructions LOAD/STORE ressemble à ce qui est effectué par le séquenceur d'un CPU. Le séquenceur est d'ordinaire celui qui séquence la copie des adresses/données dans les registres d’interfaçage, puis lance la lecture/écriture. Ici, c'est réalisé via des instructions machines. Il faut bien comprendre que les registres d’interfaçage mémoire ont été promus au rang de registres architecturaux, sur ce processeur. De même, pour communiquer avec les entrées-sorties, il disposait de deux registres CMND et DATA : CMND pour envoyer une commande à une entrée-sortie, DATA pour lire ou écrire une donnée. Il y avait aussi un registre U, qui mémorisait une donnée lue depuis le lecteur de cassette. ===Le code machine du Burroughs B1700=== Le processeur utilise des instructions de 16 bits de long, qui sont copiées dans registre d'instruction M de 16 bits. Le ''program counter'' est appelé le registre A. Les instructions du processeur font 16 bits de long, et elles sont alignées en RAM sur 16 bits, ce qui fait que les 4 bits de poids fort de ce registre valent 0, seuls les 14 bits de poids fort sont utiles. Les adresses mentionnées plus haut, qui adressent les micro-opérations en mémoire RAM, sont des adresses de mots de 16 bits, pas les adresses de bit individuels. Fait intéressant, il était possible de faire un OU logique entre l'instruction lue et un registre du processeur, le résultat étant mémorisé dans le registre M. Cela permettait de faire du code automodifiant, pour émuler des modes d'adressage complexe. Cela permettait par exemple de remplacer une adresse dans une micro-opération. L'adresse est alors surimposée avec un OU dans le champ d'adresse, alors que le reste de l'instruction n'est pas modifié. Afin de gérer les interruptions, ces dernières étaient partiellement détectées en logiciel. Une interruption doit être prise en compte à la toute fin de l'exécution d'une instruction source, quand celle-ci a fini son travail. Mais vu qu'ici, les instructions sont émulées avec des séries d'instructions cibles, il y a un problème : il est possible d'interrompre une instruction émulée en plein milieu. Pour éviter cela, le processeur ne déclenche pas les interruptions matérielles immédiatement, elles sont mises en attente. Une instruction dédiée vérifie si une interruption est en attente, et l'exécute alors cas échéant. L'instruction en question est utilisée en dernier, dans la suite d'instruction qui émule l'instruction source. ===La traduction binaire sur le Burroughs B1700=== Les Burroughs B1700 intégraient une pile d'adresse de retour, capable de mémoriser 16 adresses de 24 bits, ainsi que 4 registres généraux, nommés X, Y, T et L, tous de 24 bits. Un point important est que le registre T avait des possibilités d’extraction spécifiques. Il était possible d'extraire N bits, placés n'importe où dans ce registre, et de les copier dans un autre registre. Le CPU supportait une '''instruction EXTRACT''' pour ça. Nous verrons comment cette possibilité est exploitée pour la traduction binaire dans ce qui suit. Dans ce qui suit, on suppose que l'instruction est composée de '''champs''' : l'opcode, les opérandes, les adresses absolues, les constantes immédiates, les numéros de registre, etc. L'idée est que l'instruction source est chargée dans le registre T, puis découpée en champs, qui sont copiés dans les registres du processeur ou envoyés au microcode. Je rappelle que le registre T est relié à un ''barrel shifter'', différent au précédent, qui permettait de masquer, décaler et extraire une donnée de ce registre. Et il y a la possibilité d'extraire une suite de bit de ce registre T, pour la copier dans un autre registre. Par exemple, prenons une instruction composée d'un opcode, d'une constante immédiate et d'une adresse immédiate. Premièrement, elle est chargée dans le registre T. Deuxièmement, la constante immédiate est extraite du registre T et copiée dans le registre X. Troisièmement, l'adresse est extraite et est copiée dans le registre d’interfaçage mémoire, une lecture est démarrée, et l'opérande lu est copiée dans le registre Y. Enfin, l'instruction équivalente à l'opcode est exécutée par le microcode. Le tout prend plusieurs instructions : une première pour lire l'opcode, une seconde pour lire le premier opérande, une troisième pour lire la seconde opérande, une quatrième pour tout exécuter. Notons que suivant la taille des champs, on peut en charger plusieurs à la fois. Par exemple, imaginons qu'on ait chargé 24 bits, contenant un opcode de 8 bits et une constante immédiate de 16 bits : le registre T est découpé en un opcode et une constante, avec deux instructions EXTRACT. L'architecture est bit-adressable, car elle gère des champs qui ne font pas forcément 8 ou 16 bits. Par exemple, certains jeux d'instructions ont des opcodes codés sur 6 ou 7 bits, voire 9-10 bits. Utiliser une architecture bit-adressable règle ce problème d'alignement. On peut lire un champ depuis la mémoire RAM en précisant l'adresse de son premier bit, pas besoin de gérer des accès non-alignés. Par exemple, prenons une instruction source avec un opcode de 7 bits, suivi par une adresse de 12 bits et une constante immédiate de 15 bits. On peut charger 7 + 12 bits en un premier accès, pour extraite l'opcode et l'adresse, suivi par un second accès de 15 bits pour extraire la constante immédiate. Pour charger un champ, il faut connaitre plusieurs informations : l'adresse de son premier bit, sa taille. Pour cela, le B1700 contient deux registres, nommés ''Field Adress'' (FA) et ''Field Length'' (FL), qui indiquent l'adresse du premier bit et la taille de l'instruction à charger. Le premier fait 24 bits, ce qui permet de gérer des adresses de 24 bits. N'oubliez pas que le processeur est bit-adressable, ce qui permet d'adresser 16 Mébi-bits, soit 2 mébioctets. Le registre pour la taille fait lui 16 bits, ce qui permet de gérer des instructions de 65536 bits, soit 8192 octets ! Leur nom commence par ''field'', car le processeur peut gérer des instructions de taille variable et/ou plus longues que 24 bits. Dans ce cas, le chargement de l'instruction se fait champ par champ. Pour donner un exemple, prenons une instruction composée de 20 champs de 12 bits chacun. Les champs sont chargés un par un dans le registre T. Le registre FA est alors initialisé avec l'adresse de l'instruction, il est incrémenté de 12 à chaque cycle. Le registre FL est initialisé avec la taille de l'instruction, soit 20 × 12 = 240 bits, et il est décrémenté de 16 à chaque cycle. Précisons cependant que la taille d'un champ peut être changée d'un cycle à l'autre. Par exemple, le processeur peut charger un opcode de 8 bits, l'interpréter, détecter que l'instruction demande ensuite de charger une adresse de 16 bits. Dans ce cas, le registre FL est immédiatement altéré pour charger 16 bits, au lieu des 8 bits de l'opcode immédiatement précédent. ===Le Burroughs B1726 : le mal-nommé ''split-level control store''=== Le Burroughs B1700 avait plusieurs modèles : le B1726, le B1710 et le B1800. * Le B1710 plaquait le traducteur binaire en mémoire RAM. * Le B1800 avait ajouté un cache dédié au code du traducteur binaire, afin d'améliorer les performances. * Le B1726 utilisait un ''local store'' dédié au traducteur binaire. Le B1726 peut exécuter le traducteur binaire soit depuis le ''local store'', soit depuis la mémoire RAM avec une pénalité en termes de performances. La documentation appelle cela un '''''split-level control store''''', mais le terme est trompeur : la documentation qualifie de microcode le langage machine du Burroughs B1700, ce qui est à l'origine de beaucoup de confusions. Une autre source de confusion est que ce langage machine a quelques propriétés qu'on pourrait attendre d'un microcode, mais certaines sont manquantes. Par exemple, il peut adresser les registres d’interfaçage mémoire, mais c'est parce que ce sont des registres architecturaux sur ce processeur. Ses instructions n'encodent pas de signaux de commande, par contre, elles font 16 bits et adressent les opérandes de manière implicite. Le ''local store'' mémorisait au maximum 2048 instructions machine, ce qui fait que les 2048 premières "adresses" correspondaient au ''local store''. Les suivantes étaient des adresses de mémoire RAM qui contenaient le reste du traducteur binaire. En pratique, l'adresse qui séparait les deux était configurable ! On pouvait limiter la taille du ''local store'' à un multiple de 32 instructions ! Les adresses restantes étaient alors réattribuées à la RAM. Par exemple, on pouvait attribuer 64 adresses au ''local store'', les 2048 - 64 adresses restantes étaient alors attribuées à la mémoire RAM. Un registre limite, nommé TDPM, indiquait quelle était l'adresse de démarcation entre les deux. Le programmeur devait découper le traducteur binaire en segments, certains étant placés dans le ''local store'', les autres étant en mémoire RAM. Mieux que ça, le processeur autorisait d'utiliser la technique de l'''overlaying'' pour le microcode ! Il y avait même une fonction OVERLAY dédiée pour ! OVERLAY avait besoin de trois opérandes : la taille du segment à copier, son adresse source en mémoire RAM, son adresse de destination dans la micro-SRAM. L'interpréteur réservait un "segment" en mémoire RAM, pour les données, dont le processeur connaissait la position. En dehors de ce segment, il n'y a que des instructions machines à traduire, et le traducteur binaire. Le CPU incorporait pour cela deux registres, un pour l'adresse de base du segment de données, un autre pour son adresse de fin. Il incorporait une protection mémoire limitée sur ce segment, à savoir que seul l'interpréteur pouvait lire ou écrire dans ce segment. ==Les jeux d'instructions dédiés à un langage de programmation== De rares processeurs sont conçus pour un langage de programmation en particulier. On appelle ces processeurs, conçus pour des besoins particuliers, des '''processeurs dédiés'''. Par exemple, les fameux ''Burrough E-mode'' B5000/B6000/B7000 étaient spécialement conçus pour exécuter de l'ALGOL-60. Leurs cousins B2000/B3000/B4000 étaient eux conçus pour le COBOL. Des langages fonctionnels ont aussi eu droit à leurs processeurs dédiés. Le prolog en est un bel exemple, avec les superordinateurs de 5ème génération qui lui étaient dédié. On peut aussi citer les machines LISP, dédiés au langage LISP, qui datent des années 1970. Elles étaient capables d’exécuter certaines fonctions de base du langage directement dans leurs circuits : elles possédaient notamment un ''garbage collector'' câblé dans ses circuits ainsi que des instructions machines supportant un typage déterminé à l’exécution. Les processeurs dédiés ont eu leur heure de gloire au début de l'informatique, à une époque où les langages de haut niveau venaient d'être inventés. À cette époque, les compilateurs n'étaient pas performants et ne savaient pas bien optimiser le code machine. Il était alors rationnel, pour l'époque, de rapprocher le code machine cible et le langage de programmation de haut niveau. De nombreuses architectures dédiés ont ainsi été inventées, avant que les concepteurs se rendent compte des défauts de cette approche. Les défauts en question ne sont pas nombreux, mais assez simples à comprendre. Premièrement, elles sont très rapides pour un langage de programmation en particulier, mais sont assez mauvaises pour les autres, d'où un problème de "compatibilité". Ajoutons à cela que les langages de programmation peuvent évoluer, devenir de moins en moins populaires/utilisés, ce qui rend la création d'architectures généralistes plus pertinente. Enfin, les architectures dédiées sont évidemment des processeurs CISC, pour implémenter les nombreuses fonctionnalités des langages évolués. Et les défauts des CISC sont assez rédhibitoires à l'heure actuelle. À l'heure actuelle, les algorithmes des compilateurs se sont améliorés et savent nettement mieux utiliser le matériel. Ils produisent du code machine efficace, ce qui rend les architecture dédiées bien moins intéressantes. Si on ajoute les défauts de ces architectures dédiées, par étonnant que les architectures dédiées aient presque disparues. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les coprocesseurs : FPU et IO | prevText=Les coprocesseurs : FPU et IO | next=Les processeurs de traitement du signal | nextText=Les processeurs de traitement du signal }} </noinclude> bax3906aam6vw62yryoh67tiqyl6mzs Fonctionnement d'un ordinateur/Les coprocesseurs : FPU et IO 0 83778 772083 763772 2026-09-12T17:02:18Z Mewtow 31375 /* Le Motorola 68881 et le 68882 */ 772083 wikitext text/x-wiki Les '''coprocesseurs''' sont des processeurs secondaires qui complémentent un processeur principal. Ils permettent de déléguer certains calculs à un processeur secondaire, afin de décharger le processeur principal. Un détail important est que le processeur principal et le coprocesseur sont très différents : ils n'ont pas le même jeu d'instruction, n'ont pas les mêmes performances, et bien d'autres différences. Nous en avions déjà vu dans le chapitre sur l'architecture de base, où nous avions analysé d'anciennes consoles de jeu. Mais il est temps de voir ces coprocesseurs en détail ==Les différents types de coprocesseurs== Les coprocesseurs peuvent se classer en plusieurs catégories : les coprocesseurs sonores, arithmétiques, et d'entrées-sorties. Les '''coprocesseurs sonores''' sont une sorte d'ancêtre des cartes son, utilisés sur les anciennes consoles de jeux vidéo, comme La Nintendo 64, la Playstation et autres consoles antérieures. Ils s'occupaient respectivement de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un coprocesseur sonore. Le processeur principal était un Motorola 68000, alors que le coprocesseur sonore était un processeur Z80. Les '''coprocesseur d'IO''' sont dédiés à l'accès aux entrées-sorties. Pour simplifier, ce sont des contrôleurs DMA programmables, capables d'effectuer quelques opérations de branchements et de calcul. Nous en avions parlé dans le chapitre sur les entrée-sorties, je ne reviendrais pas dessus ici. [[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]] Les '''coprocesseurs arithmétiques''' sont dédiés aux calculs en virgule flottante. Ils étaient utilisés à une époque où les CPU ne géraient que des calculs entiers (en binaire ou en BCD). Un exemple est le coprocesseur flottant x87, complémentaire des premiers processeurs Intel x86. Il y a eu la même chose sur les processeurs Motorola 68000, avec deux coprocesseurs flottants appelés les Motorola 68881 et les Motorola 68882. Ils sont aujourd'hui tombés en désuétude, depuis que les CPU sont devenus capables de faire des calculs sur des nombres flottants. ===Les coprocesseurs faiblement et fortement couplés=== À ce stade du cours, nous allons distinguer les coprocesseurs faiblement couplés et fortement couplés. La distinction est que les premiers sont assez détachés du processeur, alors que les seconds ne le sont pas. La distinction n'est pas très claire, aussi j'ai décidé de prendre cette définition : les premiers sont traités comme des entrées-sorties, alors que les seconds sont intégrés sur le bus mémoire. Avec les '''coprocesseurs fortement couplés''', le CPU et le coprocesseur sont connectés sur le même bus mémoire. Le programme exécuté contient des instructions à destination du CPU, d'autres à destination du coprocesseur, dont l'encodage est différent. Les deux surveillent le bus mémoire et décident à qui est destinée l'instruction. Les instructions sont exécutées soit par le CPU, soit par le coprocesseur. En clair, le CPU et le coprocesseur se passent à la main à tour de rôle, ils ne travaillent pas en parallèle. Pour cela, le CPU envoie son ''program counter'' sur le bus d'adresse, ce qui entraine l'apparition d'une instruction sur le bus de données. Là, le processeur et le coprocesseur reçoivent l'instruction et la décodent. Si l'instruction est destinée au processeur, le CPU l'exécutera, alors que le coprocesseur la traitera comme un NOP. Et inversement si l'instruction est destinée au coprocesseur. Les '''coprocesseurs faiblement couplés''' sont des entrées-sorties mappées en mémoire, avec des registres d'interfaçage. Le processeur écrit une instruction et ses opérandes dans ces registres d'interfaçage, et le coprocesseur fait les calculs dans son coin. Le processeur récupère le résultat quelques cycles plus tard, en le lisant dans un autre registre d’interfaçage. La récupération du résultat peut se faire avec du ''pooling'' ou des ''interruptions inter-processeurs''. Le coprocesseur peut envoyer une interruption au processeur principal pour dire qu'il a terminé son travail. Parfois, les interruptions peuvent aller dans l'autre sens. Un exemple est celui des consoles néo-géo et Megadrive. Elles intègrent deux processeurs : un Motorola 68000 qui sert de processeur principal, un Z80 qui sert de processeur dédié à l'audio. Le MC68000 envoie des commandes au Z80, mais la communication ne va pas dans l'autre sens. Les deux processeurs communiquent via l'intermédiaire d'un ''IO arbiter chip'', qui gère les interruptions inter-processeur. Il contient un registre de 8 bits, dans lequel le MC68000 peut écrire un numéro d'interruption, qui indiquent quelle routine d'interruption exécuter. Lorsque le MC68000 écrit une valeur dedans, cela déclenche l’exécution automatique d'une interruption sur le Z80. Les coprocesseurs sonores sont tous dans ce cas. Le coprocesseur sonore exécute un programme pour gérer le son, qui est séparé au programme principal. Le programme principal communique avec le coprocesseur, mais c'est assez rare. Dans un jeu vidéo, cela arrive seulement quand il faut changer de musique ou déclencher un effet sonore. Et ce n'est possible que si ces coprocesseurs sont faiblement couplés. Mais quelques coprocesseurs arithmétiques sont dans ce cas aussi, comme on le verra plus bas. [[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]] Il existe cependant des cas assez difficiles à classer. Nous verrons le cas des Motorola 68881 dans ce qui suit, qui sont un mélange des deux solutions. ===Les coprocesseurs arithmétiques : quelques généralités=== Dans le reste de ce chapitre, nous allons surtout voir les coprocesseurs arithmétiques. Et ce pour une raison très simple : nous avons déjà vu les coprocesseurs I/O et les coprocesseurs sonores dans un chapitre antérieur. Pour rappel, les coprocesseurs sonores sont des cartes sons, ou du moins une partie de carte son. De plus, on a plus de documentation sur les coprocesseurs arithmétiques. Il faut dire que c'étaient des processeurs commerciaux, vendus autrefois en magasin, avec de la documentation destinée aux utilisateurs. Les coprocesseurs arithmétiques étaient spécialisés dans les calculs flottants Ils étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans coprocesseur. La solution la plus simple était de fournir deux versions du logiciel : une sans usage du coprocesseur, et une autre qui en fait usage, plus rapide. Une autre solution était d'émuler les calculs flottants en logiciel. Le problème ne se pose pas sur les consoles de jeu, mais il est assez rare que les consoles de jeu incorporent des coprocesseurs arithmétiques. Il existe cependant des exceptions. Un exemple récent est de la console de jeu Nintendo DS. La console utilisait deux processeurs, un ARM9 et un ARM7, deux processeurs RISC qui ne pouvaient pas faire de division entière. Il s'agit pourtant d'opérations importantes dans le cas du rendu 3D, ce qui fait que les concepteurs de la console ont rajouté un coprocesseur spécialisé dans les divisions entières et les racines carrées. Le coprocesseur était adressable directement par le processeur, comme peuvent l'être la RAM ou les périphériques, et était traité comme une entrée-sortie comme une autre. ==Les coprocesseurs pour les CPU x86== Dans le chapitre précédent, nous avons parlé du jeu d'instruction x87, qui ajoutait le support des nombres flottants aux PC x86. Formellement, le x87 est apparu sur le coprocesseur 8087, un coprocesseur Intel prévu pour être utilisé avec un 8086. Mais ce n'a pas été le premier coprocesseur flottant pour PC. Il a existé quelques coprocesseurs avant lui, qui ne respectaient pas le standard x87. Et ne parlons pas des coprocesseurs Motorola et autres, qui suivaient un autre standard et ne fonctionnaient pas avec un CPU x86. Dans cette section, nous allons voir les coprocesseurs conçus pour les PC, qui fonctionnaient en tandem avec un CPU x86. Les premiers coprocesseurs de ce type étaient l'Intel 8231/8232, destinés à être utilisés avec le 8088, un processeur 8 bits. Par la suite, Intel a récidivé avec le 8087, qui était destiné pour servir en tandem avec le 8086. Il a été suivi par les Intel 187, le 287, le 387, le 487 et le 587, qui étaient censés servir avec les CPU 186, 286, 386, 486, etc. Mais d'autres compagnies ont crée des coprocesseurs x87, comme Weitek, Cyrix, AMD, Texas Instrument, et bien d'autres. ===Les précurseurs : l'Intel 8231 et le 8232=== L'Am9511 et Am9512 sont une des toutes premières FPU pour PC, si ce n'est les premières si on en croit AMD. Ils ont été licenciés par Intel sous le nom d'Intel 8231 et le 8232. Ils étaient conçus pour complémenter le CPU Intel 8080, mais on pouvait parfaitement les utiliser avec d'autres CPU, comme le Z80. La [http://ep.homeserver.hu/PDF/AM9511A-9512.pdf documentation AMD donnait même des exemples assez variés]. La raison est qu'on y accédait comme n'importe quelle entrée-sortie connectée au bus système. Ils étaient accessibles via ''pooling'', interruptions ou même via DMA. Nous expliquerons comment c'est possible plus bas. L'Intel 8231 ne supportait pas le jeu d'extension x87, qui est apparu après. Il gérait des nombres flottants de 32 bits, mais aussi des nombres en virgule fixe de 16 et 32 bits. Les flottants 32 bits suivaient globalement la norme IEEE 754, mais les nombres en virgule fixe utilisaient un format propriétaire. Il gérait les quatre opérations de base, mais aussi des calculs trigonométriques. Il utilisait pour cela du microcode, avec une approximation basée sur des polynômes de Tchebychev. L'intel 8232 supportait lui des flottants 32 et 64 bits, mais ne supportait que les quatre opérations de base (addition, soustraction, multiplication et division). : La documentation décrit ces flottants 32 bits comme étant de la double précision, mais c'est parce que la terminologie de l'époque n'était pas encore bien stabilisée. [[File:C8231A FPU PIN CONFIGURATION.png|thumb|Intel 8231 FPU PIN CONFIGURATION.]] Les broches de l'intel 8231 sont illustrées ci-contre. La plupart des broches nous sont familières : 8 broches pour le bus de données (qui fait 8 bits), une entrée d'horloge, une entrée de RESET, une entrée ''chip select'' pour le décodage d'adresse. Les broches restantes sont très intéressantes, mais on les verra dans ce qui suit. Toujours est-il que le coprocesseur est relié à un bus de 8 bits, alors que ses registres font 32 à 64 bits. Pour cela, le 8231/8232 lisait les opérandes octet par octet depuis le bus de données. Idem mais pour les écritures. Par contre, les instructions sont prévues pour faire 8 bits, pas plus. Pour avoir des instructions aussi courtes, la seule solution est d'utiliser une machine à pile et c'est ce que le 8231/8232 a fait. Précisons cependant que ce n'est pas la même pile de registre que la pile x87, mais c'était une sorte de pile similaire, qui a évolué pour donner la pile x87. Il s'agissait pour le coup d'une vraie pile, les opérations utilisaient systématiquement le sommet de la pile et l'opérande en dessous. Il n'y avait pas de possibilité d'adresser un opérande dans la pile. Le processeur intégrait 8 registres de 16 bits, organisés comme une pile. Les registres pouvaient être utilisés : soit comme une pile de 8 opérandes 16 bits, soit une pile de 4 opérandes 32 bits, soit une pile de 2 opérandes 64 bits. Les opérandes étaient empilées octet par octet dans le processeur. Ils étaient dépilés là aussi octet par octet. Pour cela, le 8231/8232 dispose de trois entrées nommées A0, RD et WR. Les trois bits décident s'il faut faire une lecture, une écriture, exécuter une instruction, ou lire le registre d'état. Les quatre opérations sont appelées des commandes dans la documentation Intel et AMD. Les trois entrées font donc office de bus de commande simplifié. {|class="wikitable" |- ! A0, RD, WR !! Action |- | 000 || Lecture de l'octet depuis les registres de données. |- | 010 || Écriture de l'octet dans les registres de données. |- | 111 || L'octet est l'opcode d'une instruction, qui est exécutée immédiatement. |- | 101 || Lecture du registre d'état. |} Le processeur principal envoyait des commandes à l'Intel 8231/8232, qui les exécutait dans son coin. Le 8231/8232 envoyait un signal END OF EXECUTION pour prévenir qu'il avait fini son travail, que la commande précédente était terminée. Il avait une broche dédiée, appelée END, dédiée à ça. Le coprocesseur avait donc une interface de communication asynchrone, qui se voit quand on étudie ses broches. Les broches suivantes servent à la communication asynchrone avec le 8231/8232. * READY est à 1 quand le 8231/8232 est libre, capable d'accepter une nouvelle instruction/commande. Il passe à 0 quand une instruction démarre, avec la commande 111 vue plus haut. * END indique que la commande précédente a terminé son exécution. Lorsque END passe à 1, BUSY passe automatiquement à 0. * EACK est une entrée sur laquelle le processeur dit qu'il a bien reçu le signal END, et que ce dernier peut être remis à 0. Ce système pouvait être utilisé avec du ''pooling'', avec des interruptions, voire du DMA. Avec des interruptions, la sortie END était utilisée comme sortie d'interruption, reliée au CPU ou au contrôleur d'interruption. Pour le ''pooling'', le registre d'état du 8231/8232 contenait un bit BUSY, qui indiquait si le coprocesseur était utilisé ou non. Un tel fonctionnement peut sembler étrange, et vous aurez l'impression que communiquer avec le coprocesseur est très lent. Mais cela prend tout son sens quand on connait le temps mis pour exécuter une instruction sur le coprocesseur. Une opération simple sur des flottants 32 bits prenait facilement une cinquantaine de cycles d'horloge, et c'était parmi les meilleurs temps de calcul. Il n'était pas rare d'avoir des opérations prenant plusieurs centaines, voire milliers de cycles d'horloge. Pas loin de 5000 cycles d'horloge pour une division de deux flottants 64 bits sur le 8232, plusieurs dizaines de milliers de cycles pour certaines opérations trigonométriques. Et le pire, c'était que c'était plus rapide que l'émulation logicielle ! Pas étonnant donc que le 8231/8232 aient été traités comme des entrées-sorties, à une époque ou tout était connecté sur un bus système assez rapide. Un autre avantage est que le 8231/8232 pouvaient fonctionner à une fréquence sans rapport avec celle du processeur. Par exemple, on pouvait utiliser un processeur à 1 MHz alors que le 8231/8232 allait à 4 MHz. Le coprocesseur faisait juste des calculs rapidement, comparé au CPU. Et ça a été utilisé sur certains systèmes Apple II. Ou encore, on pouvait utiliser un processeur légèrement plus rapide que le coprocesseur, avec quelques MHz de différence, comme un CPU à 5 MHz avec un coprocesseur de 2 MHz. ===L'intel 8087 et ses successeurs=== [[File:Intel 8087.svg|vignette|Intel 8087]] Le 8087 été fabriqué avec 65 000 transistors. Le 8087 avait pour particularité qu'il était connecté directement sur le bus mémoire, au même titre que le 8086. Mais le 8087 n'avait pas de bus d'adresse et de données séparé. Le processeur utilisait un bus multiplexé. Il avait 20 broches pour se connecter au bus : 16 d'entre elles servaient alternativement de bus d'adresse et de données. L'interface avec le bus était donc un peu compliquée. L'intel 387 était le coprocesseur associé au 386 d'Intel. Il était le premier coprocesseur à s'intégrer sur un bus de 32 bits. Il a été décliné en plusieurs versions, dont certaines sont spécifiques à un modèle de 386. Par exemple, le i386SX était une version simplifiée du 386 initial, qui avait notamment un bus de seulement 16 bits. Et de ce fait, il avait son propre coprocesseur i387SX, qui était adapté à un bus de 16 bits. De même, le i386SL était adapté aux ordinateurs portables et avait son propre coprocesseur i387SL. Tout ce qui va suivre est valide pour tous les coprocesseurs x87 de marque Intel. Le processeur central lisait des instructions, en envoyant le ''program counter'' sur le bus d'adresse, les instructions étaient récupérées sur le bus de données. Là, les deux processeurs déterminaient si l'instruction chargée était destinée au coprocesseur ou au CPU. Pour cela, les instructions x87 commencent toutes par la suite de bit 11011, qui permet de savoir facilement si une instruction est destinée au coprocesseur. Le 11011 était suivi par un opcode et un mode d'adressage. Si le mode d'adressage demandait de lire un opérande mémoire, le 8086 envoyait l'adresse de l'opérande sur le bus, et le coprocesseur récupérait celle-ci sur le bus de données. Si l'opérande devait être lu en plusieurs fois, le coprocesseur lisait le reste de lui-même, en prenant le contrôle du bus d'adresse. Il récupérait l'adresse envoyée initialement par le CPU, puis l'incrémentait et relançait un nouvel accès mémoire. Il l'incrémentait autant de fois que nécessaire pour charger l'opérande. Un problème est que le CPU ne sait pas combien de temps dure une instruction x87. Et cette durée dépendait de l'implémentation du processeur, elle n'était pas la même selon la marque du coprocesseur. Un 186 n'avait pas les mêmes timings que le 286, par exemple. Pour le CPU, une instruction x87 met juste deux cycles pour s'exécuter (plus si des opérandes doivent être lus en mémoire). Pour cela, le CPU disposait d'un mécanisme de synchronisation. Le mécanisme de synchronisation était une instruction WAIT, qui forçait le CPU à attendre que le coprocesseur ait terminé l'instruction précédente. L'implémentation matérielle était assez simple. Le coprocesseur disposait d'une sortie BUSY, qui indiquait qu'il était en train d'exécuter une instruction et ne pouvait pas en accepter une nouvelle. Le CPU, quant à lui, avait une entrée TEST qui vérifiait si le, coprocesseur était occupé ou non. La sortie BUSY était reliée à l'entrée TEST. L'instruction test vérifiait juste ce qu'il y avait sur l'entrée TEST. Tant qu'elle était à 1, le processeur attendait et ne chargeait pas de nouvelle instruction. Dès qu'elle passe à 0, l'exécution reprend. Il faut noter que l'instruction WAIT n'est nécessaire qu'entre deux instructions flottantes assez proches. Mais il est possible d'intercaler des instructions entières entre deux instructions flottantes. Le programme pouvait ainsi mixer instructions entières et flottantes, les instructions entières étant exécutées sur le 8086, les instructions flottantes sur le coprocesseur. Il y avait donc une possibilité de parallélisme, à savoir que les deux processeurs pouvaient exécuter des instructions différentes en même temps. Mais cela demandait que les calculs soient coopératifs et mélangent bien entiers et flottants. Le 8087 et ses successeurs avaient une microarchitecture assez simple. L'unité de contrôle contenait un décodeur d'instruction microcodé, le registre de contrôle, le registre d'état. La plupart des instructions sont microcodées, l'unité de calcul est assez limitée. Elle permet d'additionner deux mantisses flottantes, de faire des décalages, d'additionner deux exposants, mais pas plus. Les multiplications et divisions sont donc microcodées et émulées en enchainant des additions flottantes. Les instructions trigonométriques sont implémentées en utilisant l'algorithme CORDIC, qu'on a vu dans le chapitre sur les circuits de calcul flottant. [[File:Intel 8087 arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel 8087.]] Le chemin de données est composé d'un banc de registre flottant pour la pseudo-pile, et de plusieurs circuits de calcul. Le banc de registre était mono-port, ce qui fait que les ALUs étaient précédés par deux registres temporaires pour les opérandes. Les circuits pour l'exposant et la mantisse sont séparés, et sont même reliés au banc de registre par deux bus séparés. Il y a un additionneur pour les exposants, un additionneur pour les mantisses et un décaleur pour les mantisses (pour les normaliser). De plus, on trouve une mémoire ROM dédiée aux constantes les plus utilisées. Elle sert pour les constantes de base, gérées par le jeu d'extension x87. Mais elle contient aussi des constantes utilisées pour l'algorithme CORDIC. Elle n'est pas illustrée sur le schéma ci-dessous, mais elle existe. L'interface avec le bus est un simple registre d’interfaçage avec le bus. Pour rappel, le bus de données fait 16 bits sur le 8087, 32 bits sur le 387. Entre le bus et le chemin de données, on trouve une file servant à simplifier la gestion des lectures. L'idée est que les opérandes lus/écrits font 32, 64 ou 80 bits, alors que le bus de données n'en fait que 16/32. Les opérandes sont donc lus/écrits en plusieurs passes. Sur le 8087, il doit réaliser deux passes pour des opérandes de 32 bits, quatre passes pour celles de 64 bits, 5 pour des opérandes de 80 bits (80 = 5 × 16). Le 387 doit faire deux fois moins. [[File:Intel 387 arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel 387. Les circuits pour les exposants sont à gauche dans le chemin de données, les circuits pour les mantisses sont à droite.]] L'implémentation du banc de registre est assez simple : une RAM avec un registre qui indique la position du sommet de la pile dedans. Le registre fait 3 bits, pour 8 registres. En plus de cela, il y a un petit soustracteur et un multiplexeur, pour adresser les opérandes dans la pile. Pour rappel, il est possible d'adresser la seconde opérande dans la pile. Mais on précise pas le numéro du registre dans la pile pour cela, on précise sa position sous le sommet de la pile, à savoir si elle est deux, trois, quatre opérandes sous le sommet de la pile. Pour déterminer quel registre lire, il faut soustraire ce "décalage" au numéro de registre du sommet de la pile. Pour cela, il y a un petit soustracteur pour faire le calcul. Le circuit décaleur est composé de deux sous-décaleurs. Le premier fait des décalages au niveau des octets, le second décale l'opérande de 0 à 7 rangs. Pour finir, voici quelques liens sur la microarchitecture du 8087 : * [https://www.righto.com/2026/02/8087-instruction-decoding.html Instruction decoding in the Intel 8087 floating-point chip]. * [https://www.righto.com/2020/05/die-analysis-of-8087-math-coprocessors.html Die analysis of the 8087 math coprocessor's fast bit shifter]. * [https://www.righto.com/2025/12/8087-stack-circuitry.html The stack circuitry of the Intel 8087 floating point chip, reverse-engineered]. * [https://www.righto.com/2025/12/8087-microcode-conditions.html Conditions in the Intel 8087 floating-point chip's microcode]. * [https://www.righto.com/2020/05/extracting-rom-constants-from-8087-math.html Extracting ROM constants from the 8087 math coprocessor's die]. * [https://www.righto.com/2018/09/two-bits-per-transistor-high-density.html Two bits per transistor: high-density ROM in Intel's 8087 floating point chip]. ===Les coprocesseurs x87 de Weitek=== Intel n'a pas été le seul fabricant à commercialiser des coprocesseurs x87. Weitek et de nombreuses autres entreprises s'y sont mises. Weitek a commercialisé plusieurs coprocesseurs : un premier coprocesseur appelé le 1067, le 1167, le 2167, le 3167 et le 4167. Ils sont tous rétrocompatibles entre eux, à savoir que le 4167 ne fait qu'ajouter des fonctionnalités au 3167, qui lui-même ajoute des fonctionnalités au 2167, et ainsi de suite. Ils gèrent tous les quatre opérations de base, ainsi que le calcul de la racine carrée. Le '''Weitek 1067''' avait pour particularité d'être fourni en pièces détachées, avec trois circuits séparés : un circuit de contrôle, une ALU flottante, et un multiplieur/diviseur. Ces trois pièces détachées étaient censées être soudées sur la carte mère. Le '''Weitek 1167''' regroupait ces trois pièces détachées sur une carte d'extension ISA. Par la suite, le '''Weitek 2167''' regroupa les trois pièces détachées dans un seul circuit imprimé. Il n'y avait pas de registres flottants adressables, ni de pile de registres. À la place, l'ALU et le multiplieur/diviseur intégraient deux registres pour les opérandes et un registre accumulateur. Les opérandes étaient présentés sur le bus de données et l'ALU les mémorisait dans deux registres internes de 64 bits chacun, nommés A et B. Le coprocesseur lisait les opérandes depuis ces deux registres et mémorisait le résultat dans un registre de résultat interne. Il envoyait alors le résultat sur le bus de données, prévenait le CPU avec une interruption, et le CPU récupérait le résultat sur le bus. Il faut noter que toutes les communications avec l'ALU passent par le bus de données, appelé le bus X. La transmission d'un flottant 32 bits se faisait en un cycle d'horloge, vu que le bus était de 32 bits. Par contre, la transmission d'un flottant 64 bits se faisait en deux cycles. À part le bus de données, il y avait un bus de commande, relié à l'unité de contrôle 1163. Elle envoyait l'opcode sur une entrée dédiée, notée F. Les bits de commande L, CSL, CSUS, CUSX, U commandent la lecture des opérandes ou leur écriture. L'unité de contrôle recevait le registre d'état via une sortie dédiée nommée S ou STATUS. [[File:Weitek WTL1167 arch.svg|centre|vignette|upright=2.5|Weitek WTL1167.]] Pour charger les opérandes dans l'ALU, celle-ci intégrait diverses entrées de commande nommées L0, L1, L2, L3 et CSL. * Le signal CSL est le ''Chip Select Load'', ce qui indique qu'il est mis à 1 lors d'une lecture. * Le bit L0 à 1 indique qu'un opcode est envoyé sur l'entrée F, l'entrée pour l'opcode est recopiée dans un registre interne, qui n'est pas un registre d'instruction vu que l'ALU n'a pas de décodeur. * Les bits L1 et L2 indiquent si ce qu'il y a sur le bus est : un flottant 32 bits, les 32 bits de poids fort d'un flottant 64 bits, les 32 bits de poids faible d'un flottant 64 bits. * Le registre L3 indique quel est le registre de destination : A ou B. Les signaux U, CSUS et CSUX servaient pour l'envoi du résultat sur le bus. Ils précisaient s'il fallait copier un flottant 32 bits, les 32 bits de poids fort d'un flottant 64 bits, les 32 bits de poids faible d'un flottant 64 bits. Le '''Weitek 3167''' était conçu pour fonctionner en tandem avec un CPU Intel 386, alors que le '''Weitek 4167''' était prévu pour aller avec un Intel 486, mais ils fonctionnaient de la même manière au-delà de quelques détails. Contrairement à leurs prédécesseurs, ils intégraient 32 registres flottants de 32 bits. Un registre pair et un registre impair pouvaient être concaténés pour mémoriser un opérande 64 bits. Les opérations se faisaient soit entre deux registres flottants, soit entre un registre flottant et l'opérande présentée sur le bus de données. Le résultat est stocké dans un registre flottant. Leur registre de status contenait les résultats des comparaisons flottantes, ainsi que 8 bits pour les exceptions flottantes. Le registre de contrôle avait un champ pour configurer les arrondis, mais aussi un masque d'exceptions de 8 bits disant quels bits d'exceptions ignorer dans le registre de statut. Le coprocesseur est mappé en mémoire, ce qui fait qu'il a des adresses réservées dans lesquelles le processeur peut lire/écrire, pour lui envoyer une instruction, envoyer un opérande ou récupérer un résultat. Les adresses en question sont les adresses COOO OOOOh à COOO FFFFh, ce qui fait que le coprocesseur est adressé si les 16 bits de poids fort de l'adresse valent COOO. Par contre, les 65536 adresses réservées n'étaient pas associées à de la mémoire, pas même aux registres. A la place, les 16 bits de poids faible de l'adresse encodaient une instruction au coprocesseur, à savoir un opcode de 6 bits deux numéros de registres. Le processeur communique avec le coprocesseur en envoyant l'instruction sur le bus d'adresse, et éventuellement un opérande sur le bus de données. L'opérande vient généralement des registres, par simplicité, car cela permet de tout envoyer en une seule écriture. Par exemple, une écriture du registre EAX à l'adresse COOO OOOOh va copier le registre EAX sur le bus de données, et envoyer l'opcode de l'addition (0000) sur le bus d'adresse avec deux numéros de registre. Le coprocesseur fait alors une addition entre le registre flottant sélectionné, et l'opérande sur le bus de données copiée depuis EAX. ==Le Motorola 68881 et le 68882== Le 68881 de Motorola était conçu pour fonctionner avec les CPU 68020 et 68030. Les programmes mixaient instructions entières et flottantes, le 68000 exécutant les instructions entières, le 68881 exécutant les instructions flottantes. Les instructions flottantes avaient un opcode qui commençait par F (en hexadécimal), ce qui permettait de les distinguer rapidement du reste. Le 68000 chargeait les instructions, et regardait si l'instruction était destinée soit au coprocesseur, soit pour lui. Pour une instruction coprocesseur, il lisait les opérandes en RAM, puis envoyait instruction et opérandes au 68881. Il continuait son travail dans son coin, et récupérait le résultat quelques cycles plus tard. Malgré le fait qu'il y ait des instructions destinées au coprocesseur, le 68881 n'était pas un coprocesseur fortement couplé. A la place, le 68881 était géré comme une entrée-sortie, du point de vue du CPU. Il était mappé en mémoire, avait une entrée ''Chip Select'' commandé par décodage d'adresse. Il contenait aussi des registres d'interface, appelés des ''coprocessor interface registers'' (CIRs). Il y avait des registres pour l'opcode de l'instruction à exécuter, un autre pour chaque opérande, etc. Pour envoyer une instruction au 68881, le CPU avait juste à écrire dans les registres adéquats, idem pour charger les opérandes de l'instruction si besoin. Les coprocesseurs Motorola utilisaient des flottants codés sur 80 bits : la mantisse était codée sur 64 bits, l'exposant sur 15 bits. Le 68881 incorporait 8 registres flottants, nommés, de 80 bits chacun. Fait étonnant, cela ressemble beaucoup à ce qui est fait avec les coprocesseurs x87 : usage de flottants codés sur 80 bits, 8 registres flottants. Mais les détails sont différents, le jeu d'instruction est complétement différent. Les coprocesseurs Motorola avaient aussi un registre de statut et un registre de contrôle, guère plus. Le registre de statut mémorisait les conditions classiques, mais aussi des bits pour les exceptions qui ont été levées lors d'un calcul. Le registre de contrôle mémorisait de quoi configurer les arrondis, mais aussi un masque pour indiquer quelles exceptions ignorer dans le registre de statut. Pareil que pour les processeurs précédents, donc. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Un exemple de jeu d'instruction : l'extension x87 | prevText=Un exemple de jeu d'instruction : l'extension x87 | next=Les ISA optimisés pour la compilation/interprétation | nextText=Les ISA optimisés pour la compilation/interprétation }} </noinclude> k6wk84k3mwbx3e2vsbvwxkcnvagnyyx 772104 772083 2026-09-13T07:34:11Z DavidL 1746 /* Les coprocesseurs pour les CPU x86 */ 772104 wikitext text/x-wiki Les '''coprocesseurs''' sont des processeurs secondaires qui complémentent un processeur principal. Ils permettent de déléguer certains calculs à un processeur secondaire, afin de décharger le processeur principal. Un détail important est que le processeur principal et le coprocesseur sont très différents : ils n'ont pas le même jeu d'instruction, n'ont pas les mêmes performances, et bien d'autres différences. Nous en avions déjà vu dans le chapitre sur l'architecture de base, où nous avions analysé d'anciennes consoles de jeu. Mais il est temps de voir ces coprocesseurs en détail ==Les différents types de coprocesseurs== Les coprocesseurs peuvent se classer en plusieurs catégories : les coprocesseurs sonores, arithmétiques, et d'entrées-sorties. Les '''coprocesseurs sonores''' sont une sorte d'ancêtre des cartes son, utilisés sur les anciennes consoles de jeux vidéo, comme La Nintendo 64, la Playstation et autres consoles antérieures. Ils s'occupaient respectivement de calculer tout ce qui a trait au son. Pour donner un exemple, on peut citer la console Neo-géo, qui disposait de deux processeurs travaillant en parallèle : un processeur principal, et un coprocesseur sonore. Le processeur principal était un Motorola 68000, alors que le coprocesseur sonore était un processeur Z80. Les '''coprocesseur d'IO''' sont dédiés à l'accès aux entrées-sorties. Pour simplifier, ce sont des contrôleurs DMA programmables, capables d'effectuer quelques opérations de branchements et de calcul. Nous en avions parlé dans le chapitre sur les entrée-sorties, je ne reviendrais pas dessus ici. [[File:Asmp 2.gif|centre|vignette|upright=2|Co-processeur pour l'accès aux entrées-sorties.]] Les '''coprocesseurs arithmétiques''' sont dédiés aux calculs en virgule flottante. Ils étaient utilisés à une époque où les CPU ne géraient que des calculs entiers (en binaire ou en BCD). Un exemple est le coprocesseur flottant x87, complémentaire des premiers processeurs Intel x86. Il y a eu la même chose sur les processeurs Motorola 68000, avec deux coprocesseurs flottants appelés les Motorola 68881 et les Motorola 68882. Ils sont aujourd'hui tombés en désuétude, depuis que les CPU sont devenus capables de faire des calculs sur des nombres flottants. ===Les coprocesseurs faiblement et fortement couplés=== À ce stade du cours, nous allons distinguer les coprocesseurs faiblement couplés et fortement couplés. La distinction est que les premiers sont assez détachés du processeur, alors que les seconds ne le sont pas. La distinction n'est pas très claire, aussi j'ai décidé de prendre cette définition : les premiers sont traités comme des entrées-sorties, alors que les seconds sont intégrés sur le bus mémoire. Avec les '''coprocesseurs fortement couplés''', le CPU et le coprocesseur sont connectés sur le même bus mémoire. Le programme exécuté contient des instructions à destination du CPU, d'autres à destination du coprocesseur, dont l'encodage est différent. Les deux surveillent le bus mémoire et décident à qui est destinée l'instruction. Les instructions sont exécutées soit par le CPU, soit par le coprocesseur. En clair, le CPU et le coprocesseur se passent à la main à tour de rôle, ils ne travaillent pas en parallèle. Pour cela, le CPU envoie son ''program counter'' sur le bus d'adresse, ce qui entraine l'apparition d'une instruction sur le bus de données. Là, le processeur et le coprocesseur reçoivent l'instruction et la décodent. Si l'instruction est destinée au processeur, le CPU l'exécutera, alors que le coprocesseur la traitera comme un NOP. Et inversement si l'instruction est destinée au coprocesseur. Les '''coprocesseurs faiblement couplés''' sont des entrées-sorties mappées en mémoire, avec des registres d'interfaçage. Le processeur écrit une instruction et ses opérandes dans ces registres d'interfaçage, et le coprocesseur fait les calculs dans son coin. Le processeur récupère le résultat quelques cycles plus tard, en le lisant dans un autre registre d’interfaçage. La récupération du résultat peut se faire avec du ''pooling'' ou des ''interruptions inter-processeurs''. Le coprocesseur peut envoyer une interruption au processeur principal pour dire qu'il a terminé son travail. Parfois, les interruptions peuvent aller dans l'autre sens. Un exemple est celui des consoles néo-géo et Megadrive. Elles intègrent deux processeurs : un Motorola 68000 qui sert de processeur principal, un Z80 qui sert de processeur dédié à l'audio. Le MC68000 envoie des commandes au Z80, mais la communication ne va pas dans l'autre sens. Les deux processeurs communiquent via l'intermédiaire d'un ''IO arbiter chip'', qui gère les interruptions inter-processeur. Il contient un registre de 8 bits, dans lequel le MC68000 peut écrire un numéro d'interruption, qui indiquent quelle routine d'interruption exécuter. Lorsque le MC68000 écrit une valeur dedans, cela déclenche l’exécution automatique d'une interruption sur le Z80. Les coprocesseurs sonores sont tous dans ce cas. Le coprocesseur sonore exécute un programme pour gérer le son, qui est séparé au programme principal. Le programme principal communique avec le coprocesseur, mais c'est assez rare. Dans un jeu vidéo, cela arrive seulement quand il faut changer de musique ou déclencher un effet sonore. Et ce n'est possible que si ces coprocesseurs sont faiblement couplés. Mais quelques coprocesseurs arithmétiques sont dans ce cas aussi, comme on le verra plus bas. [[File:Architecture de la Megadrive et de la Néogeo.png|centre|vignette|upright=2.5|Architecture de la Megadrive et de la Néogeo]] Il existe cependant des cas assez difficiles à classer. Nous verrons le cas des Motorola 68881 dans ce qui suit, qui sont un mélange des deux solutions. ===Les coprocesseurs arithmétiques : quelques généralités=== Dans le reste de ce chapitre, nous allons surtout voir les coprocesseurs arithmétiques. Et ce pour une raison très simple : nous avons déjà vu les coprocesseurs I/O et les coprocesseurs sonores dans un chapitre antérieur. Pour rappel, les coprocesseurs sonores sont des cartes sons, ou du moins une partie de carte son. De plus, on a plus de documentation sur les coprocesseurs arithmétiques. Il faut dire que c'étaient des processeurs commerciaux, vendus autrefois en magasin, avec de la documentation destinée aux utilisateurs. Les coprocesseurs arithmétiques étaient spécialisés dans les calculs flottants Ils étaient optionnels et il était parfaitement possible de monter un PC qui n'en avait pas. En conséquence, les programmeurs devaient coder des programmes qui peuvent fonctionner avec et sans coprocesseur. La solution la plus simple était de fournir deux versions du logiciel : une sans usage du coprocesseur, et une autre qui en fait usage, plus rapide. Une autre solution était d'émuler les calculs flottants en logiciel. Le problème ne se pose pas sur les consoles de jeu, mais il est assez rare que les consoles de jeu incorporent des coprocesseurs arithmétiques. Il existe cependant des exceptions. Un exemple récent est de la console de jeu Nintendo DS. La console utilisait deux processeurs, un ARM9 et un ARM7, deux processeurs RISC qui ne pouvaient pas faire de division entière. Il s'agit pourtant d'opérations importantes dans le cas du rendu 3D, ce qui fait que les concepteurs de la console ont rajouté un coprocesseur spécialisé dans les divisions entières et les racines carrées. Le coprocesseur était adressable directement par le processeur, comme peuvent l'être la RAM ou les périphériques, et était traité comme une entrée-sortie comme une autre. ==Les coprocesseurs pour les CPU x86== Dans le chapitre précédent, nous avons parlé du jeu d'instruction x87, qui ajoutait le support des nombres flottants aux PC x86. Formellement, le x87 est apparu avec le coprocesseur 8087, un coprocesseur Intel prévu pour être utilisé avec un 8086. Mais ce n'est pas le premier coprocesseur flottant pour PC. Il a existé quelques coprocesseurs avant lui, qui ne respectaient pas le standard x87. Et ne parlons pas des coprocesseurs Motorola et autres, qui suivaient un autre standard et ne fonctionnaient pas avec un CPU x86. Dans cette section, nous allons voir les coprocesseurs conçus pour les PC, qui fonctionnaient en tandem avec un CPU x86. Les premiers coprocesseurs de ce type étaient l'Intel 8231/8232, destinés à être utilisés avec le 8088, un processeur 8 bits. Par la suite, Intel a récidivé avec le 8087, qui était destiné pour servir en tandem avec le 8086. Il a été suivi par les Intel 187, le 287, le 387, le 487 et le 587, qui étaient censés servir avec les CPU 186, 286, 386, 486, etc. Mais d'autres compagnies ont crée des coprocesseurs x87, comme Weitek, Cyrix, AMD, Texas Instrument, et bien d'autres. ===Les précurseurs : l'Intel 8231 et le 8232=== L'Am9511 et Am9512 sont une des toutes premières FPU pour PC, si ce n'est les premières si on en croit AMD. Ils ont été licenciés par Intel sous le nom d'Intel 8231 et le 8232. Ils étaient conçus pour complémenter le CPU Intel 8080, mais on pouvait parfaitement les utiliser avec d'autres CPU, comme le Z80. La [http://ep.homeserver.hu/PDF/AM9511A-9512.pdf documentation AMD donnait même des exemples assez variés]. La raison est qu'on y accédait comme n'importe quelle entrée-sortie connectée au bus système. Ils étaient accessibles via ''pooling'', interruptions ou même via DMA. Nous expliquerons comment c'est possible plus bas. L'Intel 8231 ne supportait pas le jeu d'extension x87, qui est apparu après. Il gérait des nombres flottants de 32 bits, mais aussi des nombres en virgule fixe de 16 et 32 bits. Les flottants 32 bits suivaient globalement la norme IEEE 754, mais les nombres en virgule fixe utilisaient un format propriétaire. Il gérait les quatre opérations de base, mais aussi des calculs trigonométriques. Il utilisait pour cela du microcode, avec une approximation basée sur des polynômes de Tchebychev. L'intel 8232 supportait lui des flottants 32 et 64 bits, mais ne supportait que les quatre opérations de base (addition, soustraction, multiplication et division). : La documentation décrit ces flottants 32 bits comme étant de la double précision, mais c'est parce que la terminologie de l'époque n'était pas encore bien stabilisée. [[File:C8231A FPU PIN CONFIGURATION.png|thumb|Intel 8231 FPU PIN CONFIGURATION.]] Les broches de l'intel 8231 sont illustrées ci-contre. La plupart des broches nous sont familières : 8 broches pour le bus de données (qui fait 8 bits), une entrée d'horloge, une entrée de RESET, une entrée ''chip select'' pour le décodage d'adresse. Les broches restantes sont très intéressantes, mais on les verra dans ce qui suit. Toujours est-il que le coprocesseur est relié à un bus de 8 bits, alors que ses registres font 32 à 64 bits. Pour cela, le 8231/8232 lisait les opérandes octet par octet depuis le bus de données. Idem mais pour les écritures. Par contre, les instructions sont prévues pour faire 8 bits, pas plus. Pour avoir des instructions aussi courtes, la seule solution est d'utiliser une machine à pile et c'est ce que le 8231/8232 a fait. Précisons cependant que ce n'est pas la même pile de registre que la pile x87, mais c'était une sorte de pile similaire, qui a évolué pour donner la pile x87. Il s'agissait pour le coup d'une vraie pile, les opérations utilisaient systématiquement le sommet de la pile et l'opérande en dessous. Il n'y avait pas de possibilité d'adresser un opérande dans la pile. Le processeur intégrait 8 registres de 16 bits, organisés comme une pile. Les registres pouvaient être utilisés : soit comme une pile de 8 opérandes 16 bits, soit une pile de 4 opérandes 32 bits, soit une pile de 2 opérandes 64 bits. Les opérandes étaient empilées octet par octet dans le processeur. Ils étaient dépilés là aussi octet par octet. Pour cela, le 8231/8232 dispose de trois entrées nommées A0, RD et WR. Les trois bits décident s'il faut faire une lecture, une écriture, exécuter une instruction, ou lire le registre d'état. Les quatre opérations sont appelées des commandes dans la documentation Intel et AMD. Les trois entrées font donc office de bus de commande simplifié. {|class="wikitable" |- ! A0, RD, WR !! Action |- | 000 || Lecture de l'octet depuis les registres de données. |- | 010 || Écriture de l'octet dans les registres de données. |- | 111 || L'octet est l'opcode d'une instruction, qui est exécutée immédiatement. |- | 101 || Lecture du registre d'état. |} Le processeur principal envoyait des commandes à l'Intel 8231/8232, qui les exécutait dans son coin. Le 8231/8232 envoyait un signal END OF EXECUTION pour prévenir qu'il avait fini son travail, que la commande précédente était terminée. Il avait une broche dédiée, appelée END, dédiée à ça. Le coprocesseur avait donc une interface de communication asynchrone, qui se voit quand on étudie ses broches. Les broches suivantes servent à la communication asynchrone avec le 8231/8232. * READY est à 1 quand le 8231/8232 est libre, capable d'accepter une nouvelle instruction/commande. Il passe à 0 quand une instruction démarre, avec la commande 111 vue plus haut. * END indique que la commande précédente a terminé son exécution. Lorsque END passe à 1, BUSY passe automatiquement à 0. * EACK est une entrée sur laquelle le processeur dit qu'il a bien reçu le signal END, et que ce dernier peut être remis à 0. Ce système pouvait être utilisé avec du ''pooling'', avec des interruptions, voire du DMA. Avec des interruptions, la sortie END était utilisée comme sortie d'interruption, reliée au CPU ou au contrôleur d'interruption. Pour le ''pooling'', le registre d'état du 8231/8232 contenait un bit BUSY, qui indiquait si le coprocesseur était utilisé ou non. Un tel fonctionnement peut sembler étrange, et vous aurez l'impression que communiquer avec le coprocesseur est très lent. Mais cela prend tout son sens quand on connait le temps mis pour exécuter une instruction sur le coprocesseur. Une opération simple sur des flottants 32 bits prenait facilement une cinquantaine de cycles d'horloge, et c'était parmi les meilleurs temps de calcul. Il n'était pas rare d'avoir des opérations prenant plusieurs centaines, voire milliers de cycles d'horloge. Pas loin de 5000 cycles d'horloge pour une division de deux flottants 64 bits sur le 8232, plusieurs dizaines de milliers de cycles pour certaines opérations trigonométriques. Et le pire, c'était que c'était plus rapide que l'émulation logicielle ! Pas étonnant donc que le 8231/8232 aient été traités comme des entrées-sorties, à une époque ou tout était connecté sur un bus système assez rapide. Un autre avantage est que le 8231/8232 pouvaient fonctionner à une fréquence sans rapport avec celle du processeur. Par exemple, on pouvait utiliser un processeur à 1 MHz alors que le 8231/8232 allait à 4 MHz. Le coprocesseur faisait juste des calculs rapidement, comparé au CPU. Et ça a été utilisé sur certains systèmes Apple II. Ou encore, on pouvait utiliser un processeur légèrement plus rapide que le coprocesseur, avec quelques MHz de différence, comme un CPU à 5 MHz avec un coprocesseur de 2 MHz. ===L'intel 8087 et ses successeurs=== [[File:Intel 8087.svg|vignette|Intel 8087]] Le 8087 été fabriqué avec 65 000 transistors. Le 8087 avait pour particularité qu'il était connecté directement sur le bus mémoire, au même titre que le 8086. Mais le 8087 n'avait pas de bus d'adresse et de données séparé. Le processeur utilisait un bus multiplexé. Il avait 20 broches pour se connecter au bus : 16 d'entre elles servaient alternativement de bus d'adresse et de données. L'interface avec le bus était donc un peu compliquée. L'intel 387 était le coprocesseur associé au 386 d'Intel. Il était le premier coprocesseur à s'intégrer sur un bus de 32 bits. Il a été décliné en plusieurs versions, dont certaines sont spécifiques à un modèle de 386. Par exemple, le i386SX était une version simplifiée du 386 initial, qui avait notamment un bus de seulement 16 bits. Et de ce fait, il avait son propre coprocesseur i387SX, qui était adapté à un bus de 16 bits. De même, le i386SL était adapté aux ordinateurs portables et avait son propre coprocesseur i387SL. Tout ce qui va suivre est valide pour tous les coprocesseurs x87 de marque Intel. Le processeur central lisait des instructions, en envoyant le ''program counter'' sur le bus d'adresse, les instructions étaient récupérées sur le bus de données. Là, les deux processeurs déterminaient si l'instruction chargée était destinée au coprocesseur ou au CPU. Pour cela, les instructions x87 commencent toutes par la suite de bit 11011, qui permet de savoir facilement si une instruction est destinée au coprocesseur. Le 11011 était suivi par un opcode et un mode d'adressage. Si le mode d'adressage demandait de lire un opérande mémoire, le 8086 envoyait l'adresse de l'opérande sur le bus, et le coprocesseur récupérait celle-ci sur le bus de données. Si l'opérande devait être lu en plusieurs fois, le coprocesseur lisait le reste de lui-même, en prenant le contrôle du bus d'adresse. Il récupérait l'adresse envoyée initialement par le CPU, puis l'incrémentait et relançait un nouvel accès mémoire. Il l'incrémentait autant de fois que nécessaire pour charger l'opérande. Un problème est que le CPU ne sait pas combien de temps dure une instruction x87. Et cette durée dépendait de l'implémentation du processeur, elle n'était pas la même selon la marque du coprocesseur. Un 186 n'avait pas les mêmes timings que le 286, par exemple. Pour le CPU, une instruction x87 met juste deux cycles pour s'exécuter (plus si des opérandes doivent être lus en mémoire). Pour cela, le CPU disposait d'un mécanisme de synchronisation. Le mécanisme de synchronisation était une instruction WAIT, qui forçait le CPU à attendre que le coprocesseur ait terminé l'instruction précédente. L'implémentation matérielle était assez simple. Le coprocesseur disposait d'une sortie BUSY, qui indiquait qu'il était en train d'exécuter une instruction et ne pouvait pas en accepter une nouvelle. Le CPU, quant à lui, avait une entrée TEST qui vérifiait si le, coprocesseur était occupé ou non. La sortie BUSY était reliée à l'entrée TEST. L'instruction test vérifiait juste ce qu'il y avait sur l'entrée TEST. Tant qu'elle était à 1, le processeur attendait et ne chargeait pas de nouvelle instruction. Dès qu'elle passe à 0, l'exécution reprend. Il faut noter que l'instruction WAIT n'est nécessaire qu'entre deux instructions flottantes assez proches. Mais il est possible d'intercaler des instructions entières entre deux instructions flottantes. Le programme pouvait ainsi mixer instructions entières et flottantes, les instructions entières étant exécutées sur le 8086, les instructions flottantes sur le coprocesseur. Il y avait donc une possibilité de parallélisme, à savoir que les deux processeurs pouvaient exécuter des instructions différentes en même temps. Mais cela demandait que les calculs soient coopératifs et mélangent bien entiers et flottants. Le 8087 et ses successeurs avaient une microarchitecture assez simple. L'unité de contrôle contenait un décodeur d'instruction microcodé, le registre de contrôle, le registre d'état. La plupart des instructions sont microcodées, l'unité de calcul est assez limitée. Elle permet d'additionner deux mantisses flottantes, de faire des décalages, d'additionner deux exposants, mais pas plus. Les multiplications et divisions sont donc microcodées et émulées en enchainant des additions flottantes. Les instructions trigonométriques sont implémentées en utilisant l'algorithme CORDIC, qu'on a vu dans le chapitre sur les circuits de calcul flottant. [[File:Intel 8087 arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel 8087.]] Le chemin de données est composé d'un banc de registre flottant pour la pseudo-pile, et de plusieurs circuits de calcul. Le banc de registre était mono-port, ce qui fait que les ALUs étaient précédés par deux registres temporaires pour les opérandes. Les circuits pour l'exposant et la mantisse sont séparés, et sont même reliés au banc de registre par deux bus séparés. Il y a un additionneur pour les exposants, un additionneur pour les mantisses et un décaleur pour les mantisses (pour les normaliser). De plus, on trouve une mémoire ROM dédiée aux constantes les plus utilisées. Elle sert pour les constantes de base, gérées par le jeu d'extension x87. Mais elle contient aussi des constantes utilisées pour l'algorithme CORDIC. Elle n'est pas illustrée sur le schéma ci-dessous, mais elle existe. L'interface avec le bus est un simple registre d’interfaçage avec le bus. Pour rappel, le bus de données fait 16 bits sur le 8087, 32 bits sur le 387. Entre le bus et le chemin de données, on trouve une file servant à simplifier la gestion des lectures. L'idée est que les opérandes lus/écrits font 32, 64 ou 80 bits, alors que le bus de données n'en fait que 16/32. Les opérandes sont donc lus/écrits en plusieurs passes. Sur le 8087, il doit réaliser deux passes pour des opérandes de 32 bits, quatre passes pour celles de 64 bits, 5 pour des opérandes de 80 bits (80 = 5 × 16). Le 387 doit faire deux fois moins. [[File:Intel 387 arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel 387. Les circuits pour les exposants sont à gauche dans le chemin de données, les circuits pour les mantisses sont à droite.]] L'implémentation du banc de registre est assez simple : une RAM avec un registre qui indique la position du sommet de la pile dedans. Le registre fait 3 bits, pour 8 registres. En plus de cela, il y a un petit soustracteur et un multiplexeur, pour adresser les opérandes dans la pile. Pour rappel, il est possible d'adresser la seconde opérande dans la pile. Mais on précise pas le numéro du registre dans la pile pour cela, on précise sa position sous le sommet de la pile, à savoir si elle est deux, trois, quatre opérandes sous le sommet de la pile. Pour déterminer quel registre lire, il faut soustraire ce "décalage" au numéro de registre du sommet de la pile. Pour cela, il y a un petit soustracteur pour faire le calcul. Le circuit décaleur est composé de deux sous-décaleurs. Le premier fait des décalages au niveau des octets, le second décale l'opérande de 0 à 7 rangs. Pour finir, voici quelques liens sur la microarchitecture du 8087 : * [https://www.righto.com/2026/02/8087-instruction-decoding.html Instruction decoding in the Intel 8087 floating-point chip]. * [https://www.righto.com/2020/05/die-analysis-of-8087-math-coprocessors.html Die analysis of the 8087 math coprocessor's fast bit shifter]. * [https://www.righto.com/2025/12/8087-stack-circuitry.html The stack circuitry of the Intel 8087 floating point chip, reverse-engineered]. * [https://www.righto.com/2025/12/8087-microcode-conditions.html Conditions in the Intel 8087 floating-point chip's microcode]. * [https://www.righto.com/2020/05/extracting-rom-constants-from-8087-math.html Extracting ROM constants from the 8087 math coprocessor's die]. * [https://www.righto.com/2018/09/two-bits-per-transistor-high-density.html Two bits per transistor: high-density ROM in Intel's 8087 floating point chip]. ===Les coprocesseurs x87 de Weitek=== Intel n'a pas été le seul fabricant à commercialiser des coprocesseurs x87. Weitek et de nombreuses autres entreprises s'y sont mises. Weitek a commercialisé plusieurs coprocesseurs : un premier coprocesseur appelé le 1067, le 1167, le 2167, le 3167 et le 4167. Ils sont tous rétrocompatibles entre eux, à savoir que le 4167 ne fait qu'ajouter des fonctionnalités au 3167, qui lui-même ajoute des fonctionnalités au 2167, et ainsi de suite. Ils gèrent tous les quatre opérations de base, ainsi que le calcul de la racine carrée. Le '''Weitek 1067''' avait pour particularité d'être fourni en pièces détachées, avec trois circuits séparés : un circuit de contrôle, une ALU flottante, et un multiplieur/diviseur. Ces trois pièces détachées étaient censées être soudées sur la carte mère. Le '''Weitek 1167''' regroupait ces trois pièces détachées sur une carte d'extension ISA. Par la suite, le '''Weitek 2167''' regroupa les trois pièces détachées dans un seul circuit imprimé. Il n'y avait pas de registres flottants adressables, ni de pile de registres. À la place, l'ALU et le multiplieur/diviseur intégraient deux registres pour les opérandes et un registre accumulateur. Les opérandes étaient présentés sur le bus de données et l'ALU les mémorisait dans deux registres internes de 64 bits chacun, nommés A et B. Le coprocesseur lisait les opérandes depuis ces deux registres et mémorisait le résultat dans un registre de résultat interne. Il envoyait alors le résultat sur le bus de données, prévenait le CPU avec une interruption, et le CPU récupérait le résultat sur le bus. Il faut noter que toutes les communications avec l'ALU passent par le bus de données, appelé le bus X. La transmission d'un flottant 32 bits se faisait en un cycle d'horloge, vu que le bus était de 32 bits. Par contre, la transmission d'un flottant 64 bits se faisait en deux cycles. À part le bus de données, il y avait un bus de commande, relié à l'unité de contrôle 1163. Elle envoyait l'opcode sur une entrée dédiée, notée F. Les bits de commande L, CSL, CSUS, CUSX, U commandent la lecture des opérandes ou leur écriture. L'unité de contrôle recevait le registre d'état via une sortie dédiée nommée S ou STATUS. [[File:Weitek WTL1167 arch.svg|centre|vignette|upright=2.5|Weitek WTL1167.]] Pour charger les opérandes dans l'ALU, celle-ci intégrait diverses entrées de commande nommées L0, L1, L2, L3 et CSL. * Le signal CSL est le ''Chip Select Load'', ce qui indique qu'il est mis à 1 lors d'une lecture. * Le bit L0 à 1 indique qu'un opcode est envoyé sur l'entrée F, l'entrée pour l'opcode est recopiée dans un registre interne, qui n'est pas un registre d'instruction vu que l'ALU n'a pas de décodeur. * Les bits L1 et L2 indiquent si ce qu'il y a sur le bus est : un flottant 32 bits, les 32 bits de poids fort d'un flottant 64 bits, les 32 bits de poids faible d'un flottant 64 bits. * Le registre L3 indique quel est le registre de destination : A ou B. Les signaux U, CSUS et CSUX servaient pour l'envoi du résultat sur le bus. Ils précisaient s'il fallait copier un flottant 32 bits, les 32 bits de poids fort d'un flottant 64 bits, les 32 bits de poids faible d'un flottant 64 bits. Le '''Weitek 3167''' était conçu pour fonctionner en tandem avec un CPU Intel 386, alors que le '''Weitek 4167''' était prévu pour aller avec un Intel 486, mais ils fonctionnaient de la même manière au-delà de quelques détails. Contrairement à leurs prédécesseurs, ils intégraient 32 registres flottants de 32 bits. Un registre pair et un registre impair pouvaient être concaténés pour mémoriser un opérande 64 bits. Les opérations se faisaient soit entre deux registres flottants, soit entre un registre flottant et l'opérande présentée sur le bus de données. Le résultat est stocké dans un registre flottant. Leur registre de status contenait les résultats des comparaisons flottantes, ainsi que 8 bits pour les exceptions flottantes. Le registre de contrôle avait un champ pour configurer les arrondis, mais aussi un masque d'exceptions de 8 bits disant quels bits d'exceptions ignorer dans le registre de statut. Le coprocesseur est mappé en mémoire, ce qui fait qu'il a des adresses réservées dans lesquelles le processeur peut lire/écrire, pour lui envoyer une instruction, envoyer un opérande ou récupérer un résultat. Les adresses en question sont les adresses COOO OOOOh à COOO FFFFh, ce qui fait que le coprocesseur est adressé si les 16 bits de poids fort de l'adresse valent COOO. Par contre, les 65536 adresses réservées n'étaient pas associées à de la mémoire, pas même aux registres. A la place, les 16 bits de poids faible de l'adresse encodaient une instruction au coprocesseur, à savoir un opcode de 6 bits deux numéros de registres. Le processeur communique avec le coprocesseur en envoyant l'instruction sur le bus d'adresse, et éventuellement un opérande sur le bus de données. L'opérande vient généralement des registres, par simplicité, car cela permet de tout envoyer en une seule écriture. Par exemple, une écriture du registre EAX à l'adresse COOO OOOOh va copier le registre EAX sur le bus de données, et envoyer l'opcode de l'addition (0000) sur le bus d'adresse avec deux numéros de registre. Le coprocesseur fait alors une addition entre le registre flottant sélectionné, et l'opérande sur le bus de données copiée depuis EAX. ==Le Motorola 68881 et le 68882== Le 68881 de Motorola était conçu pour fonctionner avec les CPU 68020 et 68030. Les programmes mixaient instructions entières et flottantes, le 68000 exécutant les instructions entières, le 68881 exécutant les instructions flottantes. Les instructions flottantes avaient un opcode qui commençait par F (en hexadécimal), ce qui permettait de les distinguer rapidement du reste. Le 68000 chargeait les instructions, et regardait si l'instruction était destinée soit au coprocesseur, soit pour lui. Pour une instruction coprocesseur, il lisait les opérandes en RAM, puis envoyait instruction et opérandes au 68881. Il continuait son travail dans son coin, et récupérait le résultat quelques cycles plus tard. Malgré le fait qu'il y ait des instructions destinées au coprocesseur, le 68881 n'était pas un coprocesseur fortement couplé. A la place, le 68881 était géré comme une entrée-sortie, du point de vue du CPU. Il était mappé en mémoire, avait une entrée ''Chip Select'' commandé par décodage d'adresse. Il contenait aussi des registres d'interface, appelés des ''coprocessor interface registers'' (CIRs). Il y avait des registres pour l'opcode de l'instruction à exécuter, un autre pour chaque opérande, etc. Pour envoyer une instruction au 68881, le CPU avait juste à écrire dans les registres adéquats, idem pour charger les opérandes de l'instruction si besoin. Les coprocesseurs Motorola utilisaient des flottants codés sur 80 bits : la mantisse était codée sur 64 bits, l'exposant sur 15 bits. Le 68881 incorporait 8 registres flottants, nommés, de 80 bits chacun. Fait étonnant, cela ressemble beaucoup à ce qui est fait avec les coprocesseurs x87 : usage de flottants codés sur 80 bits, 8 registres flottants. Mais les détails sont différents, le jeu d'instruction est complétement différent. Les coprocesseurs Motorola avaient aussi un registre de statut et un registre de contrôle, guère plus. Le registre de statut mémorisait les conditions classiques, mais aussi des bits pour les exceptions qui ont été levées lors d'un calcul. Le registre de contrôle mémorisait de quoi configurer les arrondis, mais aussi un masque pour indiquer quelles exceptions ignorer dans le registre de statut. Pareil que pour les processeurs précédents, donc. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Un exemple de jeu d'instruction : l'extension x87 | prevText=Un exemple de jeu d'instruction : l'extension x87 | next=Les ISA optimisés pour la compilation/interprétation | nextText=Les ISA optimisés pour la compilation/interprétation }} </noinclude> 4tne70o06k7rmfw6imwmatie2vpb67q Mathc initiation/006f 0 84481 772130 771402 2026-09-13T10:41:27Z Xhungab 23827 772130 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t)'+y(t)=1 avec y(0) = 0|Sommaire]] : '''Résoudre l'équation : ''' y(t)' + 2 y(t) = 4 y(0) = 1 '''Utilisons la transformée de Laplace''' : L{y(t)'} + 2 L{y(t)} = L{4} sY(s) - y(0) + 2 Y(s) = 4/s y(0) = 1 sY(s) - 1 + 2 Y(s) = 4/s Y(s) (s + 2) = 4/s + 1 4/s + 1 Y(s) = -------- (s + 2) 4 + s Y(s) = --------- s (s + 2) '''Utilisons la méthode des fractions partielles.''' '''[[Mathc initiation/006g|Voir explication Ici]]''' 4 + s A B Y(s) = --------- = --- + ------ s (s + 2) s (s + 2) si s = 0 A = 2 si s = -2 B = -1 donc 4 + s 2 1 Y(s) = ---------- = -- - ------ s (s + 2) s (s + 2) '''Utilisons la transformée inverse de Laplace :''' 2 1 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{--} - L<sup>-1</sup>{ -------- } s (s-(- 2)) ---------------------- | y(t) = 2 - exp(-2t) | ---------------------- '''Vérifions :''' y(t)' + 2 y(t) = 4 y(0) = 1 (2-exp(-2t))' + 2 (2-exp(-2t)) = 4 2exp(-2t) + 4-2 exp(-2t)) = 4 4 = 4 {{AutoCat}} p60r0ib9ct6ti4ji9kgfft39q2s0m0n Mathc initiation/006h 0 84483 772134 771404 2026-09-13T10:42:40Z Xhungab 23827 772134 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3|Sommaire]] : '''Résoudre l'équation : ''' y(t) ' ' + 3 y(t)' + 2 y(t) = 0 avec *** y(0)=(1), y(0)'=(0) '''Utilisons la transformée de Laplace''' : L{y(t) ' '} + 3 L{y(t)'} + 2 L{y(t)} = L{0} [s**2 Y(s) - s y(0) - y(0)'] + 3 [s Y(s) - y(0)] + 2 [Y(s)] = 0 avec *** y(0)=(1), y(0)'=(0) [s**2 Y(s)-s (1)-(0)] + 3 [s Y(s)-(1)] + 2 [Y(s)] = 0 [s**2 Y(s)-s] + 3 [s Y(s)-1] + 2 [Y(s)] = 0 s**2 Y(s) - s + 3 s Y(s) - 3 + 2 Y(s) = 0 s**2 Y(s) + 3 s Y(s) + 2 Y(s) = (s+3) (s**2+3 s+2) Y(s) = (s+3) (s+3) (s+3) Y(s) = ------------ = ---------- (s**2+3 s+2) (s+1)(s+2) '''Utilisons la méthode des fractions partielles.''' '''[[Mathc initiation/006i|Voir explication Ici]]''' (s+3) A B Y(s) = ---------- = ----- + ----- (s+1)(s+2) (s+1) (s+2) si s = -1 A = 2 si s = -2 B = -1 donc (s+3) 2 1 Y(s) = ---------- = ----- - ------ (s+1)(s+2) (s+1) (s+2) '''Utilisons la transformée inverse de Laplace :''' L<sup>-1</sup>{Y(s)} = 2 L<sup>-1</sup>{1/(s-(-1))} - L<sup>-1</sup>{1/(s-(-2)) } ------------------------------ | y(t) = 2 exp(-t) - exp(-2t) | ------------------------------ {{AutoCat}} 0hucx7pkdshajo80a6cc8gjorxs2klp Wikilivres:Prise de décision/Créer un espace lecteurs et un espace auteurs sur la page d'accueil 4 84486 772077 772075 2026-09-12T14:41:51Z Xhungab 23827 772077 wikitext text/x-wiki {{Prise de décision}} ==Présentation== '''Le problème :''' Actuellement, si un lecteur essaie de parcourir la bibliothèque à partir des listes : Arts, Loisirs, Histoire, Langues... Il se retrouve dans un labyrinte qui fini souvent sur une ébauche abandonné depuis plus de 5, 10, 15, 20 ans. '''La solution :''' Cette page [https://fr.wikibooks.org/wiki/Utilisateur:Xhungab '''Wikibook'''] propose la vitrine, les livres disponibles, les mini-livres disponibles pour les lecteurs. Les lecteurs ne seront en contact qu'avec les livres terminés. . En bas à côté des nouveautés, il y a '''[https://fr.wikibooks.org/wiki/Discussion_utilisateur:Xhungab Les coulisses de Wikibook]''', que l'on pourrait appeler, '''le local technique'''... avec tous les livres du site rangés par thème ou par niveau d'avancement si on clique sur l'image, ou bien des listes où les livres sont rangés par catégories. . '''Cette proposition sépare donc deux espaces. Un pour les étudiants qui cherchent à travailler sur un des livres de la bibliothèque et un pour les personnes curieuses qui veulent connaître les coulisses de Wikibook .''' . Ces changements ne demandent aucune modification technique. . Juste la création d'une page '''[https://fr.wikibooks.org/wiki/Discussion_utilisateur:Xhungab Les coulisses de Wikibook]'''. Il suffit de copier le tableau présent dans la page vitrine actuelle, et d'ajouter un petit texte de bienvenue. (10 minutes) . Modification de la page vitrine actuelle. . Insérer le lien de la page ci-dessus devant le lien "Nouveautés". en bas de la page. . Supprimer tous les liens : Arts, Loisirs, Histoire, et les remplacer par : * [[:Catégorie:Livres terminés|Livres disponibles]] * [[:Catégorie:Minilivres|Mini Livres disponibles]] (10 minutes) . En moins de 20 minutes, on a créé un espace convivial pour les lecteurs où les livres, tous terminés, sont rangés par ordre alphabétique, et un Espace technique, avec tous les livres du site rangés par thème ou par niveau d'avancement ou par catégories . Si cette proposition s'avérait mauvaise, il suffirait de remettre la version originale et de supprimer la page espace pour les auteurs. (2 minutes) Merci de m'avoir suivie jusqu'ici.[[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 30 août 2026 à 00:38 (CEST) == Discussions == [[Wikilivres:Le Bistro/2026|Voir les discussions antécédentes dans le bisto]] Suite à ce message : '''Les autres wikis utilisent déjà les sous-pages de l'auteur pour les brouillons, donc si les nouveaux ne respectent pas ça, ils posteront encore moins dans un nouvel espace.''' Dans un premier temps j'ai utilisé '''le titre un espace lecteurs et un espace auteurs'''. J'ai choisi le titre l'espace auteurs pour le mettre en opposition à l'espace lecteurs pour indiquer aux étudiants que si leur but était d'étudier leurs cours, l'espace pour les auteurs n'était pas approprié. J'ai donc remplacé '''Un espace auteurs''' par '''Les coulisses de Wikibook''' car cela a provoqué un malentendu. Les auteurs n'ont aucune obligation d'utiliser quoi que ce soit.Cet espace donne juste accès à tout le contenu de Wikibook comme le fait la version originale de la page de Wikibook. [[Utilisateur:Xhungab|Xhungab]] ---- ---- Je comprends bien l'idée de mieux distinguer dans la présentation les nouveautés finies des nouveautés en cours. Il me semble plus pertinent de distinguer cela en mettant en valeur sur une même page d'abord les livres finis tout en gardant sur la même page les livres en cours d'élaboration qui peuvent être tout aussi intéressant. Il ne me semble pas forcément pertinent d'après ce que j'ai compris, de créer un autre espace plus lointain et plus difficile d'accès pour les créations en cours. Si les coulisses de wiki livre crée un espace plus lointain et plus difficile d'accès pour ses livres en cours de création alors je suis contre la proposition. Il me semble d'ailleurs que le nombre de livres ne soit pas si grand et ne justifie pas une séparation aussi nette. Un livre en cours d'élaboration peut être tout aussi intéressant qu'un livre fini. [[Utilisateur:Sicarov|Sicarov]] Avez vous vu la deuxième proposition? [https://fr.wikibooks.org/wiki/Wikilivres:Prise_de_d%C3%A9cision/Modifier_le_contenue_de_l%27espace_Nouveaut%C3%A9s Wikilivres:Prise de décision/Modifier le contenue de l'espace Nouveautés] Les nouveaux livres et les livres en construction active seront mis en avant dans l'espace nouveauté.[[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 21:33 (CEST) :Bonjour, j'ai pu regarder l'espace des nouveautés. Je n'ai pas peut-être pas bien tout compris. :Mais une chose dont je suis sûr c'est que plus l'information est loin avec un nombre de clics nécessaires, moins elle est accessible. J'aime beaucoup utiliser les dynamics qui sont présents sur les catégories existantes pour voir l'activité des nouveaux livres entre guillemets. :Certaines '''Dynamic list''' bien trouvées pourrait avoir leur place '''dans la page d'accueil de wiki livre''' pour montrer un échantillon de ce qui est en train de se faire. :J'ai également fait sur wiki source fr un switch avec plusieurs auteurs qui tournent. Un switch de livre pourrait également être proposé sur la page d'accueil avec une série de livres exemplaire et pertinent. [[Utilisateur:Sicarov|Sicarov]] ([[Discussion utilisateur:Sicarov|discussion]]) 11 septembre 2026 à 23:11 (CEST) ::Les noms des nouveaux livres et des livres en constructions active apparaîtrons en dessous des trois livres de la vitrine. Il suffira de ::cliquer sur le nom du livre en construction pour tomber sur sa page. Vous pouvez essayer sur l'exemple proposer. '''Pourriez vous cliquer sur l'image des livres dans la vitrine, pour voir si cela correspond à votre proposition.''' ::* '''Nouveautés et Projets En Construction Actif :''' [[Chanter les psaumes]] ::* '''Cette espace peut contenir une vingtaine de livres''' ::* '''[https://fr.wikibooks.org/wiki/Utilisateur:Xhungab '''Wikibook''']''' ::* [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 23:19 (CEST) == Votes == Votez {{m|Pour}} / {{m|Contre}} / {{m|Neutre}}, avec vos arguments. # {{Pour}} Très bonne proposition. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 30 août 2026 à 00:47 (CEST) # {{Pour}} Et je propose alors de créer deux nouvelles pages qui affichent le contenu des différentes catégories de manières esthétique et contextualisée, grâce à l'[[mw:Extension:CategoryTree]]. Une première page pour les livres terminés ([[Utilisateur:Lionel Scheepmans/page avec liste des livres terminés|exemple]]) et une seconde pour les livres inachevés. # {{neutre}} Les autres wikis utilisent déjà les sous-pages de l'auteur pour les brouillons, donc si les nouveaux ne respectent pas ça, ils posteront encore moins dans un nouvel espace. [[Utilisateur:JackPotte|JackPotte]] ([[Discussion utilisateur:JackPotte|<span style="color:#FF6600">$</span>♠]]) 30 août 2026 à 11:31 (CEST) # {{contre}} les livres en cours de création sont tout aussi intéressants que des livres finis. Je veux éviter une plus grande invisibilisation des livres en cours de création. La proposition actuelle et peut-être plus nuancée. [[Utilisateur:Sicarov|Sicarov]] ([[Discussion utilisateur:Sicarov|discussion]]) 11 septembre 2026 à 19:56 (CEST) # {{Pour}} Le principe est bon, clairement séparer les livres terminés de ceux en recherche de contributeurs me plait, avoir un fourre-tout accesible sur la page d'accueil n'est pas l'idéal. J'aurais juste une remarque : le nom "Les coulisses de Wikibook" n'est pas très parlant. J'aurais plus utilisé "Wikilivres en cours de rédaction" ou "Wikilivres en recherche de contributeurs".[[Utilisateur:Mewtow|Mewtow]] ([[Discussion utilisateur:Mewtow|discussion]]) 11 septembre 2026 à 22:46 (CEST) #:Les coulisses de Wikibook était juste un nom pour la présentation de la nouvelle page. [[Utilisateur:Xhungab|Xhungab]] ([[Discussion utilisateur:Xhungab|discussion]]) 11 septembre 2026 à 23:10 (CEST) == Décision == . 2qyu1sebxbqvp6fukfxmv5626q9hr0z Mathc initiation/006j 0 84488 772132 771531 2026-09-13T10:41:55Z Xhungab 23827 772132 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t)'+y(t)=1 avec y(0) = 0|Sommaire]] : '''Résoudre l'équation : ''' y(t)' + 3 y(t) = exp(-2t) y(0) = 2 '''Utilisons la transformée de Laplace''' : L{y(t)'} + 3L{y(t)} = L{exp(-2t)} sY(s) - y(0) + 3 Y(s) = 1/(s+2) y(0) = 2 sY(s) - 2 + 3 Y(s) = 1/(s+2) sY(s) + 3 Y(s) = 1/(s+2) +2 Y(s) (s+3) = 1/(s+2) +2 Y(s) (s+3) = 1/(s+2) +2(s+2)/(s+2) Y(s) (s+3) = (1+2(s+2))/(s+2) Y(s) (s+3) = (1+2s+4)/(s+2) Y(s) (s+3) = (2s+5)/(s+2) Y(s) = (2s+5)/((s+2)(s+3)) '''Utilisons la méthode des fractions partielles.''' '''[[Mathc initiation/006k|Voir explication Ici ]]''' (2s+5) A B Y(s) = ---------- = ----- + ----- (s+2)(s+3) (s+2) (s+3) si s = (-2) A = 1 si s = (-3) B = 1 donc Y(s) = (2s+5)/ ((s+2)(s+3)) Y(s) = A/(s+2) + B/(s+3) Y(s) = 1/(s+2) + 1/(s+3) '''Utilisons la transformée inverse de Laplace :''' 1 1 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{ ---- } + L<sup>-1</sup>{ ---- } (s+2) (s+3) 1 1 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{ ------- } + L<sup>-1</sup>{ ------- } (s-(-2)) (s-(-3)) ---------------------------- | y(t) = exp(-2t) + exp(-3t) | ----------------------------- '''Vérifions :''' y(t)' + 3 y(t) = exp(-2t) ( exp(-2t) + exp(-3t))' + 3 (exp(-2t) + exp(-3t)) = exp(-2t) (-2exp(-2t) - 3exp(-3t)) + 3exp(-2t) + 3exp(-3t) = exp(-2t) (-2exp(-2t) + 3exp(-2t) = exp(-2t) exp(-2t) = exp(-2t) {{AutoCat}} p1r3q0jqdobinkwdr3rh7wimwengnsp Mathc initiation/006l 0 84491 772131 771571 2026-09-13T10:41:40Z Xhungab 23827 772131 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] : [[Mathc initiation/006r#* Résoudre : y(t)'+y(t)=1 avec y(0) = 0|Sommaire]] : '''Résoudre l'équation : ''' y(t)' + 2 y(t) = exp(-t) y(0) = 1 '''Utilisons la transformée de Laplace''' : L{y(t)'} + 2L{y(t)} = L{exp(-t)} sY(s) - y(0)+ 2 Y(s) = 1/(s+1) y(0) = 1 sY(s) - 1 + 2 Y(s) = 1/(s+1) sY(s) + 2 Y(s) = (1/(s+1)+1) Y(s) (s+ 2) = (1/(s+1)+1) Y(s) (s+ 2) = (1/(s+1) +1(s+1)/(s+1)) Y(s) (s+ 2) = (1+1(s+1))/(s+1) Y(s) (s+ 2) = (1+s+1)/(s+1) Y(s) (s+2) = (2+s)/(s+1) Y(s) = (2+s)/((s+1)(s+2)) Y(s) = 1/(s+1) '''Utilisons la transformée inverse de Laplace :''' 1 L<sup>-1</sup>{Y(s))} = L<sup>-1</sup>{ ------ } s-(-1) ---------------- | y(t) = exp(-t) | ---------------- '''Vérifions :''' y(t)' + 2 y(t) = exp(-t) (exp(-t))' + 2 exp(-t) = exp(-t) -exp(-t) + 2 exp(-t) = exp(-t) exp(-t) = exp(-t) {{AutoCat}} dupg848auf48yes4o7dd40ptog3e5vj Mathc initiation/006o 0 84499 772122 771975 2026-09-13T10:29:54Z Xhungab 23827 772122 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] '''La transformée de Laplace translation de la variable s : ''' ''' L{exp(a*t) F(t)} = f(s-a)''' '''Remarque :''' L{sin(t)} = 1/(s^2+1) ... L{sin(bt)} = b/(s^2+b^2) L{cos(t)} = s/(s^2+1) ... L{cos(bt)} = s/(s^2+b^2) L{sinh(t)} = 1/(s^2-1) ... L{sinh(bt)} = b/(s^2-b^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(bt)} = s/(s^2-b^2) a) '''Calculons la transformée de Laplace de :''' (L{exp(a*t) F(t)} = f(s-a)) L{exp(a t) sin(b t)} = b/((s-a)^2+b^2) b) '''Calculons la transformée de Laplace de :''' (L{exp(a*t) F(t)} = f(s-a)) L{exp(a t) cos(b t)} = (s-a)/((s-a)^2+b^2) c) '''Calculons la transformée de Laplace de :''' (L{exp(a*t) F(t)} = f(s-a)) L{exp(a t) sinh(b t)} = b/((s-a)^2-b^2) d) '''Calculons la transformée de Laplace de :''' (L{exp(a*t) F(t)} = f(s-a)) L{exp(a t) cosh(b t)} = (s-a)/((s-a)^2-b^2) * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} ewcxljvclgii05029c77dqi1b4jmeqh Mathc initiation/006p 0 84501 772126 772050 2026-09-13T10:34:36Z Xhungab 23827 772126 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] '''La transformée de Laplace Multiplication par t : ''' '''L{t F(t)} = (-1) f'(s)''' '''Remarque :''' L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) L{sinh(t)} = 1/(s^2-1) ... L{sinh(at)} = a/(s^2-a^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(at)} = s/(s^2-a^2) '''a) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1) f'(s)) L{t sin(a t)} = (-1) [a/(s^2+a^2)]' = (-1) (a) [(s^2+a^2)^(-1)]' = (-1) (a) (-1)(s^2+a^2)^(-2) [s^2+a^2]' = (a) (s^2+a^2)^(-2) (2)s 2 a s = ----------- (s^2+a^2)^2 '''b) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1) f'(s)) s L{t cos(a t)} = (-1) [-------]' s^2+a^2 (1)(s^2+a^2) - s (2s) = (-1) --------------------- (s^2+a^2)^2 s^2+a^2 - 2s^2 = (-1) -------------- (s^2+a^2)^2 a^2-s^2 = (-1) ----------- (s^2+a^2)^2 s^2-a^2 = ----------- (s^2+a^2)^2 '''c) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1) f'(s)) L{t sinh(a t)} = (-1) [a/(s^2-a^2)]' = (-1) (a) [(s^2-a^2)^(-1)]' = (-1) (a) (-1)(s^2-a^2)^(-2) [s^2-a^2]' = (a) (s^2-a^2)^(-2) (2)s 2 a s = --------- (s^2-a^2)^2 '''d) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1) f'(s)) s L{t cosh(a t)} = (-1) [-------]' s^2-a^2 (1)(s^2-a^2) - s(2s) = (-1) -------------------- (s^2-a^2)^2 s^2-a^2 - 2s^2 = (-1) -------------- (s^2-a^2)^2 -s^2-a^2 = (-1) ----------- (s^2-a^2)^2 s^2+a^2 = ----------- (s^2-a^2)^2 * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} nth00zy6y7b78yvgiakrfx3hssbo6tf Mathc initiation/006q 0 84502 772079 2026-09-12T14:50:00Z Xhungab 23827 news 772079 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a512#* la Transformée Inverse de Laplace : Le Théorème De Convolution| Sommaire]] '''La transformée de Laplace Multiplication par t^2 : ''' '''L{t F(t)} = (-1)^2 f"(s)''' '''Remarque :''' L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) L{sinh(t)} = 1/(s^2-1) ... L{sinh(at)} = a/(s^2-a^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(at)} = s/(s^2-a^2) a) Calculons la transformée de Laplace de : L{t^2 sin(a t)} = (-1)^2 [a/(s^2+a^2)]" 2a (a^2-3s^2) = (-) ------------- (a^2+s^2)^3 b) Calculons la transformée de Laplace de : s L{t^2 cos(a t)} = (-1)^2 [-------]" s^2+a^2 2s (s^2-3a^2) = (-) ------------- (a^2+s^2)^3 c) Calculons la transformée de Laplace de : L{t^2 sinh(a t)} = (-1)^2 [a/(s^2-a^2)]" 2a (a^2+3s^2) = (-) ------------- (a^2-s^2)^3 d) Calculons la transformée de Laplace de : s L{t^2 cosh(a t)} = (-1)^2 [-------]" s^2-a^2 2s (3a^2+s^2) = (-) ------------- (s^2-a^2)^3 * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} 00laszp1c3ho1xbgebyst8o8w6jayar 772127 772079 2026-09-13T10:36:44Z Xhungab 23827 772127 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/006s|Sommaire]] '''La transformée de Laplace Multiplication par t^2 : ''' '''L{t F(t)} = (-1)^2 f"(s)''' '''Remarque :''' L{sin(t)} = 1/(s^2+1) ... L{sin(at)} = a/(s^2+a^2) L{cos(t)} = s/(s^2+1) ... L{cos(at)} = s/(s^2+a^2) L{sinh(t)} = 1/(s^2-1) ... L{sinh(at)} = a/(s^2-a^2) L{cosh(t)} = s/(s^2-1) ... L{cosh(at)} = s/(s^2-a^2) '''a) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1)^2 f"(s)) L{t^2 sin(a t)} = (-1)^2 [a/(s^2+a^2)]" 2a (a^2-3s^2) = (-) ------------- (a^2+s^2)^3 '''b) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1)^2 f"(s)) s L{t^2 cos(a t)} = (-1)^2 [-------]" s^2+a^2 2s (s^2-3a^2) = (-) ------------- (a^2+s^2)^3 '''c) Calculons la transformée de Laplace de :''' (L{t F(t)} = (-1)^2 f"(s)) L{t^2 sinh(a t)} = (-1)^2 [a/(s^2-a^2)]" 2a (a^2+3s^2) = (-) ------------- (a^2-s^2)^3 d) Calculons la transformée de Laplace de : (L{t F(t)} = (-1)^2 f"(s)) s L{t^2 cosh(a t)} = (-1)^2 [-------]" s^2-a^2 2s (3a^2+s^2) = (-) ------------- (s^2-a^2)^3 * '''Vérifions''' avec [https://www.wolframalpha.com/input?i=laplace+transform Mathematica] : {{AutoCat}} ld1og6zy5ewqb2twxcpr7v88fhles3v Mathc initiation/006r 0 84503 772113 2026-09-13T10:13:36Z Xhungab 23827 news 772113 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] {{Partie{{{type|}}}|la Transformée de Laplace : Quelques applications}} : {{Partie{{{type|}}}|[[Mathc initiation/a547|* Résoudre : y(t)'+y(t)=1 avec y(0) = 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/a00ad|* Résoudre : y(t)'+3 y(t)=6 avec y(0) = 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/006f|* Résoudre : y(t)'+2 y(t)=4 avec y(0) = 1]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/006l|* Résoudre : y(t)'+2y(t)=exp(-t) avec y(0) = 1]]}} {{Partie{{{type|}}}|[[Mathc initiation/006j|* Résoudre : y(t)'+3y(t)=exp(-2t) avec y(0) = 2]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a608|* Résoudre : y(t) ' ' - 9 y(t) = 0 avec y(0) = 1 et y(0)' = 3]]}} {{Partie{{{type|}}}|[[Mathc initiation/006h|* Résoudre : y(t) ' ' + 3 y(t)' + 2 y(t) = 0 avec y(0)=1 y(0)'=0]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a613|* Résoudre un sytème d'équations différentielles]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/a580|* L'intégrale impropre en posant s tend vers 0]]}} {{Partie{{{type|}}}|[[Mathc initiation/a564|* L'intégrale impropre avec la multiplication par t^n avec n=1]]}} {{Partie{{{type|}}}|[[Mathc initiation/a565|* L'intégrale impropre avec la division par t]]}} : . : '''Quelques rappels mathématiques : ''' {{Partie{{{type|}}}|[[Mathc initiation/a566|* Trigonométriques. Trigonométriques hyperboliques]]}} {{Partie{{{type|}}}|[[Mathc initiation/a569|* Fractions partielles]]}} : . : {{AutoCat}} nvey1v6zqxvqvsm5knbqjrsn3sqss2l Mathc initiation/006s 0 84504 772118 2026-09-13T10:21:26Z Xhungab 23827 news 772118 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] {{Partie{{{type|}}}|la Transformée de Laplace : Quelques exercices}} {{Partie{{{type|}}}|[[Mathc initiation/a538|* Calculons : L{sin(t)sin(2t)} L{cos(3t)cos(2t)} L{sin(4t)cos(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a549|* Calculons : L{sinh(t)sinh(2t)} L{cosh(3t)cosh(2t)} L{sinh(4t)cosh(3t)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/a526|* Calculons : L{cos(2t)^2} L{sin(3t)^2} L{cos(2t)^3} L{sin(4t)^3}]]}} {{Partie{{{type|}}}|[[Mathc initiation/Fichiers h : c44a4|* Calculons : L{cosh(2t)^2} L{sinh(3t)^2} L{cosh(2t)^3} L{sinh(4t)^3}]]}} : . : {{Partie{{{type|}}}|[[Mathc initiation/006o|* Calculons : L{exp(at)sin(bt)} L{exp(at)sinh(bt)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006p|* Calculons : L{t sin(at)} L{t sinh(at)}]]}} {{Partie{{{type|}}}|[[Mathc initiation/006q|* Calculons : L{t^2 sin(at)} L{t^2 sinh(at)}]]}} : . : '''Quelques rappels mathématiques : ''' {{Partie{{{type|}}}|[[Mathc initiation/a566|* Trigonométriques. Trigonométriques hyperboliques]]}} {{Partie{{{type|}}}|[[Mathc initiation/a569|* Fractions partielles]]}} : . : {{AutoCat}} 7acru1o5wgyo5ti1z79qv8huq0o4shd