<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Triceraprog</title><link href="https://www.triceraprog.fr/" rel="alternate"></link><link href="https://www.triceraprog.fr/feeds/all.atom.xml" rel="self"></link><id>https://www.triceraprog.fr/</id><updated>2026-04-06T00:00:00+02:00</updated><subtitle>La programmation depuis le Crétacé</subtitle><entry><title>Comparaisons 8 bits en Z80</title><link href="https://www.triceraprog.fr/comparaisons-8-bits-en-z80.html" rel="alternate"></link><published>2026-04-06T00:00:00+02:00</published><updated>2026-04-06T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-04-06:/comparaisons-8-bits-en-z80.html</id><summary type="html">&lt;p&gt;Il y a bien quelque chose avec le Z80 qui me ralenti à chaque fois, ce sont les comparaisons. L'égalité, c'est facile. Mais dès qu'il s'agit de comparer deux octets pour savoir si l'un est plus grand que l'autre, strictement ou pas, et encore pire, si ce sont des octets signés, j'y passe du temps... pour souvent me tromper.&lt;/p&gt;
&lt;p&gt;Et donc, voici un petit tableau récapitulatif pour m'aider à m'y retrouver, et peut-être que ça pourra aussi vous aider.&lt;/p&gt;
&lt;h2&gt;Table des matières&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#comparaisons-non-signees"&gt;Comparaisons non signées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#comparaisons-signees"&gt;Comparaisons signées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#comparaisons-signees-simplifiees"&gt;Comparaisons signées simplifiées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#les-drapeaux"&gt;Les drapeaux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id="comparaisons-non-signees"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Comparaisons non signées (8 bits)&lt;/h2&gt;
&lt;p&gt;Un octet non signé est positif et dans l'intervalle [0, 255]. Après &lt;code&gt;cp b&lt;/code&gt; (qui calcule &lt;code&gt;A−B&lt;/code&gt; sans stocker le résultat), on a : &lt;code&gt;Z = 1&lt;/code&gt; si &lt;code&gt;A = B&lt;/code&gt; et  &lt;code&gt;C = 1&lt;/code&gt; si &lt;code&gt;A &amp;lt; B&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;A = B&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;egal&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A ≠ B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Il y a bien quelque chose avec le Z80 qui me ralenti à chaque fois, ce sont les comparaisons. L'égalité, c'est facile. Mais dès qu'il s'agit de comparer deux octets pour savoir si l'un est plus grand que l'autre, strictement ou pas, et encore pire, si ce sont des octets signés, j'y passe du temps... pour souvent me tromper.&lt;/p&gt;
&lt;p&gt;Et donc, voici un petit tableau récapitulatif pour m'aider à m'y retrouver, et peut-être que ça pourra aussi vous aider.&lt;/p&gt;
&lt;h2&gt;Table des matières&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#comparaisons-non-signees"&gt;Comparaisons non signées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#comparaisons-signees"&gt;Comparaisons signées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#comparaisons-signees-simplifiees"&gt;Comparaisons signées simplifiées (8 bits)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#les-drapeaux"&gt;Les drapeaux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id="comparaisons-non-signees"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Comparaisons non signées (8 bits)&lt;/h2&gt;
&lt;p&gt;Un octet non signé est positif et dans l'intervalle [0, 255]. Après &lt;code&gt;cp b&lt;/code&gt; (qui calcule &lt;code&gt;A−B&lt;/code&gt; sans stocker le résultat), on a : &lt;code&gt;Z = 1&lt;/code&gt; si &lt;code&gt;A = B&lt;/code&gt; et  &lt;code&gt;C = 1&lt;/code&gt; si &lt;code&gt;A &amp;lt; B&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;A = B&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;egal&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A ≠ B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A = B&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;A ≠ B&lt;/h3&gt;
&lt;p&gt;Le même code que pour A = B, mais en privilégiant le cas A ≠ B.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inegal&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A = B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inegal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≠ B&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;A &amp;lt; B et A ≥ B&lt;/h3&gt;
&lt;p&gt;Les deux cas sont identiques, c'est juste une question de sémantique.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_strict&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;lt; B (ou A ≥ B)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inf_strict:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≥ B (ou A &amp;lt; B)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;A ≤ B et A &amp;gt; B&lt;/h3&gt;
&lt;p&gt;Les deux cas sont identiques, c'est juste une question de sémantique.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;gt; B (ou A ≤ B)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inf_ou_egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≤ B (ou A &amp;gt; B)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;&lt;a id="comparaisons-signees"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Comparaisons signées (8 bits)&lt;/h2&gt;
&lt;p&gt;En signé, les deux octets sont dans l'intervalle [−128, +127]. La condition A &amp;lt; B est plus complexe à évaluer, car il faut aussi prendre en compte le flag de débordement (overflow) qui peut se produire lors de la soustraction &lt;code&gt;A−B&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si on est assuré qu'aucun overflow ne se produit (si A et B sont tous deux dans un intervalle [−64, +63]), voir la section suivante.&lt;/p&gt;
&lt;p&gt;En signé ou pas, l'égalité est identique à celle des non signés, elle n'est pas reproduite ici.&lt;/p&gt;
&lt;p&gt;Note : &lt;code&gt;jr&lt;/code&gt; ne supporte pas les conditions sur S et V, il faut donc utiliser &lt;code&gt;jp&lt;/code&gt; pour ces cas.&lt;/p&gt;
&lt;h3&gt;A &amp;gt; B ou A ≤ B (signé)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; A et B égaux&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;ov_gt&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Overflow, il faut inverser la condition&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;sup_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=0 et pas d&amp;#39;overflow, donc A &amp;gt; B (strict)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=1 et pas d&amp;#39;overflow, donc A ≤ B&lt;/span&gt;
&lt;span class="nl"&gt;ov_gt:&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Cas de l&amp;#39;overflow&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;sup_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=1 et overflow, donc A &amp;gt; B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=0 et overflow, donc A ≤ B&lt;/span&gt;
&lt;span class="nl"&gt;sup_strict:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;gt; B (signé)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inf_ou_egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≤ B (signé)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;A &amp;lt; B ou A ≥ B (signé)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;ov_lt&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Overflow, il faut inverser la condition&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=1 et pas d&amp;#39;overflow, donc A &amp;lt; B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;sup_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=0 et pas d&amp;#39;overflow, donc A ≥ B&lt;/span&gt;
&lt;span class="nl"&gt;ov_lt:&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Cas de l&amp;#39;overflow&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=0 et overflow, donc A &amp;lt; B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;sup_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=1 et overflow, donc A ≥ B&lt;/span&gt;
&lt;span class="nl"&gt;inf_strict:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;lt; B (signé)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;sup_ou_egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≥ B (signé)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a id="comparaisons-signees-simplifiees"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Comparaisons signées simplifiées (8 bits)&lt;/h2&gt;
&lt;p&gt;Lorsque A et B sont dans un intervalle tel qu'aucun overflow ne se produit lors de A−B (tous deux dans [−64, +63] ou toute opération garantie sans débordement) le code est simplifié en retirant les vérifications d'overflow.&lt;/p&gt;
&lt;h3&gt;A &amp;gt; B ou A ≤ B (signé, pas d'overflow)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; A = B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;sup_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=0, donc A &amp;gt; B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;inf_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=1, donc A ≤ B&lt;/span&gt;
&lt;span class="nl"&gt;sup_strict:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;gt; B (signé)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inf_ou_egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≤ B (signé)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;A &amp;lt; B ou A ≥ B (signé, pas d'overflow)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;inf_strict&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S=1, donc A &amp;lt; B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;sup_ou_egal&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; S=0, donc A ≥ B&lt;/span&gt;
&lt;span class="nl"&gt;inf_strict:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 1 : A &amp;lt; B (signé)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;sup_ou_egal:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; cas 2 : A ≥ B (signé)&lt;/span&gt;
&lt;span class="nl"&gt;next:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a id="les-drapeaux"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Les drapeaux&lt;/h2&gt;
&lt;p&gt;L'état des drapeaux après &lt;code&gt;cp b&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Signification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Z&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1 si &lt;code&gt;A = B&lt;/code&gt; (&lt;code&gt;A - B = 0&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1 si &lt;code&gt;A &amp;lt; B&lt;/code&gt; &lt;strong&gt;(non signé)&lt;/strong&gt; (emprunt lors de &lt;code&gt;A−B&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Bit 7 de &lt;code&gt;A−B&lt;/code&gt; (signe du résultat 8 bits)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;P/V&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1 si overflow signé (voir conditions ci-dessous)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;À propos de l'overflow signé : il se produit lorsque A et B ont des signes opposés et que le résultat de A−B a un signe différent de celui de A.&lt;/p&gt;
&lt;p&gt;Entre autre, il n'y a pas d'overflow possible si A et B sont de même signe.&lt;/p&gt;
&lt;h3&gt;À propos de S et V :&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;S&lt;/th&gt;
&lt;th&gt;V&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Interprétation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td style="text-align: left;"&gt;A − B ≥ 0, pas de débordement, donc A ≥ B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td style="text-align: left;"&gt;A − B &amp;lt; 0, pas de débordement, donc A &amp;lt; B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Résultat positif mais a débordé, donc A &amp;lt; B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Résultat négatif mais a débordé, donc A &amp;gt; B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Instructions et drapeaux&lt;/h3&gt;
&lt;p&gt;La syntax des sauts ne fait pas toujours référence directe au nom des drapeaux, ce qui est confusant.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jr z/nz&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Saut relatif sur Z&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jr c/nc&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Saut relatif sur C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jp m/p&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Saut absolu sur S&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jp pe/po&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Saut absolu sur P/V&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><category term="Machines"></category><category term="Z80"></category><category term="ASM"></category><category term="Programmation"></category></entry><entry><title>z80dezasm, désassembler et commenter le Z80</title><link href="https://www.triceraprog.fr/z80dezasm-desassembler-et-commenter-le-z80.html" rel="alternate"></link><published>2026-03-22T00:00:00+01:00</published><updated>2026-03-22T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-03-22:/z80dezasm-desassembler-et-commenter-le-z80.html</id><summary type="html">&lt;h2&gt;L'origine&lt;/h2&gt;
&lt;p&gt;C'est à l'été 2017 qu'après avoir commencé à étudier en profondeur le VG5000µ, je me mets en tête de commenter l'intégralité de sa ROM. Il y a bien quelques morceaux de ROM désassemblée qui existent, mais c'est incomplet et surtout, à cause des astuces d'instructions partielles du Z80, pas ré-assemblable à l'identique.&lt;/p&gt;
&lt;p&gt;Or, en plus de l'étude, j'aimerais pouvoir modifier la ROM pour faire des essais, voire ajouter des commandes. Je cherche alors un désassembleur Z80 qui puisse aussi ajouter des commentaires et produire un code ré-assemblable. Je n'en trouve pas. Et puis, il y a &lt;a href="http://z80.info/decoding.htm"&gt;cette page&lt;/a&gt; qui me fait dire que ça ne serait pas si compliqué que ça à faire.&lt;/p&gt;
&lt;p&gt;C'est ainsi que je commence à développer un désassembleur Z80, que je nomme alors &lt;code&gt;z80tools&lt;/code&gt;, car il n'est alors qu'une partie d'un répertoire d'outils variés permettant d'analyser la ROM. Une partie de ces outils seront extraits …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;L'origine&lt;/h2&gt;
&lt;p&gt;C'est à l'été 2017 qu'après avoir commencé à étudier en profondeur le VG5000µ, je me mets en tête de commenter l'intégralité de sa ROM. Il y a bien quelques morceaux de ROM désassemblée qui existent, mais c'est incomplet et surtout, à cause des astuces d'instructions partielles du Z80, pas ré-assemblable à l'identique.&lt;/p&gt;
&lt;p&gt;Or, en plus de l'étude, j'aimerais pouvoir modifier la ROM pour faire des essais, voire ajouter des commandes. Je cherche alors un désassembleur Z80 qui puisse aussi ajouter des commentaires et produire un code ré-assemblable. Je n'en trouve pas. Et puis, il y a &lt;a href="http://z80.info/decoding.htm"&gt;cette page&lt;/a&gt; qui me fait dire que ça ne serait pas si compliqué que ça à faire.&lt;/p&gt;
&lt;p&gt;C'est ainsi que je commence à développer un désassembleur Z80, que je nomme alors &lt;code&gt;z80tools&lt;/code&gt;, car il n'est alors qu'une partie d'un répertoire d'outils variés permettant d'analyser la ROM. Une partie de ces outils seront extraits au fur et à mesure pour donner &lt;a href="https://github.com/Triceraprog/vg5000_tools"&gt;ce repo&lt;/a&gt;. Il m'en reste une paire d'autres à extraire et puis, surtout, il reste ce plus gros morceau : le désassembleur/commenteur lui-même.&lt;/p&gt;
&lt;p&gt;Seulement, c'est un gros morceau de scripts écrits itérativement au fur et à mesure de mes besoins, sans vraiment une idée de produit publiable. Je le garde donc dans un coin et je me contente de publier &lt;a href="https://github.com/Triceraprog/vg5000_rom_comments"&gt;le résultat du commentaire&lt;/a&gt; de la ROM du VG5000µ, avec la spécification du format que j'utilise.&lt;/p&gt;
&lt;h2&gt;Mars 2026&lt;/h2&gt;
&lt;p&gt;Cet outil me servira dans d'autres projets, principalement lors des sessions de la &lt;a href="tag/rpufos.html"&gt;RPUfOS&lt;/a&gt;, pour analyser les ROMs des machines cibles lorsque celles-ci utilisent un Z80. Jamais rien de complet ceci dit.&lt;/p&gt;
&lt;p&gt;Et puis vient à nouveau une session, avec pour machine cette fois le Canon X-07. C'est une machine qui a de la documentation, mais pas toujours très précise, et de l'émulation, mais pas vraiment fiable (en cause, le coprocesseur T6834, pas documenté assez précisément). Je relance l'outil pour aller vérifier certaines hypothèses et je me dis qu'il serait peut-être temps que je publie ce projet !&lt;/p&gt;
&lt;p&gt;Et c'est donc chose faite. J'ai donné un nom au projet : &lt;code&gt;z80dezasm&lt;/code&gt;, packagé l'application avec &lt;code&gt;uv&lt;/code&gt;, fait un peu de ménage à coup de linter (même si c'est encore vraiment le bazar dans le code), nettoyé les trucs hardcodé qui ne fonctionnent que sur ma machine ou sur le VG5000µ et écrit un README pour expliquer comment utiliser l'outil, en récupérant le bout de spécification que j'avais écrit pour le dépôt des commentaires. Ouf.&lt;/p&gt;
&lt;h2&gt;z80dezasm&lt;/h2&gt;
&lt;p&gt;L'outil z80dezasm  &lt;a href="https://github.com/Triceraprog/z80dezasm"&gt;est ici !&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gardez en tête que ça reste un outil personnel trituré depuis 2017 et dont j'ai été le seul utilisateur pendant presque 9 ans. Ce n'est peut-être pas l'outil le plus facile à utiliser, ni le plus robuste, ni (certainement pas) le plus rapide. Mais s'il vous convient comme il me convient, c'est tant mieux.&lt;/p&gt;
&lt;p&gt;Entre temps, une ou deux années après avoir commencé, j'avais trouvé un autre désassembleur/commenteur assez similaire (dont j'ai perdu la trace, désolé), mais bon, j'avais l'habitude du mien. Il existe aussi le maintenant bien connu &lt;a href="https://github.com/NationalSecurityAgency/ghidra"&gt;ghidra&lt;/a&gt;, mais pareil... j'ai mes habitudes et ma façon de faire.&lt;/p&gt;</content><category term="Projets"></category><category term="Z80"></category><category term="ASM"></category><category term="Outil"></category></entry><entry><title>Adressage 6502, un récapitulatif</title><link href="https://www.triceraprog.fr/adressage-6502-un-recapitulatif.html" rel="alternate"></link><published>2026-03-20T00:00:00+01:00</published><updated>2026-03-20T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-03-20:/adressage-6502-un-recapitulatif.html</id><summary type="html">&lt;p&gt;Si vous aussi vous jetez régulièrement un œil sur les adressages possibles et valides pour le 6502,
voici un tableau récapitulatif qui pourra vous servir. En tout cas, il me servira.&lt;/p&gt;
&lt;h2&gt;Tableau Récapitulatif&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Syntaxe&lt;/th&gt;
&lt;th&gt;Exemple&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Cycles&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implicite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2-6&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Accumulateur&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LSR A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Immédiat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP #nn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA #$42&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Constante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3-5&lt;/td&gt;
&lt;td&gt;Rapide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro,X&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $80,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4-6&lt;/td&gt;
&lt;td&gt;Wrapping en page 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro,Y&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDX $10,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LDX/STX uniquement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $1234&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-6&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu,X&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $2000,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-7&lt;/td&gt;
&lt;td&gt;+1 si page crossed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu,Y&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $3000,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-7&lt;/td&gt;
&lt;td&gt;+1 si page crossed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relatif&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP label&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BEQ Loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2-4&lt;/td&gt;
&lt;td&gt;Branches uniquement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indirect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JMP ($nnnn)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JMP ($FFFC)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;JMP uniquement …&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</summary><content type="html">&lt;p&gt;Si vous aussi vous jetez régulièrement un œil sur les adressages possibles et valides pour le 6502,
voici un tableau récapitulatif qui pourra vous servir. En tout cas, il me servira.&lt;/p&gt;
&lt;h2&gt;Tableau Récapitulatif&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Syntaxe&lt;/th&gt;
&lt;th&gt;Exemple&lt;/th&gt;
&lt;th&gt;Taille&lt;/th&gt;
&lt;th&gt;Cycles&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implicite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2-6&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Accumulateur&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LSR A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Immédiat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP #nn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA #$42&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Constante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3-5&lt;/td&gt;
&lt;td&gt;Rapide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro,X&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $80,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4-6&lt;/td&gt;
&lt;td&gt;Wrapping en page 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Zéro,Y&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nn,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDX $10,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LDX/STX uniquement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $1234&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-6&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu,X&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $2000,X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-7&lt;/td&gt;
&lt;td&gt;+1 si page crossed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Absolu,Y&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP $nnnn,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA $3000,Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4-7&lt;/td&gt;
&lt;td&gt;+1 si page crossed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relatif&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP label&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BEQ Loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2-4&lt;/td&gt;
&lt;td&gt;Branches uniquement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indirect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JMP ($nnnn)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;JMP ($FFFC)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;JMP uniquement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indexed Indirect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP ($nn,X)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA ($40,X)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;X ajouté d'abord&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indirect Indexed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OP ($nn),Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LDA ($40),Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;5-6&lt;/td&gt;
&lt;td&gt;Y ajouté après&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;&lt;code&gt;($nn,X)&lt;/code&gt; vs &lt;code&gt;($nn),Y&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Indexed Indirect&lt;/strong&gt; vs. &lt;strong&gt;Indirect Indexed&lt;/strong&gt;, ma source de confusion préférée.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Écriture&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;($nn,X)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;($nn),Y&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Évaluation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;X ajouté &lt;strong&gt;avant&lt;/strong&gt; lecture&lt;/td&gt;
&lt;td&gt;Y ajouté &lt;strong&gt;après&lt;/strong&gt; lecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Calcul&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;addr = read16(($nn+X)&amp;amp;$FF)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;addr = read16($nn)+Y&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wrapping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;X wrappe en page 0&lt;/td&gt;
&lt;td&gt;Y sur 16-bit complet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Usage typique&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tables de pointeurs, dispatch&lt;/td&gt;
&lt;td&gt;Tableaux, structures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Références&lt;/h2&gt;
&lt;p&gt;Les deux pages sur lesquelles je vais régulièrement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.6502.org/users/obelisk/6502/addressing.html"&gt;6502.org - Addressing Modes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.6502.org/users/obelisk/6502/instructions.html"&gt;6502.org - Instruction Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Machines"></category><category term="Programmation"></category><category term="6502"></category><category term="ASM"></category></entry><entry><title>Forth sur 6502, épisode 11</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-11.html" rel="alternate"></link><published>2026-02-25T00:00:00+01:00</published><updated>2026-02-25T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-02-25:/forth-sur-6502-episode-11.html</id><summary type="html">&lt;h2&gt;ACCEPT, enfin !&lt;/h2&gt;
&lt;p&gt;Cela aura pris un peu de temps, entre autres raisons car d'autres activités se sont invitées entre-temps, mais &lt;code&gt;ACCEPT&lt;/code&gt; est enfin implémenté ! &lt;code&gt;ACCEPT&lt;/code&gt; est un mot qui lit une ligne de texte entrée par l'utilisateur et la stocke dans une adresse mémoire fournie lors de l'appel. Généralement, cette adresse est le &lt;code&gt;TIB&lt;/code&gt; (Terminal Input Buffer), qui sera ensuite fournie à l'interpréteur Forth.&lt;/p&gt;
&lt;p&gt;Comme indiqué lors du &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-10.html"&gt;&lt;strong&gt;précédent article&lt;/strong&gt;&lt;/a&gt;, se posait la question de savoir comment récupérer les données. J'ai tenté deux versions et je suis finalement partie sur celle que je pressentais : utiliser la mémoire PPU pour stocker les données en cours d'édition, puis les récupérer lorsque la touche &lt;code&gt;RETURN&lt;/code&gt; est appuyée.&lt;/p&gt;
&lt;p&gt;Oui, mais... même si la mémoire représentant les caractères est linéaire, depuis le début de l'implémentation j'ai réservé des caractères sur les bords de l'écran pour ne rien y afficher, afin de respecter les &lt;strong&gt;marges nécessaires …&lt;/strong&gt;&lt;/p&gt;</summary><content type="html">&lt;h2&gt;ACCEPT, enfin !&lt;/h2&gt;
&lt;p&gt;Cela aura pris un peu de temps, entre autres raisons car d'autres activités se sont invitées entre-temps, mais &lt;code&gt;ACCEPT&lt;/code&gt; est enfin implémenté ! &lt;code&gt;ACCEPT&lt;/code&gt; est un mot qui lit une ligne de texte entrée par l'utilisateur et la stocke dans une adresse mémoire fournie lors de l'appel. Généralement, cette adresse est le &lt;code&gt;TIB&lt;/code&gt; (Terminal Input Buffer), qui sera ensuite fournie à l'interpréteur Forth.&lt;/p&gt;
&lt;p&gt;Comme indiqué lors du &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-10.html"&gt;&lt;strong&gt;précédent article&lt;/strong&gt;&lt;/a&gt;, se posait la question de savoir comment récupérer les données. J'ai tenté deux versions et je suis finalement partie sur celle que je pressentais : utiliser la mémoire PPU pour stocker les données en cours d'édition, puis les récupérer lorsque la touche &lt;code&gt;RETURN&lt;/code&gt; est appuyée.&lt;/p&gt;
&lt;p&gt;Oui, mais... même si la mémoire représentant les caractères est linéaire, depuis le début de l'implémentation j'ai réservé des caractères sur les bords de l'écran pour ne rien y afficher, afin de respecter les &lt;strong&gt;marges nécessaires&lt;/strong&gt; lors d'un affichage sur écran cathodique. Récupérer les données nécessite donc de prendre des morceaux de mémoire à différents endroits. Pas forcément très complexe, mais ça nécessite un peu plus de réflexion qu'un simple transfert en une fois.&lt;/p&gt;
&lt;p&gt;Et tant qu'à faire, puisque je dois définir une géométrie d'écran logique, pourquoi ne pas implémenter un mot &lt;strong&gt;&lt;code&gt;WINDOW&lt;/code&gt;&lt;/strong&gt; qui permettrait de définir les marges haut, bas, gauche et droite ? C'est ce que j'ai commencé par faire, en adaptant la gestion du curseur qui était codée en dur avec des marges fixes. Deux routines me permettent d'avancer et de reculer le curseur en respectant cette géométrie de fenêtre logique, et c'est bon. Les marges sont toujours là, initialisées au démarrage, mais à présent elles sont configurables.&lt;/p&gt;
&lt;p&gt;Retour sur &lt;strong&gt;&lt;code&gt;ACCEPT&lt;/code&gt;&lt;/strong&gt;. Au début, il s'agit uniquement de reprendre le code d'affichage de caractères que j'avais déjà. Le code me semble quand même voué à être un peu long, je lui dédie donc un fichier. Il me faut implémenter l'édition d'une ligne logique, avec gestion des touches curseur du clavier (au moins droite et gauche), ainsi que des touches &lt;code&gt;INS&lt;/code&gt; (insertion), &lt;code&gt;DEL&lt;/code&gt; (suppression) et &lt;code&gt;RETURN&lt;/code&gt; (validation de la ligne). Ces touches ne sont pas encore branchées, je repasse donc sur la gestion du clavier.&lt;/p&gt;
&lt;h2&gt;Gestion du clavier complet&lt;/h2&gt;
&lt;p&gt;Tant qu'à faire, puisque je suis sur le clavier, j'en profite pour gérer les majuscules, minuscules et kanas. Pour cela, il me faut compléter la fonte. Celle que j'avais choisie n'a pas tous ces caractères. J'en cherche une et je tombe sur la fonte &lt;strong&gt;Misaki&lt;/strong&gt;, qui, en plus des katakanas, contient des caractères graphiques. Parfait pour utiliser la touche &lt;code&gt;GRPH&lt;/code&gt; du clavier.&lt;/p&gt;
&lt;p&gt;La fonte &lt;strong&gt;format bitmap&lt;/strong&gt; 8x8 est fournie avec beaucoup de caractères. J'écris donc un petit script Python pour en prendre une sélection et générer ma fonte dans le format Famicom attendu. Puis je mappe tous les scancodes, un par un, vers leurs équivalents pour quatre tables différentes : majuscules, minuscules, kanas et graphiques. Je sélectionne quelques codes entre 0 et 32 pour les touches de contrôle, en respectant les codes classiques et en improvisant un peu pour les autres.&lt;/p&gt;
&lt;p&gt;Et me voilà avec &lt;strong&gt;un mapping&lt;/strong&gt; complet. Je peux compléter &lt;code&gt;ACCEPT&lt;/code&gt; pour gérer les touches &lt;code&gt;SHIFT&lt;/code&gt;, &lt;code&gt;KANA&lt;/code&gt; et &lt;code&gt;GRAPH&lt;/code&gt;. Les touches de direction avant et arrière ne posent pas beaucoup de problèmes... à part le curseur.&lt;/p&gt;
&lt;p&gt;Tant que le curseur était en fin de ligne, c'était simple. Mais maintenant qu'il se déplace sur des caractères déjà présents, je veux le faire clignoter afin de laisser le caractère en dessous apparent. Et pour savoir quel est ce caractère, il faut aller le chercher... dans la mémoire de &lt;strong&gt;l'écran&lt;/strong&gt; !&lt;/p&gt;
&lt;h2&gt;Transferts PPU &amp;lt;-&amp;gt; RAM&lt;/h2&gt;
&lt;p&gt;Je laisse donc le clavier de côté. Il est temps de s'occuper des &lt;strong&gt;transferts RAM/PPU&lt;/strong&gt;. J'ai déjà, via le framework utilisé, un transfert de buffer de la RAM vers la mémoire PPU. Celui-ci fonctionne par recopie de données dans un buffer de commandes. C'est bien pour la sécurité des données : comme elles sont copiées, la source peut changer en RAM, elles sont au chaud dans la commande. Par contre, cela prend du temps de recopie et de la place en RAM.&lt;/p&gt;
&lt;p&gt;J'implémente donc une version qui permet de référencer une adresse mémoire et une longueur, qui servent directement lors du décodage des commandes pendant la synchronisation verticale. À la charge de l'appelant d'assurer que les données sont toujours là où elles doivent être. J'en profite pour afficher le &lt;strong&gt;message de bienvenue&lt;/strong&gt; avec cette commande, afin de valider le fonctionnement.&lt;/p&gt;
&lt;p&gt;De là, il est assez facile d'en faire la commande symétrique : une commande qui référence une adresse mémoire et une longueur en RAM, et qui y copiera les résultats de requêtes PPU lors de la prochaine synchronisation verticale. En spécifiant comme adresse celle d'une variable contenant le caractère sous le curseur et comme longueur 1, je peux récupérer ce &lt;strong&gt;caractère courant&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour être sûr des buffers, j'attends la synchronisation verticale après chaque déplacement de curseur. Pendant l'édition d'une ligne d'entrée logique, ce n'est &lt;strong&gt;pas très important&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Retour à l'édition de ligne logique&lt;/h2&gt;
&lt;p&gt;Bien. À présent, j'ai la possibilité de récupérer le caractère sous le curseur, mais aussi tous les caractères à l'écran. Avant d'implémenter &lt;code&gt;RETURN&lt;/code&gt;, je fais un détour par &lt;code&gt;INS&lt;/code&gt; et &lt;code&gt;DEL&lt;/code&gt;, afin de pouvoir faire de l'édition et de ne pas partir du principe que l'utilisateur tape une ligne parfaite du premier coup. Mes multiples tests montrent que ce n'est pas le cas. J'ai besoin de ces touches !&lt;/p&gt;
&lt;p&gt;Un détour par le Family BASIC me montre que &lt;code&gt;INS&lt;/code&gt; insère un espace à l'emplacement du curseur, ok, mais que &lt;code&gt;DEL&lt;/code&gt; est en fait un &lt;strong&gt;&lt;code&gt;BACKSPACE&lt;/code&gt;&lt;/strong&gt; : il supprime le caractère avant le curseur et recule le curseur d'une position. Par cohérence, j'implémente le même comportement.&lt;/p&gt;
&lt;p&gt;Cependant, il n'est pas possible de déplacer des morceaux de mémoire PPU directement. Ou alors je n'ai pas trouvé (et les personnes à qui j'ai demandé ne savaient pas). Qu'à cela ne tienne, &lt;strong&gt;&lt;code&gt;ACCEPT&lt;/code&gt;&lt;/strong&gt; a à sa disposition un buffer de travail dans lequel il déposera les données finales. Je l'utilise comme buffer temporaire. Pour les deux opérations, je récupère les données de l'écran (en respectant la géométrie de la fenêtre logique), je fais la modification en RAM, puis je renvoie le tout à l'écran.&lt;/p&gt;
&lt;p&gt;Je ne m'embête pas à trouver la sous-partie qui va bouger, je récupère et je renvoie tout. J'attends même une synchronisation verticale pour chaque ligne physique transférée pour être certain de tenir dans le temps de synchronisation. Sur émulateur, ça ne bronche pas. On verra sur vrai matériel. Au pire, je pourrais grouper quelques transferts pour trouver le bon équilibre. Mais là encore, on est en pleine &lt;strong&gt;édition de ligne logique&lt;/strong&gt; utilisateur, on peut se permettre des attentes sans affecter l'expérience utilisateur.&lt;/p&gt;
&lt;h2&gt;ACCEPT !&lt;/h2&gt;
&lt;p&gt;L'avantage avec l'implémentation de &lt;code&gt;INS&lt;/code&gt; et &lt;code&gt;DEL&lt;/code&gt;, c'est qu'il y a déjà tout ce qu'il faut pour implémenter &lt;strong&gt;&lt;code&gt;RETURN&lt;/code&gt;&lt;/strong&gt;. J'ai la récupération des données en RAM. Reste à pousser la longueur actuelle de la ligne logique sur la pile. Cette longueur est maintenue au fur et à mesure des opérations d'édition.&lt;/p&gt;
&lt;p&gt;Il reste des choses à faire pour une édition au clavier agréable et complète. Et une paire de petits bugs, dont &lt;strong&gt;la longueur&lt;/strong&gt; de la ligne logique qui n'est pas mise à jour correctement dans certains cas. Je m'en occuperai plus tard. Il est grand temps d'avancer vers &lt;code&gt;INTERPRET&lt;/code&gt; !&lt;/p&gt;
&lt;h2&gt;Amélioration du framework de test&lt;/h2&gt;
&lt;p&gt;Au passage, avec l'arrivée du clavier, j'ai ajouté comme prévu l'injection de caractères depuis le &lt;strong&gt;framework de tests&lt;/strong&gt;. Cela m'a permis d'écrire un test pour &lt;code&gt;INS&lt;/code&gt; et un autre pour &lt;code&gt;DEL&lt;/code&gt;. Ces tests demandent la mise en place de contextes en plusieurs étapes, avec parfois des attentes de frames pour attendre les résultats. Les tests commençaient à être très verbeux et j'ai donc fait une passe pour factoriser tout ça dans des fonctions d'aide qui me permettent d'écrire le déroulement des opérations qui seront ensuite conduites de manière asynchrone.&lt;/p&gt;
&lt;h2&gt;Interprète... interprète !&lt;/h2&gt;
&lt;p&gt;Maintenant que j'ai une boucle d'entrée de texte, la prochaine étape est l'&lt;strong&gt;interprétation du résultat&lt;/strong&gt;. Cela va nécessiter l'écriture de nombreux mots standards de Forth (au passage, j'ai implémenté &lt;code&gt;DROP&lt;/code&gt; car actuellement je dois ignorer le retour de &lt;code&gt;ACCEPT&lt;/code&gt;). Cependant, ces mots devraient être nettement plus simples que &lt;code&gt;ACCEPT&lt;/code&gt; ou la gestion clavier.&lt;/p&gt;
&lt;p&gt;La « simple » implémentation d'&lt;code&gt;ACCEPT&lt;/code&gt; a eu de nombreuses ramifications. J'en ai même profité pour faire quelques petites optimisations/simplifications simples au passage.&lt;/p&gt;
&lt;p&gt;J'aimerais pour la suite pouvoir écrire quelque chose comme &lt;code&gt;HEX 7FF FF C!&lt;/code&gt;, qui écrit la valeur &lt;code&gt;0xFF&lt;/code&gt; à l'adresse &lt;code&gt;0x7FFF&lt;/code&gt;, ce que le framework de test peut détecter. Cela signifie le découpage par mots de la chaîne d'entrée, un traitement de base numérique, le parsing de nombres dans cette base et l'implémentation de &lt;strong&gt;&lt;code&gt;C!&lt;/code&gt;&lt;/strong&gt; (le plus facile de toute la liste).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partons là-dessus&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;&lt;img alt="Forth sur 6502 - écriture interactive à l'écran 2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/20260225-Line-Edit.gif"&gt;&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Deux livres pour le développement sur Famicom</title><link href="https://www.triceraprog.fr/deux-livres-pour-le-developpement-sur-famicom.html" rel="alternate"></link><published>2026-02-24T00:00:00+01:00</published><updated>2026-02-24T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-02-24:/deux-livres-pour-le-developpement-sur-famicom.html</id><summary type="html">&lt;p&gt;En attendant le prochain article de la série sur le développement d'un &lt;strong&gt;Forth sur Famicom&lt;/strong&gt;, qui prend un peu de temps, je voulais faire une petite aparté pour présenter les deux livres qui m'accompagnent, en plus de différentes ressources en ligne.&lt;/p&gt;
&lt;p&gt;En effet, un livre que l'on peut feuilleter, où on peut retrouver un passage rapidement, c'est &lt;strong&gt;pratique&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Making Games for the NES&lt;/h2&gt;
&lt;p&gt;Le premier livre est en anglais et aborde le développement de jeux pour la NES, et donc pour la Famicom. &lt;strong&gt;Très progressif&lt;/strong&gt;, il amène chaque aspect de la machine avec clarté. Pas forcément dans les plus obscurs des détails et c'est aussi ce qui est intéressant : c'est une bonne première approche.&lt;/p&gt;
&lt;p&gt;Le livre date un peu. Ça n'est pas très important pour la console elle-même, qui n'a pas bougé, mais quelques outils évoqués ne sont plus forcément les meilleurs choix.&lt;/p&gt;
&lt;p&gt;L'auteur, Steven Hugg, a écrit d'autres livres …&lt;/p&gt;</summary><content type="html">&lt;p&gt;En attendant le prochain article de la série sur le développement d'un &lt;strong&gt;Forth sur Famicom&lt;/strong&gt;, qui prend un peu de temps, je voulais faire une petite aparté pour présenter les deux livres qui m'accompagnent, en plus de différentes ressources en ligne.&lt;/p&gt;
&lt;p&gt;En effet, un livre que l'on peut feuilleter, où on peut retrouver un passage rapidement, c'est &lt;strong&gt;pratique&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Making Games for the NES&lt;/h2&gt;
&lt;p&gt;Le premier livre est en anglais et aborde le développement de jeux pour la NES, et donc pour la Famicom. &lt;strong&gt;Très progressif&lt;/strong&gt;, il amène chaque aspect de la machine avec clarté. Pas forcément dans les plus obscurs des détails et c'est aussi ce qui est intéressant : c'est une bonne première approche.&lt;/p&gt;
&lt;p&gt;Le livre date un peu. Ça n'est pas très important pour la console elle-même, qui n'a pas bougé, mais quelques outils évoqués ne sont plus forcément les meilleurs choix.&lt;/p&gt;
&lt;p&gt;L'auteur, Steven Hugg, a écrit d'autres livres pour d'autres machines et est aussi derrière le site &lt;a href="https://8bitworkshop.com/"&gt;&lt;strong&gt;8bitworkshop&lt;/strong&gt;&lt;/a&gt;, qui propose un environnement de développement en ligne pour différentes machines, dont la NES. Tous les exemples du livre y sont disponibles et peuvent être testés et modifiés directement dans le navigateur.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Livre Making Games for the NES" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/202512-Livre-Making-Games-For-The-NES.jpeg"&gt;&lt;/p&gt;
&lt;h2&gt;Langage machine 6502 et 6510&lt;/h2&gt;
&lt;p&gt;Le second livre est &lt;strong&gt;en français&lt;/strong&gt; et aborde le langage machine du 6502 ainsi que les particularités du 6510. C'est avant tout un livre écrit avec le Commodore 64 en tête, mais sa structure en fait une &lt;strong&gt;bonne référence&lt;/strong&gt; à garder sous la main pour la partie 6502.&lt;/p&gt;
&lt;p&gt;N'ayant pas une grande expérience du 6502 (même si depuis le début du projet, j'ai progressé) je m'y réfère encore pas mal, surtout pour les modes d'adressages basés sur X et Y, pour lesquels j'ai encore tendance à tout mélanger.&lt;/p&gt;
&lt;p&gt;Je me sers aussi du site &lt;a href="https://www.6502.org/"&gt;6502.org&lt;/a&gt;, mais comme je le disais, avoir un livre sous la main, c'est pratique. Et en français, c'est reposant.&lt;/p&gt;
&lt;p&gt;Merci à l'auteur, Philippe Gianviti.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Livre Langage machine 6502 et 6510" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/202512-Livre-Langage-machine-6502.jpeg"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 10</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-10.html" rel="alternate"></link><published>2026-01-18T00:00:00+01:00</published><updated>2026-01-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-01-18:/forth-sur-6502-episode-10.html</id><summary type="html">&lt;h2&gt;Un curseur et des branches&lt;/h2&gt;
&lt;p&gt;Le clavier est pour le moment implémenté avec deux mots. L'un qui sera gardé, &lt;code&gt;KBDSCAN&lt;/code&gt; et l'autre qui est là en attendant de pouvoir écrire la même chose en &lt;em&gt;Forth&lt;/em&gt;, &lt;code&gt;KBDPROCESS&lt;/code&gt;. L'objectif premier est de transformer &lt;code&gt;KBDPROCESS&lt;/code&gt; en son équivalent &lt;em&gt;Forth&lt;/em&gt; que je placerai dans ma boucle principale (pas encore &lt;code&gt;QUIT&lt;/code&gt;, qui n'est pas encore prêt).&lt;/p&gt;
&lt;p&gt;Mais avant toute chose, j'ai quelque chose à corriger avec le curseur. Pour le moment, j'affiche le curseur avec &lt;code&gt;EMIT&lt;/code&gt;, ce qui fait avancer la prochaine position d'affichage de caractère. Ce que je veux, c'est afficher le caractère reçu du clavier avec &lt;code&gt;EMIT&lt;/code&gt; &lt;em&gt;puis&lt;/em&gt; afficher le caractère du curseur &lt;strong&gt;sans faire avancer&lt;/strong&gt; la position d'affichage. Ainsi, le caractère du curseur sera toujours une position après le dernier caractère affiché.&lt;/p&gt;
&lt;p&gt;Pour cela, j'ai un peu remanié le code afin de &lt;strong&gt;séparer&lt;/strong&gt; l'&lt;strong&gt;envoi&lt;/strong&gt; du caractère à afficher et la mise …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Un curseur et des branches&lt;/h2&gt;
&lt;p&gt;Le clavier est pour le moment implémenté avec deux mots. L'un qui sera gardé, &lt;code&gt;KBDSCAN&lt;/code&gt; et l'autre qui est là en attendant de pouvoir écrire la même chose en &lt;em&gt;Forth&lt;/em&gt;, &lt;code&gt;KBDPROCESS&lt;/code&gt;. L'objectif premier est de transformer &lt;code&gt;KBDPROCESS&lt;/code&gt; en son équivalent &lt;em&gt;Forth&lt;/em&gt; que je placerai dans ma boucle principale (pas encore &lt;code&gt;QUIT&lt;/code&gt;, qui n'est pas encore prêt).&lt;/p&gt;
&lt;p&gt;Mais avant toute chose, j'ai quelque chose à corriger avec le curseur. Pour le moment, j'affiche le curseur avec &lt;code&gt;EMIT&lt;/code&gt;, ce qui fait avancer la prochaine position d'affichage de caractère. Ce que je veux, c'est afficher le caractère reçu du clavier avec &lt;code&gt;EMIT&lt;/code&gt; &lt;em&gt;puis&lt;/em&gt; afficher le caractère du curseur &lt;strong&gt;sans faire avancer&lt;/strong&gt; la position d'affichage. Ainsi, le caractère du curseur sera toujours une position après le dernier caractère affiché.&lt;/p&gt;
&lt;p&gt;Pour cela, j'ai un peu remanié le code afin de &lt;strong&gt;séparer&lt;/strong&gt; l'&lt;strong&gt;envoi&lt;/strong&gt; du caractère à afficher et la mise à jour de la &lt;strong&gt;position&lt;/strong&gt; d'affichage. Le code de &lt;code&gt;EMIT&lt;/code&gt; appelle les deux fonctions et j'ai ajouté le mot &lt;code&gt;PUTCHR&lt;/code&gt; qui affiche le caractère à la position courante sans avancer la position du curseur.&lt;/p&gt;
&lt;p&gt;Ainsi, l'affichage d'un caractère reçu depuis le clavier devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;\ Le caractère reçu du clavier est mis sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;EMIT&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;\ Affiche le caractère présent sur la pile et avance le curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nf"&gt;CURSOR_CODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;\ Récupère le code du caractère du curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nf"&gt;PUTCHR&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;\ Affiche le caractère du curseur sans avancer le curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le fait de mettre le code du curseur dans une variable pointée par &lt;code&gt;CURSOR_CODE&lt;/code&gt; permettra de &lt;strong&gt;changer la forme&lt;/strong&gt; du curseur en fonction du mode (pour indiquer si on est en mode KANA ou non par exemple).&lt;/p&gt;
&lt;p&gt;Avec un mot &lt;code&gt;KEY&lt;/code&gt; bloquant, cela serait suffisant. Ce bout de code serait mis dans la boucle infinie et puis voilà. Seulement, je veux pouvoir opérer d'autres traitements dans la boucle d'attente de caractère. Faire clignoter le curseur par exemple, sans gestion par interruption. Et puis, c'est une bonne occasion d'implémenter une &lt;strong&gt;branche conditionnelle&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le standard Forth actuel définit &lt;code&gt;IF&lt;/code&gt;, &lt;code&gt;ELSE&lt;/code&gt; et &lt;code&gt;THEN&lt;/code&gt; de manière haut niveau, en indiquant le comportement attendu. Dans les Forth plus anciens, comme le &lt;code&gt;FIG-Forth&lt;/code&gt; dont je m'inspire, le détail d'implémentation est d'utiliser &lt;strong&gt;les mots bas niveau&lt;/strong&gt; &lt;code&gt;0BRANCH&lt;/code&gt; et &lt;code&gt;BRANCH&lt;/code&gt; pour déplacer &lt;code&gt;IP&lt;/code&gt; (le pointeur d'instruction).&lt;/p&gt;
&lt;p&gt;J'ai déjà &lt;code&gt;BRANCH&lt;/code&gt;, c'est le mot qui me permet d'avoir ma &lt;strong&gt;boucle infinie&lt;/strong&gt;, en reculant &lt;code&gt;IP&lt;/code&gt; de façon inconditionnelle. &lt;code&gt;QUIT&lt;/code&gt;, actuellement, ressemble à ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;MAIN_LOOP&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;\ Appel du mot dans lequel je fais mes tests&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;BRANCH&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;\ Déplacement inconditionnel de IP en ajoutant le mot qui suit en mémoire&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;$fffc&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;\ le mot qui suit en mémoire : -4. Ce qui ramène IP au niveau de MAIN_LOOP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;0BRANCH&lt;/code&gt; fonctionne de la même manière, mais ne déplace &lt;code&gt;IP&lt;/code&gt; que si la valeur au sommet de la pile est &lt;strong&gt;zéro&lt;/strong&gt;. Dans le cas contraire, l'instruction ne fait rien d'autre que déplacer l'&lt;code&gt;IP&lt;/code&gt; pour passer par-dessus le mot qui suit en mémoire, puis donne le contrôle à l'instruction suivante. Dans tous les cas, la valeur sur la pile est retirée de la pile.&lt;/p&gt;
&lt;p&gt;Le mot est assez simple à implémenter avec mes briques existantes. Voici le code assembleur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="n"&gt;BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branches&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;continues&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;DEFINE_CODE_WORD_WITH_SYMBOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ZERO_BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0BRANCH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;POP_PARAM_STACK_TO_REG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ora&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;beq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BRANCH_word_pfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;advance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;inc_reg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REG_IP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;inc_reg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REG_IP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;END_TO_NEXT&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(rappel : &lt;code&gt;TOS&lt;/code&gt; signifie "Top Of Stack", le sommet de la pile de données)&lt;/p&gt;
&lt;p&gt;Avec &lt;code&gt;0BRANCH&lt;/code&gt;, le traitement et &lt;strong&gt;affichage du clavier&lt;/strong&gt; devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;KBDSCAN&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;\ Scan du clavier et mise à jour des tampons&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;KEY?&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;\ Y a-t-il un caractère disponible ?&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nf"&gt;BRANCH&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;\ Si non, branchement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;$000c&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;\ vers l&amp;#39;instruction après PUTCHR (12 octets plus loin)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;\ Récupération du caractère&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;EMIT&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;\ Affichage du caractère et avancée du curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_CODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;\ Récupération du code du curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;PUTCHR&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;\ Affichage du curseur sans avancer le curseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;\ Suite du code de la boucle principale&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ce morceau de code, j'ai un curseur qui fonctionne et je peux l'initialiser dans &lt;code&gt;COLD&lt;/code&gt;. J'en profite pour implémenter &lt;code&gt;LIT&lt;/code&gt; qui permet de pousser la valeur qui suit le mot en mémoire sur la pile. Cela me permet d'écrire &lt;strong&gt;des valeurs immédiates&lt;/strong&gt; dans le code Forth. Jusqu'à maintenant, j'utilisais des constantes qui contenaient les valeurs initiales.&lt;/p&gt;
&lt;p&gt;Il n'est pas impossible que je revienne sur l'initialisation (et le déplacement) du curseur dans le futur pour deux raisons liées. La première est qu'écrire sur &lt;strong&gt;les bords de l'écran&lt;/strong&gt; sur ces machines n'est pas une bonne idée : les télés cathodiques avaient tendance à couper les bords de l'image. Pour le moment, je n'écris ni sur la première ni sur la dernière colonne. Mais en regardant &lt;em&gt;Family BASIC&lt;/em&gt;, je vois que ce sont &lt;strong&gt;deux&lt;/strong&gt; colonnes entières qui sont laissées comme marges. Ainsi que les deux premières lignes.&lt;/p&gt;
&lt;p&gt;Ce qui m'amène à la seconde raison liée : permettre de changer &lt;strong&gt;la géométrie&lt;/strong&gt; de la fenêtre de texte par l'utilisateur. C'est une commande qui existe sur l'&lt;em&gt;Hector HRX&lt;/em&gt; par exemple. Avec ce système, ce mot &lt;code&gt;WINDOW&lt;/code&gt; permettrait de définir les marges haut, bas, gauche et droite. À noter pour plus tard... car cela compliquera la gestion du scroll lors de l'arrivée en bas de la zone.&lt;/p&gt;
&lt;h2&gt;Entrer du texte&lt;/h2&gt;
&lt;p&gt;Le texte s'affiche donc à l'écran, très bien. Mais il n'est pas encore prêt pour être traité par le système Forth. Pour cela, FIG-Forth utilise &lt;strong&gt;un buffer&lt;/strong&gt; dont l'adresse est maintenue dans la variable adresse &lt;code&gt;TIB&lt;/code&gt; (Text Input Buffer), ainsi que sa taille dans la variable adresse &lt;code&gt;#TIB&lt;/code&gt;, comme indiqué dans le livre &lt;em&gt;Starting Forth&lt;/em&gt; dans le &lt;a href="https://www.forth.com/starting-forth/9-forth-execution/#Input_Message_Buffer"&gt;chapitre &lt;em&gt;Under the Hood&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je ne sais pas encore où placer ce buffer. Je vois plusieurs options possibles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Je maintiens un buffer en RAM des caractères entrés et édités, en parallèle de ce qui est envoyé à l'écran. Cela limite l'édition à une ligne logique, pas possible de se balader sur un écran pleine page. Et maintenir en synchro deux systèmes parallèles n'est pas souvent une bonne idée.&lt;/li&gt;
&lt;li&gt;J'utilise l'écran lui-même comme buffer et je limite l'édition à une ligne logique. Le fait que les données à l'écran ne soient pas continues à cause des réservations des premières et dernières colonnes complique un peu les choses. Il faut aussi ramener les informations présentes dans la mémoire vidéo vers la RAM pour traitement, ce qui est assez lent et nécessite d'être fait pendant la &lt;em&gt;VSync&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;J'utilise l'écran lui-même comme buffer et je permets l'édition pleine page. C'est globalement la même chose que l'option précédente, avec en plus un algorithme pour déterminer où commence la ligne logique lorsque l'on appuie sur &lt;em&gt;RETURN&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans l'idéal, j'aimerais la troisième option. Cependant si cette fonctionnalité est très pratique en BASIC où on peut revenir sur des lignes précédentes pour les éditer, l'intérêt est moins évident en Forth, où il faut « oublier » les mots avant de les redéfinir.&lt;/p&gt;
&lt;p&gt;La première option m'ennuie à cause du double traitement. Je pense que &lt;strong&gt;la seconde option&lt;/strong&gt; sera mon choix de base. Si je vectorise le mot &lt;code&gt;ACCEPT&lt;/code&gt;, il sera possible pour un utilisateur avancé de redéfinir le comportement pour faire de l'édition pleine page, en fonction de la RAM disponible sur la cartouche... je m'emballe.&lt;/p&gt;
&lt;h2&gt;Et les tests ?&lt;/h2&gt;
&lt;p&gt;L'affichage initial du curseur était testé par mes tests unitaires. Indirectement, le mot &lt;code&gt;LIT&lt;/code&gt; que j'utilise à l'initialisation est testé. Par contre, j'ai à présent du texte en entrée et une boucle interactive avec du branchement conditionnel. Et pour ça, je n'ai qu'un &lt;strong&gt;test manuel&lt;/strong&gt; : lancer le programme et vérifier que le clavier fonctionne. Et j'ai encore plus de mots standards que je devrais ajouter à un moment comme &lt;code&gt;DUP&lt;/code&gt;, &lt;code&gt;DROP&lt;/code&gt;, &lt;code&gt;SWAP&lt;/code&gt;, &lt;code&gt;OVER&lt;/code&gt;, etc. que je voudrais pouvoir tester depuis Forth.&lt;/p&gt;
&lt;p&gt;Il existe un framework de test Forth, extrêmement simple, du nom de &lt;code&gt;ttester&lt;/code&gt;, de John Hayes, ainsi que des versions dérivées. J'ai hâte de pouvoir l'utiliser. J'ai deux options. La première est de réécrire le code avec mon système de macros. Jouable, mais un peu long et fastidieux. La seconde est d'attendre d'avoir &lt;strong&gt;un interpréteur Forth&lt;/strong&gt; fonctionnel... mais cela va m'obliger à écrire de nombreux mots sans tests, ce qui me déplaît. Je vais réfléchir à la question.&lt;/p&gt;
&lt;p&gt;Pour la partie gestion du clavier, je pense ajouter à mon framework de test une injection de caractères. Il restera le test du clavier à tester physiquement, mais la boucle principale pourra être testée avec des entrées simulées.&lt;/p&gt;
&lt;h2&gt;La suite !&lt;/h2&gt;
&lt;p&gt;Mon étape suivante va être de compléter le traitement du clavier avec les majuscules, minuscules et kanas. Puis le traitement des touches de directions, insertions, suppressions, etc. Sur cette partie, je ne pense pas faire d'article, cela va être très mécanique. Cependant, je devrai me diriger vers l'implémentation du mot &lt;code&gt;ACCEPT&lt;/code&gt;, qui gère l'entrée clavier et la fournit dans le buffer &lt;code&gt;TIB&lt;/code&gt;. Cela m'obligera à choisir une des options évoquées plus haut, et ce sera donc probablement le sujet de l'article suivant.&lt;/p&gt;
&lt;p&gt;Ah, et il sera peut-être temps de vérifier si tout cela fonctionne sur &lt;strong&gt;une vraie Famicom&lt;/strong&gt; avec un vrai clavier Family BASIC !&lt;/p&gt;
&lt;p&gt;En attendant, voici une capture sur émulateur :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Forth sur 6502 - écriture interactive à l'écran 2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/20260118-Forth-Keypress-2.gif"&gt;&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 9</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-9.html" rel="alternate"></link><published>2026-01-11T00:00:00+01:00</published><updated>2026-01-11T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-01-11:/forth-sur-6502-episode-9.html</id><summary type="html">&lt;h2&gt;Froid, abandon, quitte...&lt;/h2&gt;
&lt;p&gt;C'est triste un démarrage de Forth... &lt;code&gt;COLD&lt;/code&gt;, &lt;code&gt;ABORT&lt;/code&gt;, &lt;code&gt;QUIT&lt;/code&gt;. On aurait pu imaginer des mots comme &lt;code&gt;WARMUP&lt;/code&gt;, &lt;code&gt;READY&lt;/code&gt;, &lt;code&gt;LOOP&lt;/code&gt;. Mais je n'ai pas prévu de renommer les mots standards de Forth. Et comme indiqué dans &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-8.html"&gt;l'article précédent&lt;/a&gt;, il est temps de déplacer le code de démarrage vers les mots officiels.&lt;/p&gt;
&lt;p&gt;Et à vrai dire, comme prévu, il n'y avait pas grand chose à faire.&lt;/p&gt;
&lt;p&gt;Tout d'abord, le code de démarrage devient juste initialiser l'interpréteur avec le mot &lt;code&gt;COLD&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;boot_forth:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Set the Work Register to the first word to execute:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;COLD_word_cfa&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;REG_W&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#&amp;gt;COLD_word_cfa&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;REG_W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; And use it&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;docol&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et pour faire simple, &lt;code&gt;ABORT&lt;/code&gt; et &lt;code&gt;QUIT&lt;/code&gt; appellent juste des mots cachés qui contiennent le code assembleur que j'avais déjà. Cela donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; COLD&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;COLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;RESET_ENV_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ABORT_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; ABORT never returns, no need for DO_SEMI&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; ABORT&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;COLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;h2&gt;Froid, abandon, quitte...&lt;/h2&gt;
&lt;p&gt;C'est triste un démarrage de Forth... &lt;code&gt;COLD&lt;/code&gt;, &lt;code&gt;ABORT&lt;/code&gt;, &lt;code&gt;QUIT&lt;/code&gt;. On aurait pu imaginer des mots comme &lt;code&gt;WARMUP&lt;/code&gt;, &lt;code&gt;READY&lt;/code&gt;, &lt;code&gt;LOOP&lt;/code&gt;. Mais je n'ai pas prévu de renommer les mots standards de Forth. Et comme indiqué dans &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-8.html"&gt;l'article précédent&lt;/a&gt;, il est temps de déplacer le code de démarrage vers les mots officiels.&lt;/p&gt;
&lt;p&gt;Et à vrai dire, comme prévu, il n'y avait pas grand chose à faire.&lt;/p&gt;
&lt;p&gt;Tout d'abord, le code de démarrage devient juste initialiser l'interpréteur avec le mot &lt;code&gt;COLD&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;boot_forth:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Set the Work Register to the first word to execute:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;COLD_word_cfa&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;REG_W&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#&amp;gt;COLD_word_cfa&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;REG_W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; And use it&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;docol&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et pour faire simple, &lt;code&gt;ABORT&lt;/code&gt; et &lt;code&gt;QUIT&lt;/code&gt; appellent juste des mots cachés qui contiennent le code assembleur que j'avais déjà. Cela donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; COLD&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;COLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;RESET_ENV_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ABORT_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; ABORT never returns, no need for DO_SEMI&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; ABORT&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;COLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;RESET_STACK_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;QUIT_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; QUIT never returns, no need for DO_SEMI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Reste &lt;code&gt;QUIT&lt;/code&gt; qui est la boucle infinie. J'avais déjà une boucle infinie sous forme de mot assembleur, je l'ai renommée et voilà, &lt;strong&gt;terminé&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;Certes, ce n'est pas encore un vrai mot &lt;code&gt;QUIT&lt;/code&gt;, qui doit traiter les entrées utilisateur et exécuter les commandes. Mais en tout cas, la structure est en place.&lt;/p&gt;
&lt;h2&gt;Lire le clavier&lt;/h2&gt;
&lt;p&gt;Et donc puisque tout cela n'était pas bien compliqué, et que &lt;code&gt;QUIT&lt;/code&gt; va avoir besoin de lire le clavier, passons à la lecture du clavier.&lt;/p&gt;
&lt;h3&gt;Accès au clavier&lt;/h3&gt;
&lt;p&gt;Le clavier Family BASIC est connecté à la Famicom via le &lt;strong&gt;port d'extension&lt;/strong&gt;. Celui qui est devant dans une Famicom classique. Avant de l'interroger, il faut écrire à l'adresse &lt;code&gt;$4016&lt;/code&gt; puis lire depuis l'adresse &lt;code&gt;$4017&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L'écriture à l'adresse &lt;code&gt;$4016&lt;/code&gt; contrôle le balayage du clavier. En effet, le clavier est une &lt;strong&gt;matrice de touches&lt;/strong&gt; sur 9 lignes et 2 colonnes. La matrice est &lt;a href="https://www.nesdev.org/wiki/Family_BASIC_Keyboard#Matrix"&gt;visible sur NESDev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;L'écriture à &lt;code&gt;$4016&lt;/code&gt; utilise les &lt;strong&gt;3 premiers bits&lt;/strong&gt; pour contrôler le scan.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 = scan normal ; 1 = réinitialiser le scan ligne 0, colonne 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Sélection de colonne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Activer le clavier (1 = activé)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3-7&lt;/td&gt;
&lt;td&gt;inutilisés&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;La lecture depuis &lt;code&gt;$4017&lt;/code&gt; récupère les données du clavier.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Inutilisé&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1-4&lt;/td&gt;
&lt;td&gt;Données de colonne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-7&lt;/td&gt;
&lt;td&gt;Inutilisés&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Un &lt;strong&gt;délai doit être&lt;/strong&gt; respecté entre l'écriture à &lt;code&gt;$4016&lt;/code&gt; et la lecture depuis &lt;code&gt;$4017&lt;/code&gt; pour permettre au clavier de préparer les lignes de données.&lt;/p&gt;
&lt;h3&gt;Scan dans le Forth&lt;/h3&gt;
&lt;p&gt;Pour le scan dans le Forth, j'utilise &lt;strong&gt;trois tampons&lt;/strong&gt; en mémoire qui sont chacun de taille 9 octets (un par ligne). Pour chaque ligne les informations des deux colonnes sont regroupées dans un seul octet.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bits 0-3 : données de la colonne 0&lt;/li&gt;
&lt;li&gt;Bits 4-7 : données de la colonne 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le premier tampon sert au scan en cours. Un second sert à stocker le résultat du scan précédent. Le troisième sert à &lt;strong&gt;détecter les changements&lt;/strong&gt; entre les deux scans (en faisant un XOR entre les deux autres tampons).&lt;/p&gt;
&lt;p&gt;Une fois les tampons remplis, le &lt;strong&gt;tampon de changements&lt;/strong&gt; est analysé pour détecter les changements d'état des touches. Si un bit a changé dans le tampon de changements, l'état pressé/relâché est déterminé à partir du tampon de matrice actuel. Ceci est fait pour l'octet entier, donc si plusieurs bits ont changé dans une ligne, ils sont tous traités.&lt;/p&gt;
&lt;p&gt;Puis pour chaque bit modifié qui est aussi détecté comme un appui, une recherche dans une &lt;strong&gt;table de caractères&lt;/strong&gt; fait la correspondance. Si le caractère est affichable, il est placé dans une file de caractères qui pourra être interrogée plus tard par le mot Forth &lt;code&gt;KEY&lt;/code&gt;, qu'il reste à implémenter.&lt;/p&gt;
&lt;p&gt;Pour chaque bit modifié, je calcule aussi un &lt;strong&gt;code de touche&lt;/strong&gt; (&lt;code&gt;(ligne &amp;lt;&amp;lt; 4) | numéro_de_bit&lt;/code&gt;), mais je ne l'utilise pas. Cela vient d'une idée précédente où je voulais tout d'abord générer les évènements de touches puis les décoder dans un second temps. Au final, j'ai trouvé ça bien compliqué pour cette machine.&lt;/p&gt;
&lt;h3&gt;Ce qu'il reste à faire&lt;/h3&gt;
&lt;p&gt;Plein de choses. Même en se limitant au clavier. Mais je pense que le plus long a été fait : le principe général de scan et de décodage. Il me reste à traiter les touches spéciales (comme SHIFT, CTRL, etc) et à implémenter le mot Forth &lt;code&gt;KEY&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;J'ai prévu d'implémenter aussi le mot &lt;code&gt;KEY?&lt;/code&gt; qui permet de savoir si une touche est disponible. Ainsi que &lt;code&gt;KEYPRESSED?&lt;/code&gt; et &lt;code&gt;KEYDOWN?&lt;/code&gt; pour &lt;strong&gt;interroger l'état&lt;/strong&gt; de touches spécifiques.&lt;/p&gt;
&lt;h2&gt;On peut écrire !&lt;/h2&gt;
&lt;p&gt;En branchant rapidement la détection des touches avec un appel codé en dur à &lt;code&gt;EMIT&lt;/code&gt; dans la boucle principale, je peux &lt;strong&gt;écrire à l'écran&lt;/strong&gt; ! Le curseur n'avance pas, car lui aussi était un appel codé en dur, cependant, c'est assez satisfaisant.&lt;/p&gt;
&lt;p&gt;D'ailleurs, je pense que la prochaine étape sera le traitement de l'avancée du curseur depuis la boucle principale en Forth. Cela va m'obliger à implémenter quelques nouveaux mots, comme &lt;code&gt;0BRANCH&lt;/code&gt; (afin de faire des tests conditionnels).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Forth sur 6502 - écriture interactive à l'écran" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/20260111-Forth-Keypress.gif"&gt;&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 8</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-8.html" rel="alternate"></link><published>2026-01-02T00:00:00+01:00</published><updated>2026-01-02T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-01-02:/forth-sur-6502-episode-8.html</id><summary type="html">&lt;h2&gt;Afficher des caractères&lt;/h2&gt;
&lt;p&gt;Lors du &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-7.html"&gt;précédent article&lt;/a&gt;, l'ajout de &lt;strong&gt;variables&lt;/strong&gt; et de la &lt;strong&gt;pile des paramètres&lt;/strong&gt; nous a approché de l'objectif actuel : afficher des caractères à l'écran. Ou plus exactement, remplacer l'affichage de la chaîne de caractères depuis l'assembleur au démarrage du programme vers la partie Forth.&lt;/p&gt;
&lt;p&gt;Pour commencer et s'assurer que j'ai du code qui peut transformer des coordonnées en adresse PPU et afficher un caractère, je crée un mot &lt;code&gt;TEST_EMIT&lt;/code&gt; qui va prendre ces coordonnées et afficher un &lt;strong&gt;unique caractère&lt;/strong&gt; comme &lt;strong&gt;curseur&lt;/strong&gt;. Comme je n'ai que 26 lettres majuscules actuellement dans mes données graphiques, il est temps d'aller modifier les données. J'ajoute en caractères 255 un carré plein. Cela fera un bon curseur.&lt;/p&gt;
&lt;p&gt;Il me faut aussi deux variables pour stocker les coordonnées du curseur : &lt;code&gt;CURSOR_X&lt;/code&gt; et &lt;code&gt;CURSOR_Y&lt;/code&gt; que j'initialise à l'emplacement où je veux afficher le curseur au démarrage (en effet, je n'ai pas encore de moyen …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Afficher des caractères&lt;/h2&gt;
&lt;p&gt;Lors du &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-7.html"&gt;précédent article&lt;/a&gt;, l'ajout de &lt;strong&gt;variables&lt;/strong&gt; et de la &lt;strong&gt;pile des paramètres&lt;/strong&gt; nous a approché de l'objectif actuel : afficher des caractères à l'écran. Ou plus exactement, remplacer l'affichage de la chaîne de caractères depuis l'assembleur au démarrage du programme vers la partie Forth.&lt;/p&gt;
&lt;p&gt;Pour commencer et s'assurer que j'ai du code qui peut transformer des coordonnées en adresse PPU et afficher un caractère, je crée un mot &lt;code&gt;TEST_EMIT&lt;/code&gt; qui va prendre ces coordonnées et afficher un &lt;strong&gt;unique caractère&lt;/strong&gt; comme &lt;strong&gt;curseur&lt;/strong&gt;. Comme je n'ai que 26 lettres majuscules actuellement dans mes données graphiques, il est temps d'aller modifier les données. J'ajoute en caractères 255 un carré plein. Cela fera un bon curseur.&lt;/p&gt;
&lt;p&gt;Il me faut aussi deux variables pour stocker les coordonnées du curseur : &lt;code&gt;CURSOR_X&lt;/code&gt; et &lt;code&gt;CURSOR_Y&lt;/code&gt; que j'initialise à l'emplacement où je veux afficher le curseur au démarrage (en effet, je n'ai pas encore de moyen de modifier le contenu d'une variable facilement à partir d'un nombre).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    DEFINE_VARIABLE CURSOR_X, POST_LOGIC
    .word $0001

    DEFINE_VARIABLE CURSOR_Y, CURSOR_X
    .word $0002
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On peut noter que 16 bits pour des coordonnées d'écran en caractères, c'est beaucoup. On peut imaginer « compresser » les deux coordonnées dans une seule variable. Ça compliquera un peu l'écriture cependant. Je me laisse ça en note pour plus tard.&lt;/p&gt;
&lt;p&gt;Ah oui, autre chose. Peut-être que vous l'aviez remarqué avant moi, mais les variables que je définis sont actuellement dans le programme, et donc &lt;strong&gt;en ROM&lt;/strong&gt; ! Pas terrible pour des variables. Je me note ça aussi pour plus tard (mais dans pas longtemps, car sinon, le curseur ne pourra pas bouger).&lt;/p&gt;
&lt;h3&gt;Presque EMIT&lt;/h3&gt;
&lt;p&gt;Quant à &lt;code&gt;TEST_EMIT&lt;/code&gt;, il est en assembleur et il ressemble à ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;hardcoded&lt;/span&gt; &lt;span class="n"&gt;EMIT&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE_CODE_WORD&lt;/span&gt; &lt;span class="n"&gt;TEST_EMIT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CURSOR_Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;jsr&lt;/span&gt; &lt;span class="n"&gt;compute_screen_address&lt;/span&gt;  &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Now&lt;/span&gt; &lt;span class="n"&gt;Addr&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PPU&lt;/span&gt;

    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;endianness&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;swapped&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;vram_queue_set_ppu&lt;/span&gt;
    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;High&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="n"&gt;Addr&lt;/span&gt;
    &lt;span class="n"&gt;sta&lt;/span&gt; &lt;span class="n"&gt;VramQueuePtr&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;sta&lt;/span&gt; &lt;span class="n"&gt;VramQueuePtr&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="o"&gt;#$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Horizontal&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;
    &lt;span class="n"&gt;jsr&lt;/span&gt; &lt;span class="n"&gt;vram_queue_set_ppu&lt;/span&gt;

    &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;
    &lt;span class="n"&gt;vram_t_set_buffer&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;C&amp;#39;&lt;/span&gt;        &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Hardcoded&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;
    &lt;span class="n"&gt;ldy&lt;/span&gt; &lt;span class="o"&gt;#$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;
    &lt;span class="n"&gt;sta&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VramQueuePtr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;

    &lt;span class="n"&gt;END_TO_NEXT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;compute_screen_address&lt;/code&gt; est une sous-routine qui prend les coordonnées du curseur et calcule l'&lt;strong&gt;adresse PPU correspondante&lt;/strong&gt;. C'est une partie dont je veux m'assurer avoir compris le fonctionnement (et l'écriture en 6502).&lt;/p&gt;
&lt;p&gt;J'utilise ensuite le système du template de projet pour communiquer avec le PPU.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VramQueuePtr&lt;/code&gt; sert dans un premier temps de variable paramètre pour &lt;code&gt;vram_queue_set_ppu&lt;/code&gt;, qui positionne le registre d'adresse PPU. Plus exactement qui prépare la commande dans la &lt;strong&gt;liste d'affichage&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;la macro &lt;code&gt;vram_t_set_buffer&lt;/code&gt; &lt;strong&gt;réserve de l'espace&lt;/strong&gt; (ici 1 octet) dans la liste d'affichage et fait pointer &lt;code&gt;VramQueuePtr&lt;/code&gt; au début de cet espace. Le contenu de ce buffer sera transféré à l'adresse PPU spécifiée.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À noter que l'allocation de l'espace retourne sans rien faire s'il n'y a plus de place. Comme je ne vérifie rien, cela peut être assez catastrophique. Pour le moment, j'affiche un seul caractère par rafraîchissement, ça va passer. Le système du template limite la taille d'un transfert à 64 octets et le buffer complet est de 256 octets. Je ne sais pas encore si je mettrai des protections en place ou bien si je laisse l'utilisateur gérer cela. Je n'aime pas trop l'idée de se retrouver avec un programme qui plante sans explication, mais d'un autre côté, c'est du Forth, pas du BASIC.&lt;/p&gt;
&lt;p&gt;Et ça marche, voici le résultat :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Affichage du curseur sur Family Forth" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/2026/20260120-family_forth_cursor.png"&gt;&lt;/p&gt;
&lt;h3&gt;Des variables... pour de vrai ?&lt;/h3&gt;
&lt;p&gt;Comme indiqué plus haut, le contenu de mes variables sont en ROM. Pas terrible. Comment faire pour avoir des variables définies par la ROM, mais dont le contenu est en RAM ? Une méthode classique est de transformer les &lt;strong&gt;variables en constantes&lt;/strong&gt;. Je sais, dit comme ça, ça semble bizarre. Mais ça se comprend : on transforme une variable, qui contient donc sa propre valeur, en une constante qui contient l'adresse mémoire où la valeur sera stockée. Cet espace sera réservé en RAM.&lt;/p&gt;
&lt;p&gt;Après tout, le fonctionnement d'une variable en Forth n'est rien d'autre qu'un mot qui place une &lt;strong&gt;adresse mémoire&lt;/strong&gt; sur la &lt;strong&gt;pile des paramètres&lt;/strong&gt;. La variable place son propre &lt;code&gt;PFA&lt;/code&gt;. Une constante place une valeur spécifiée.&lt;/p&gt;
&lt;h3&gt;EMIT... pour de vrai aussi&lt;/h3&gt;
&lt;p&gt;Pour le moment &lt;code&gt;TEST_EMIT&lt;/code&gt; code en dur le caractère. &lt;code&gt;EMIT&lt;/code&gt;, lui, doit envoyer à l'affichage le caractère dont le code est présent sur la pile. Pour avoir un vrai &lt;code&gt;EMIT&lt;/code&gt;, il faut donc modifier &lt;code&gt;TEST_EMIT&lt;/code&gt; pour qu'il récupère le code caractère depuis la pile des paramètres. Et cette valeur devra y être placée auparavant. Cela tombe bien, je viens d'implémenter le concept de constantes.&lt;/p&gt;
&lt;p&gt;Voici donc mon &lt;strong&gt;curseur&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    DEFINE_CONSTANT CURSOR_CODE, TEST_ADDR
    .word $FF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et la &lt;strong&gt;boucle principale Forth&lt;/strong&gt; devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    DEFINE_FORTH_WORD MAIN_LOOP, MEMORY_TEST, 0
    .word READ_JOY_SAFE_word_cfa
    .word MEMORY_TEST_word_cfa
    .word CURSOR_CODE_word_cfa      ; On place le code caractère sur la pile
    .word EMIT_word_cfa             ; On appelle EMIT pour afficher ce caractère
    .word POST_LOGIC_word_cfa
    .word DO_SEMI_word_cfa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ça fonctionne. Pour un &lt;strong&gt;même résultat&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Cependant, &lt;code&gt;EMIT&lt;/code&gt; est censé aussi avancer la &lt;strong&gt;position du curseur&lt;/strong&gt;. Ce que je peux brancher, mais qui va poser problème. Car la position avançant à chaque affichage, le curseur se retrouve affiché à chaque position de l'écran, et l'écran devient rapidement entièrement rempli d'une couleur unie.&lt;/p&gt;
&lt;p&gt;En attendant une vraie gestion de curseur, je replace le curseur à la position initiale à chaque itération de la boucle principale.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; MAIN LOOP word&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MAIN_LOOP&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MEMORY_TEST&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;READ_JOY_SAFE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MEMORY_TEST_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CURSOR_INIT_X_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CURSOR_X_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;STORE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CURSOR_INIT_Y_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CURSOR_Y_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;STORE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CURSOR_CODE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EMIT_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;POST_LOGIC_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;DO_SEMI_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui équivaut en Forth à :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MAIN_LOOP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;READ_JOY_SAFE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;MEMORY_TEST&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_INIT_X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;!&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_INIT_Y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_Y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;!&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_CODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EMIT&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;POST_LOGIC&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Moving Forth, épisode 6&lt;/h2&gt;
&lt;p&gt;Revenons un peu à la lecture de la série d'articles &lt;strong&gt;Moving Forth&lt;/strong&gt; avec la &lt;a href="https://www.bradrodriguez.com/papers/moving6.htm"&gt;sixième partie&lt;/a&gt;. Après avoir présenté les primitives du langage, ce qui forme le « kernel », l'auteur aborde la notion de &lt;strong&gt;« high-level kernel »&lt;/strong&gt;. Il s'agit du reste du système, celui qui permet l'interactivité et donc la compilation de nouveaux mots et leur exécution. Ce « high-level kernel » est écrit en Forth et se veut portable, contrairement au « kernel » contenant les primitives, écrit en assembleur.&lt;/p&gt;
&lt;p&gt;On y apprend que le démarrage de Forth est effectué par&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un mot appelé &lt;code&gt;COLD&lt;/code&gt;, qui s'occupe de l'initialisation des variables internes (de l'environnement je dirais),&lt;/li&gt;
&lt;li&gt;qui lui-même appelle &lt;code&gt;ABORT&lt;/code&gt;, qui réinitialise la pile de paramètres,&lt;/li&gt;
&lt;li&gt;qui lui-même appelle &lt;code&gt;QUIT&lt;/code&gt;, qui réinitialise la pile de retour, l'état de l'interpréteur, et lance la boucle principale de l'interpréteur.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;QUIT&lt;/code&gt; est une &lt;strong&gt;boucle infinie&lt;/strong&gt; qui lit l'entrée utilisateur et appelle le mot &lt;code&gt;INTERPRET&lt;/code&gt;, qui s'occupe de l'analyse de l'entrée.&lt;/p&gt;
&lt;p&gt;J'ai déjà le contenu de &lt;code&gt;COLD&lt;/code&gt; et &lt;code&gt;ABORT&lt;/code&gt; dans mon &lt;strong&gt;bootstrap de Forth&lt;/strong&gt;. Il me faudra les implémenter en tant que mots Forth.&lt;/p&gt;
&lt;p&gt;Pour implémenter &lt;code&gt;QUIT&lt;/code&gt;, il me faudra implémenter la réception de l'entrée utilisateur, et donc du clavier de la Famicom. Puis pas mal d'autres mots qui seront nécessaires pour &lt;code&gt;INTERPRET&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;De là, l'article mentionne sans entrer dans le détail le concept de &lt;strong&gt;« vocabulaire »&lt;/strong&gt;, qui permet d'avoir plusieurs dictionnaires de mots, regroupés par fonctionnalités. Comme le Forth de l'article n'en a pas, il n'y a pas plus d'explications. J'ai prévu de mon côté d'implémenter cette notion.&lt;/p&gt;
&lt;p&gt;Puis l'auteur revient sur l'entête d'un mot et du &lt;strong&gt;drapeau « IMMEDIATE »&lt;/strong&gt; que j'avais évoqué lors de la &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-6.html"&gt;sixième partie&lt;/a&gt; et la création des mots complets. Lors de la compilation d'un mot (on verra ça plus tard), les mots trouvés sont normalement « compilés » dans le mot en train d'être définis. Sauf si le mot est marqué comme « IMMEDIATE », auquel cas il est exécuté immédiatement. Cela permet de contrôler la compilation. On peut considérer que c'est de la « méta-compilation », comme des macros qui vont effectuer des opérations pendant la compilation.&lt;/p&gt;
&lt;p&gt;Par exemple, &lt;code&gt;IF&lt;/code&gt; est un mot « IMMEDIATE » qui va insérer des instructions de branchement conditionnel dans le mot en cours de définition, conjointement avec &lt;code&gt;ELSE&lt;/code&gt; et &lt;code&gt;THEN&lt;/code&gt;, qui sont aussi des mots « IMMEDIATE ».&lt;/p&gt;
&lt;p&gt;L'article décrit d'ailleurs rapidement la manière dont la &lt;strong&gt;compilation&lt;/strong&gt; fonctionne :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la compilation démarre avec le mot &lt;code&gt;:&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;le mot est créé avec &lt;code&gt;CREATE&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;le &lt;code&gt;CFA&lt;/code&gt; est initialisé pour pointer sur le &lt;code&gt;DOCOL&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;on passe en mode « compilation »,&lt;/li&gt;
&lt;li&gt;chaque mot trouvé voit son &lt;code&gt;CFA&lt;/code&gt; ajouté à la fin du &lt;code&gt;PFA&lt;/code&gt; du mot en cours de définition,&lt;/li&gt;
&lt;li&gt;lorsque le mot &lt;code&gt;;&lt;/code&gt; est trouvé, on ajoute le &lt;code&gt;CFA&lt;/code&gt; de &lt;code&gt;;S&lt;/code&gt; (&lt;code&gt;EXIT&lt;/code&gt;) à la fin du &lt;code&gt;PFA&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;on repasse en mode « interprétation ».&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il y a des choses en plus qui sont faites, comme rendre le mot visible à la fin de la compilation, l'insérer dans le dictionnaire du vocabulaire courant, traiter les mots « IMMEDIATE », etc... Mais le principe est là.&lt;/p&gt;
&lt;p&gt;Après avoir indiqué les mots qui sont impactés par le modèle d'exécution choisi, la fin de l'article montre le layout mémoire sur CP/M pour le Forth implémenté, ce qui ne m'intéresse pas trop ici, ainsi que différent types de &lt;strong&gt;layout de mots&lt;/strong&gt; Forth.&lt;/p&gt;
&lt;p&gt;Je ne les reproduis pas ici, vous pouvez aller les voir dans l'article original. On y voit quatre Forth différents qui font chacun des choix différents. Mes choix sont globalement ceux de &lt;strong&gt;FIG-Forth&lt;/strong&gt;, ce qui n'est pas étonnant puisque c'est le type de Forth que j'ai pu aborder dans mes &lt;a href="https://www.triceraprog.fr/le-forth-sur-hector-hrx.html"&gt;expériences précédentes&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;La suite&lt;/h2&gt;
&lt;p&gt;On s'approche d'un système interactif, mais il reste encore un gros morceau côté Famicom plus que côté Forth : la &lt;strong&gt;gestion du clavier&lt;/strong&gt;. Détecter qu'il est là, scanner les touches, les interpréter, en particulier les touches spéciales (peut-être dans un second temps). Si l'appui sur une touche provoque l'affichage d'un caractère à l'écran, on aura presque la première partie de l'interpréteur.&lt;/p&gt;
&lt;p&gt;Côté Moving Forth, c'est terminé. Il reste en fait deux articles, mais qui traitent de spécificités sur des architectures particulières. Cela s'éloigne trop du projet que j'ai. Je parcourrai peut-être une autre référence comme le livre &lt;strong&gt;« Starting Forth »&lt;/strong&gt;, qui me servira &lt;a href="https://www.forth.com/starting-forth/9-forth-execution/"&gt;probablement de guide&lt;/a&gt; pour l'implémentation de &lt;code&gt;QUIT&lt;/code&gt; et &lt;code&gt;INTERPRET&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;À bientôt pour la suite !&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 7</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-7.html" rel="alternate"></link><published>2026-01-01T00:00:00+01:00</published><updated>2026-01-01T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2026-01-01:/forth-sur-6502-episode-7.html</id><summary type="html">&lt;h2&gt;En route pour l'affichage&lt;/h2&gt;
&lt;h3&gt;Afficher du texte à l'écran&lt;/h3&gt;
&lt;p&gt;L'étape d'aujourd'hui va permettre de se diriger vers l'&lt;strong&gt;affichage&lt;/strong&gt; d'un texte à l'écran depuis la boucle Forth. Pour cela, il faut revenir un peu sur le fonctionnement de la Famicom.&lt;/p&gt;
&lt;p&gt;Le processeur qui s'occupe de l'affichage est le &lt;strong&gt;PPU&lt;/strong&gt; (Picture Processing Unit). Ce processeur a son espace d'adressage mémoire propre de 16 ko dont le routage est configuré par la cartouche insérée. Dans la console, 2 ko de RAM sont dédiés au PPU, assez pour stocker les informations de deux écrans (index de caractères et attributs). La cartouche doit apporter a minima les informations de caractères (en ROM généralement, mais peut aussi offrir un espace RAM pour les construire) ; elle peut aussi étendre le nombre d'écrans (jusqu'à 4) ou ajouter un système de banking de pages.&lt;/p&gt;
&lt;p&gt;De manière générale, tout le mapping de la mémoire du PPU est contrôlé par …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;En route pour l'affichage&lt;/h2&gt;
&lt;h3&gt;Afficher du texte à l'écran&lt;/h3&gt;
&lt;p&gt;L'étape d'aujourd'hui va permettre de se diriger vers l'&lt;strong&gt;affichage&lt;/strong&gt; d'un texte à l'écran depuis la boucle Forth. Pour cela, il faut revenir un peu sur le fonctionnement de la Famicom.&lt;/p&gt;
&lt;p&gt;Le processeur qui s'occupe de l'affichage est le &lt;strong&gt;PPU&lt;/strong&gt; (Picture Processing Unit). Ce processeur a son espace d'adressage mémoire propre de 16 ko dont le routage est configuré par la cartouche insérée. Dans la console, 2 ko de RAM sont dédiés au PPU, assez pour stocker les informations de deux écrans (index de caractères et attributs). La cartouche doit apporter a minima les informations de caractères (en ROM généralement, mais peut aussi offrir un espace RAM pour les construire) ; elle peut aussi étendre le nombre d'écrans (jusqu'à 4) ou ajouter un système de banking de pages.&lt;/p&gt;
&lt;p&gt;De manière générale, tout le mapping de la mémoire du PPU est contrôlé par la cartouche, à part les palettes. La cartouche la plus simple possible n'offrira que les &lt;strong&gt;8 ko de ROM&lt;/strong&gt; nécessaires aux deux tables de définition de caractères, mais on peut faire beaucoup plus complexe.&lt;/p&gt;
&lt;p&gt;À cela s'ajoute 256 octets de mémoire pour la gestion des sprites.&lt;/p&gt;
&lt;p&gt;Le PPU utilise toutes ses informations pour composer l'image à l'écran. Cependant le processeur 6502 n'a pas accès à cette mémoire. Pour y accéder, il existe des registres mappés dans l'espace d'adressage du CPU. Mais... il y a un mais. Lorsque le PPU est en train de faire le rendu, il a un &lt;strong&gt;besoin exclusif&lt;/strong&gt; d'accès à sa mémoire. Le CPU doit donc attendre que le PPU soit dans une période où il n'a pas besoin d'accéder à sa mémoire : la période de « VBlank » (Vertical Blank), qui correspond au moment où l'écran n'est pas en train d'être rafraîchi (le balayage vertical revient en haut de l'écran).&lt;/p&gt;
&lt;p&gt;Par sécurité, pendant cette période, il faut désactiver le PPU, puis faire les modifications nécessaires et enfin réactiver le PPU. Il y a donc un temps assez bref pendant lequel on peut faire des modifications à la mémoire du PPU.&lt;/p&gt;
&lt;p&gt;Le squelette de projet que j'ai choisi utilise une pratique assez courante : construire une &lt;strong&gt;liste de commandes&lt;/strong&gt; à envoyer au PPU. Lorsque la synchronisation verticale se produit, la liste préparée est traitée. Cette liste est limitée en taille, puisque le temps d'accès est limité.&lt;/p&gt;
&lt;p&gt;Tout cela pour dire que pour afficher un caractère à l'écran, il va falloir envoyer plusieurs commandes au PPU.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tout d'abord positionner le registre d'adresse de la prochaine écriture en mémoire PPU.&lt;/li&gt;
&lt;li&gt;Puis envoyer le caractère à écrire.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le mot Forth &lt;strong&gt;&lt;code&gt;EMIT&lt;/code&gt;&lt;/strong&gt;, qui affiche un caractère, devra donc faire tout cela à chaque fois, ce qui n'est pas très efficace. Mais c'est le plus simple à implémenter. Il est possible d'utiliser une incrémentation automatique de l'adresse d'écriture par le PPU, et celle-ci pourra être utilisée pour optimiser &lt;code&gt;TYPE&lt;/code&gt; ou &lt;code&gt;."&lt;/code&gt; plus tard. Mais cela ne sera pas si simple, car le buffer de commandes est limité en taille et il faudra traiter la césure de chaînes trop longues.&lt;/p&gt;
&lt;p&gt;À voir. Le principe du projet est d'avoir un équivalent Forth au &lt;strong&gt;Family BASIC&lt;/strong&gt;, pas un système optimisé.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EMIT&lt;/code&gt; va donc ressembler à ceci :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;récupération des coordonnées du curseur,&lt;/li&gt;
&lt;li&gt;calcul de l'adresse PPU en fonction des coordonnées,&lt;/li&gt;
&lt;li&gt;positionnement du registre d'adresse PPU (dans la liste de commandes),&lt;/li&gt;
&lt;li&gt;écriture du caractère à l'adresse PPU (dans la liste de commandes),&lt;/li&gt;
&lt;li&gt;mise à jour des coordonnées du curseur,&lt;/li&gt;
&lt;li&gt;NEXT.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il faut donc maintenir les &lt;strong&gt;coordonnées du curseur&lt;/strong&gt; quelque part, et cela signifie l'utilisation de variables.&lt;/p&gt;
&lt;h3&gt;Les variables&lt;/h3&gt;
&lt;p&gt;Les variables en Forth sont, comme tout le reste, des &lt;strong&gt;mots dans le dictionnaire&lt;/strong&gt;. Lorsqu'une variable est exécutée, elle place l'adresse réservée pour son contenu sur la pile des paramètres, et c'est tout.&lt;/p&gt;
&lt;p&gt;Pour cela, un mot de type variable a pour &lt;code&gt;CFA&lt;/code&gt; une routine qui place l'adresse &lt;code&gt;PFA&lt;/code&gt; sur la pile des paramètres. Le &lt;em&gt;Parameter Field&lt;/em&gt;, lui, est un espace mémoire réservé de deux octets qui contiendra la valeur de la variable.&lt;/p&gt;
&lt;p&gt;Avec la totalité d'un mot de type variable, cela fait 2 octets pour la valeur, 2 octets pour le CFA, 2 octets pour le chaînage, 1 octet pour la longueur du nom, et le nom lui-même. Soit un &lt;strong&gt;minimum de 8 octets&lt;/strong&gt; par variable pour une variable à 16 bits. Cela peut sembler cher payer, mais ce système est autonome.&lt;/p&gt;
&lt;p&gt;Cela permet d'écrire, si la variable s'appelle &lt;code&gt;CURSOR_X&lt;/code&gt; par exemple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;\ lit la valeur de la variable&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CURSOR_X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;!&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;\ écrit la valeur dans la variable&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le mot &lt;code&gt;@&lt;/code&gt; (&lt;strong&gt;fetch&lt;/strong&gt;) lit une valeur à l'adresse située au sommet de la pile des paramètres et place cette valeur sur la pile.&lt;/p&gt;
&lt;p&gt;Le mot &lt;code&gt;!&lt;/code&gt; (&lt;strong&gt;store&lt;/strong&gt;) prend une adresse et une valeur sur la pile des paramètres, et écrit la valeur à l'adresse.&lt;/p&gt;
&lt;p&gt;Il nous faut donc écrire :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le code assembleur pointé par un mot de type variable (que j'appellerai &lt;code&gt;DOVAR&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;le mot &lt;code&gt;@&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;le mot &lt;code&gt;!&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;... et donc s'occuper du &lt;strong&gt;fonctionnement de la pile des paramètres&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je n'implémenterai pas encore le mot &lt;code&gt;VARIABLE&lt;/code&gt; qui permet de définir une nouvelle variable depuis Forth. Je vais écrire les variables directement en assembleur pour le moment.&lt;/p&gt;
&lt;h3&gt;Pas si vite !&lt;/h3&gt;
&lt;p&gt;Cela fait déjà beaucoup de choses à faire avant d'implémenter &lt;code&gt;EMIT&lt;/code&gt;. J'ai besoin d'une &lt;strong&gt;étape intermédiaire&lt;/strong&gt; pour m'assurer que tout fonctionne correctement. Pour cela, je vais réécrire le mot de test en Forth.&lt;/p&gt;
&lt;p&gt;Pour rappel, voici à quoi ressemble le mot de test en assembleur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;writes&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE_CODE_WORD&lt;/span&gt; &lt;span class="n"&gt;TEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="o"&gt;#$&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="n"&gt;sta&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;
    &lt;span class="n"&gt;END_TO_NEXT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En Forth, cela s'écrit simplement (pourvu que la base des nombres soit en hexadécimal) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TEST&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nf"&gt;FF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;C!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mais comme c'est le système de &lt;strong&gt;pile de paramètres&lt;/strong&gt; et de &lt;strong&gt;variables&lt;/strong&gt; que je veux tester, je vais plutôt écrire :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TEST&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;TEST_VALUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;\ lit la valeur de la variable TEST_VALUE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;TEST_ADDR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;\ lit la valeur de la variable TEST_ADDR&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;!&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;\ écrit cette valeur de TEST_VALUE à l&amp;#39;adresse TEST_ADDR&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Retour à la pile des paramètres&lt;/h3&gt;
&lt;p&gt;La pile des paramètres est une zone de mémoire en RAM, de 256 octets. Cela permet de l'indexer facilement en mode indirect avec le registre &lt;code&gt;Y&lt;/code&gt;. Pour ne pas monopoliser le registre, je garde une variable d'un octet en Page Zéro. Cela nécessite cependant d'aller chercher et modifier la variable à chaque opération de pile.&lt;/p&gt;
&lt;p&gt;Ainsi, le haut de la pile sera à tout moment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(ParamStack),y&lt;/code&gt; pour l'octet de poids faible avec &lt;code&gt;y = REG_PSP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(ParamStack),y&lt;/code&gt; pour l'octet de poids fort avec &lt;code&gt;y = REG_PSP + 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La pile grandit vers les &lt;strong&gt;adresses mémoire basses&lt;/strong&gt;, avec l'index initialisé à 0 et décrémenté lors des &lt;code&gt;PUSH&lt;/code&gt;, incrémenté lors des &lt;code&gt;POP&lt;/code&gt;. Le premier emplacement de valeur 16 bits sera donc aux adresses indexées par &lt;code&gt;$FE&lt;/code&gt; et &lt;code&gt;$FF&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je modifie un peu mes macros de définition de mots car &lt;code&gt;FETCH&lt;/code&gt; et &lt;code&gt;STORE&lt;/code&gt; doivent s'encoder en tant que mots avec les symboles &lt;code&gt;@&lt;/code&gt; et &lt;code&gt;!&lt;/code&gt;, mais la génération des labels pour l'assembleur ne peut pas utiliser ces symboles. J'ajoute donc la possibilité de &lt;strong&gt;différencier&lt;/strong&gt; le &lt;strong&gt;nom du mot&lt;/strong&gt; et le &lt;strong&gt;symbole&lt;/strong&gt; utilisé dans le dictionnaire.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FETCH&lt;/code&gt; fait les actions suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;récupérer l'adresse au sommet de la pile des paramètres&lt;/li&gt;
&lt;li&gt;la placer dans un registre d'adresse Page Zero temporaire&lt;/li&gt;
&lt;li&gt;lire la valeur à cette adresse (2 octets)&lt;/li&gt;
&lt;li&gt;placer cette valeur sur la pile des paramètres&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;STORE&lt;/code&gt; fait les actions suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;récupérer l'adresse au sommet de la pile des paramètres&lt;/li&gt;
&lt;li&gt;la placer dans un registre d'adresse Page Zero temporaire&lt;/li&gt;
&lt;li&gt;récupérer la valeur suivante sur la pile des paramètres (2 octets)&lt;/li&gt;
&lt;li&gt;écrire cette valeur à l'adresse dans le registre temporaire&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Le mot de test en Forth&lt;/h3&gt;
&lt;p&gt;Le &lt;strong&gt;mot final de test&lt;/strong&gt; en Forth devient, accompagné du code des deux variables :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; TEST_VALUE, a variable to hold a test value&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_VARIABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_VALUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;STORE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$4200&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; TEST_ADDR, a variable to hold a test address&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_VARIABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_ADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_VALUE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$07FE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; A test word that writes $4242 to $7FE (16 bits)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEFINE_FORTH_WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;NEW_TEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_ADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_VALUE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;FETCH_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TEST_ADDR_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;FETCH_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;STORE_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;.word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;DO_SEMI_word_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;C'est... beaucoup plus long que les deux instructions d'assembleur initiales. Cela ne fait pas non plus exactement la même chose, car j'ai implémenté tous ces mots pour des &lt;strong&gt;valeurs de 16 bits&lt;/strong&gt;. Plutôt que d'écrire &lt;code&gt;$42&lt;/code&gt; à l'adresse &lt;code&gt;$7FF&lt;/code&gt;, j'écris &lt;code&gt;$4200&lt;/code&gt; à l'adresse &lt;code&gt;$7FE&lt;/code&gt; (avec l'endianness, cela écrit bien $42 à $7FF). Cela fait passer le test et même si c'est un peu différent, cela teste bien le fonctionnement de la pile des paramètres et des variables.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Pas de lecture d'article Moving Forth aujourd'hui, il y a déjà assez de matière ici. J'ai une &lt;strong&gt;pile de paramètres fonctionnelle&lt;/strong&gt; (mais non protégée), un &lt;strong&gt;système de variables&lt;/strong&gt;, &lt;strong&gt;deux instructions&lt;/strong&gt; élémentaires de manipulation de la &lt;strong&gt;pile&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Je m'approche du nécessaire pour l'implémentation de &lt;code&gt;EMIT&lt;/code&gt;, qui sera très probablement le sujet du prochain article.&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 6</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-6.html" rel="alternate"></link><published>2025-12-30T00:00:00+01:00</published><updated>2025-12-30T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-30:/forth-sur-6502-episode-6.html</id><summary type="html">&lt;h2&gt;Des mots complets&lt;/h2&gt;
&lt;p&gt;Depuis le début de l'implémentation de ce Forth sur 6502, j'ai parlé de « pseudo mots ». Ces mots ont un &lt;code&gt;CFA&lt;/code&gt; (Code Field Address) et un &lt;code&gt;PFA&lt;/code&gt; (Parameter Field Address), mais pas d'&lt;strong&gt;entête de mot&lt;/strong&gt; ni de principe de &lt;strong&gt;dictionnaire&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Or pour qu'un mot soit complet en Forth, il faut ces deux autres concepts. Dans cette implémentation je vais utiliser deux autres sections : le NFA (Name Field Address) et le LFA (Link Field Address).&lt;/p&gt;
&lt;p&gt;Ce qui donne la &lt;strong&gt;structure complète&lt;/strong&gt; suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NFA&lt;/code&gt; : &lt;strong&gt;entête du mot&lt;/strong&gt;, dont le premier octet est la longueur du nom du mot, suivi du nom lui-même. Seuls les 5 bits de poids faible sont utilisés pour la longueur (ce qui limite la longueur des noms à 31 caractères). Le bit de poids fort est toujours à 1, les deux autres bits seront vus plus tard. De plus, le dernier octet du nom a …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2&gt;Des mots complets&lt;/h2&gt;
&lt;p&gt;Depuis le début de l'implémentation de ce Forth sur 6502, j'ai parlé de « pseudo mots ». Ces mots ont un &lt;code&gt;CFA&lt;/code&gt; (Code Field Address) et un &lt;code&gt;PFA&lt;/code&gt; (Parameter Field Address), mais pas d'&lt;strong&gt;entête de mot&lt;/strong&gt; ni de principe de &lt;strong&gt;dictionnaire&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Or pour qu'un mot soit complet en Forth, il faut ces deux autres concepts. Dans cette implémentation je vais utiliser deux autres sections : le NFA (Name Field Address) et le LFA (Link Field Address).&lt;/p&gt;
&lt;p&gt;Ce qui donne la &lt;strong&gt;structure complète&lt;/strong&gt; suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NFA&lt;/code&gt; : &lt;strong&gt;entête du mot&lt;/strong&gt;, dont le premier octet est la longueur du nom du mot, suivi du nom lui-même. Seuls les 5 bits de poids faible sont utilisés pour la longueur (ce qui limite la longueur des noms à 31 caractères). Le bit de poids fort est toujours à 1, les deux autres bits seront vus plus tard. De plus, le dernier octet du nom a son bit de poids fort à 1 pour indiquer la fin du nom.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LFA&lt;/code&gt; : adresse du mot précédent dans la &lt;strong&gt;liste chaînée&lt;/strong&gt; des mots. Tous les mots disponibles dans ce Forth forment une liste chaînée, chaque mot pointant vers le mot défini avant lui. Le dernier mot défini pointe vers l'adresse 0 pour indiquer la fin de chaîne.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CFA&lt;/code&gt; : adresse du &lt;strong&gt;code machine&lt;/strong&gt; qui sera exécuté lorsque le mot sera appelé.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PFA&lt;/code&gt; : &lt;strong&gt;paramètres du mot&lt;/strong&gt;, s'il en a.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Précision&lt;/strong&gt; : cette implémentation d'un mot complet est celle que l'on trouve dans des Forth historiques 8 bits. Mais elle n'est pas obligatoire, il peut y avoir des &lt;strong&gt;variantes&lt;/strong&gt;. Rien n'empêche d'inverser l'ordre du NFA et du LFA. Ou de terminer le nom par un octet nul plutôt que par un marqueur dans le bit de poids fort.&lt;/p&gt;
&lt;p&gt;En regardant des &lt;a href="https://forth-standard.org/standard/usage"&gt;normes plus récentes&lt;/a&gt; (section 3.3), on voit qu'il existe un « name space » un « code space » et un « parameter space », et que les mots sont organisés dans un « dictionnaire », cependant, il est laissé à l'implémentation de faire les choix de représentation.&lt;/p&gt;
&lt;h3&gt;Implémentation&lt;/h3&gt;
&lt;p&gt;Pour implémenter ces mots complets, j'ajoute des &lt;strong&gt;macros&lt;/strong&gt; pour faciliter l'écriture (et surtout la réécriture en cas de changement d'idée).&lt;/p&gt;
&lt;p&gt;Mon mot de test, qui permet de valider que le programme exécute bien la boucle, était comme ceci : &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;test_word_cfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;test_word_pfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;test_word_pfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;#$42&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;$7FF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il devient maintenant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    &lt;span class="n"&gt;DEFINE_CODE_WORD&lt;/span&gt; &lt;span class="n"&gt;TEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;lda&lt;/span&gt; &lt;span class="o"&gt;#$&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="n"&gt;sta&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;
    &lt;span class="n"&gt;END_TO_NEXT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La macro &lt;code&gt;DEFINE_CODE_WORD&lt;/code&gt; prend trois paramètres : le nom du mot, le mot précédent (pour le chaînage) et un drapeau pour les mots immédiats, que l'on n'a pas encore abordé. La macro &lt;code&gt;END_TO_NEXT&lt;/code&gt; termine le mot en appelant &lt;code&gt;NEXT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ainsi, pour le mots Forth définis par du code assembleur, il ne reste apparent que le code lui-même, encadré par les macros.&lt;/p&gt;
&lt;p&gt;J'ai une seconde macro qui permet de définir des mots exécutés par « DOCOL », c'est-à-dire des mots écrits comme une série de pointeurs vers d'autres mots.&lt;/p&gt;
&lt;p&gt;La boucle principale devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    DEFINE_FORTH_WORD MAIN_LOOP, TEST, 0
    .word READ_JOY_SAFE_word_cfa
    .word TEST_word_cfa
    .word POST_LOGIC_word_cfa
    .word DO_SEMI_word_cfa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Moving Forth, épisode 5&lt;/h2&gt;
&lt;p&gt;Avançons dans la lecture de la série d'articles &lt;strong&gt;Moving Forth&lt;/strong&gt; avec la &lt;a href="https://www.bradrodriguez.com/papers/moving5.htm"&gt;cinquième partie&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;L'auteur présente le code source d'un ANSI Forth, CamelForth, pour les processeurs Z80, 8051 et 6809. Passons. Ce qui m'intéresse le plus, c'est la notion de &lt;strong&gt;« kernel »&lt;/strong&gt;. À partir de quel ensembles de mots de base écrits peut-on construire un Forth complet ? Et surtout, combien de mots doit-on implémenter en assembleur avant de construire le reste par dessus ?&lt;/p&gt;
&lt;p&gt;C'est une question que je me posais dès le &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-1.html"&gt;premier article&lt;/a&gt; dans la conclusion. Je me disais que pour faciliter les choix d'implémentation, il serait intéressant d'avoir un &lt;strong&gt;minimum de mots&lt;/strong&gt; implémentés en assembleur.&lt;/p&gt;
&lt;p&gt;Cependant, ce dont nous prévient l'article, c'est que même s'il est théoriquement possible de se limiter à &lt;strong&gt;13 primitives&lt;/strong&gt;, dans la pratique, faire ce choix entraînera un &lt;strong&gt;Forth peu véloce&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'auteur propose une &lt;strong&gt;liste de critères&lt;/strong&gt; pour décider si un mot doit être implémenté en assembleur ou en Forth :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la &lt;strong&gt;base arithmétique&lt;/strong&gt;, logique et mémoire le sont. Cela semble évident.&lt;/li&gt;
&lt;li&gt;si le mot est &lt;strong&gt;difficile à écrire&lt;/strong&gt; en Forth (ou de manière trop complexe), alors il devrait être en assembleur.&lt;/li&gt;
&lt;li&gt;si le mot est &lt;strong&gt;très souvent utilisé&lt;/strong&gt;, il devrait être en assembleur.&lt;/li&gt;
&lt;li&gt;si le code assembleur est &lt;strong&gt;plus compact&lt;/strong&gt; (ou vraiment plus efficace) que le code Forth, il devrait être en assembleur.&lt;/li&gt;
&lt;li&gt;si la &lt;strong&gt;logique&lt;/strong&gt; du mot est &lt;strong&gt;complexe&lt;/strong&gt;, il devrait être en Forth.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avec ces critères, l'auteur arrive à une liste de &lt;strong&gt;70 primitives&lt;/strong&gt; dans son implémentation. Cela donne une idée d'échelle.&lt;/p&gt;
&lt;p&gt;Il décrit enfin une boucle de développement pour l'implémentation d'un Forth. Je suis déjà parti sur la mienne, mais cela est intéressant à regarder.&lt;/p&gt;
&lt;p&gt;L'auteur implémente toute sa base en premier, puis assemble et corrige les erreurs. Puis écrit du code qui affiche un premier caractère une fois l'initialisation complète. Puis il écrit un mot entièrement en Forth et vérifie le fonctionnement de NEXT, DOCOL et ;S/EXIT.&lt;/p&gt;
&lt;p&gt;Enfin, il implémente les branchements et &lt;code&gt;DODOES&lt;/code&gt; globalement en même temps qu'avoir un &lt;strong&gt;interpréteur interactif&lt;/strong&gt; rudimentaire afin de tester ses mots.&lt;/p&gt;
&lt;p&gt;Globalement, c'est similaire à ce que je suis en train de faire. J'ai écrit un octet en mémoire plutôt qu'un caractère à l'écran, car c'était plus simple. Mais l'idée est la même.&lt;/p&gt;
&lt;p&gt;De plus, je teste de manière automatique, et je compte bien continuer. Même si on va voir que ça va se compliquer un peu.&lt;/p&gt;
&lt;h2&gt;Conclusion et prochain épisode&lt;/h2&gt;
&lt;p&gt;J'ai à présent une liste de mots de deux types différents formant un dictionnaire. Ce que je voudrais maintenant est &lt;strong&gt;afficher un message&lt;/strong&gt; à l'écran. J'ai déplacé et changé le message écrit par le squelette de projet pour me donner un modèle, et je veux à présent faire la même chose, mais dans la boucle Forth.&lt;/p&gt;
&lt;p&gt;J'ai commencé quelques essais et des questions se posent sur la &lt;strong&gt;granularité des mots&lt;/strong&gt;. Je vais devoir implémenter le mot &lt;code&gt;EMIT&lt;/code&gt;. Celui-ci aura besoin de conserver une position à l'écran. Pour cela, je vais avoir besoin de &lt;strong&gt;variables&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour transformer ces variables en adresse mémoire, je peux soit tout écrire en assembleur (ce que je fais probablement faire dans un premier temps), mais aussi en profiter pour implémenter quelques mots de traitement &lt;strong&gt;arithmétique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Bref, à la prochaine !&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category></entry><entry><title>Forth sur 6502, épisode 5</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-5.html" rel="alternate"></link><published>2025-12-22T00:00:00+01:00</published><updated>2025-12-22T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-22:/forth-sur-6502-episode-5.html</id><summary type="html">&lt;h2&gt;La boucle, pour de vrai !&lt;/h2&gt;
&lt;p&gt;Jusqu'à présent, la boucle principale du programme en Forth était &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-3.html"&gt;basée sur un hack&lt;/a&gt;. Ce hack consistait à réinitialiser l'&lt;code&gt;IP&lt;/code&gt; (Instruction Pointer) à la fin du traitement. C'est un peu comme si à chaque fois qu'on avait fini le traitement, on &lt;strong&gt;relançait le programme&lt;/strong&gt; depuis le début.&lt;/p&gt;
&lt;p&gt;Il est temps d'implémenter un nouveau mot Forth : &lt;code&gt;BRANCH&lt;/code&gt;. Ce mot, suivi dans le &lt;code&gt;PFA&lt;/code&gt; par un offset, opère un &lt;strong&gt;saut inconditionnel&lt;/strong&gt; en additionnant cet offset à l'&lt;code&gt;IP&lt;/code&gt; courant. En choisissant un offset négatif, l'exécution va revenir en arrière et donc créer une &lt;strong&gt;boucle infinie&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le pseudo code est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    (IP) -&amp;gt; X       lit l&amp;#39;offset pointé par l&amp;#39;Instruction Pointer
                    L&amp;#39;IP ayant été positionné sur l&amp;#39;emplacement après le mot BRANCH
                    par NEXT.
    IP + X -&amp;gt; IP    ajoute l&amp;#39;offset à l&amp;#39;IP
    NEXT            appelle NEXT pour continuer l&amp;#39;exécution
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Du fait du traitement de …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;La boucle, pour de vrai !&lt;/h2&gt;
&lt;p&gt;Jusqu'à présent, la boucle principale du programme en Forth était &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-3.html"&gt;basée sur un hack&lt;/a&gt;. Ce hack consistait à réinitialiser l'&lt;code&gt;IP&lt;/code&gt; (Instruction Pointer) à la fin du traitement. C'est un peu comme si à chaque fois qu'on avait fini le traitement, on &lt;strong&gt;relançait le programme&lt;/strong&gt; depuis le début.&lt;/p&gt;
&lt;p&gt;Il est temps d'implémenter un nouveau mot Forth : &lt;code&gt;BRANCH&lt;/code&gt;. Ce mot, suivi dans le &lt;code&gt;PFA&lt;/code&gt; par un offset, opère un &lt;strong&gt;saut inconditionnel&lt;/strong&gt; en additionnant cet offset à l'&lt;code&gt;IP&lt;/code&gt; courant. En choisissant un offset négatif, l'exécution va revenir en arrière et donc créer une &lt;strong&gt;boucle infinie&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le pseudo code est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    (IP) -&amp;gt; X       lit l&amp;#39;offset pointé par l&amp;#39;Instruction Pointer
                    L&amp;#39;IP ayant été positionné sur l&amp;#39;emplacement après le mot BRANCH
                    par NEXT.
    IP + X -&amp;gt; IP    ajoute l&amp;#39;offset à l&amp;#39;IP
    NEXT            appelle NEXT pour continuer l&amp;#39;exécution
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Du fait du traitement de mots en 16 bits, cela donne un code assez long en 6502. Mais je crois que ce sera le cas pour toute cette aventure. Le 6502 est un processeur &lt;strong&gt;foncièrement 8 bits&lt;/strong&gt;. Encore une fois, modulo ma méconnaissance de ce CPU. Je reviendrai peut-être dessus plus tard en le maîtrisant mieux. Ou on me signalera des optimisations.&lt;/p&gt;
&lt;p&gt;Avec le mot &lt;code&gt;BRANCH&lt;/code&gt; implémenté, la liste de mots de ma &lt;strong&gt;boucle principale&lt;/strong&gt; devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;loop_words&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;main_loop_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branch_cfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;fffc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;little-endian&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;infinite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loop&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Plus besoin de &lt;code&gt;reset_code&lt;/code&gt; dont je retire le label et le pseudo &lt;code&gt;PFA&lt;/code&gt;. Le &lt;strong&gt;hack est enlevé&lt;/strong&gt; et j'ai enfin ma boucle complète en Forth. Puisque &lt;code&gt;loop_words&lt;/code&gt; est maintenant un (pseudo-)mot Forth complet, je lui ajoute un &lt;code&gt;CFA&lt;/code&gt; et le bootstrap change en initialisant le registre &lt;code&gt;W&lt;/code&gt; avec ce &lt;code&gt;CFA&lt;/code&gt; et en appelant &lt;code&gt;DOCOL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;C'est un peu plus élégant je trouve... mais cela fait perdre une place dans la pile de retour, puisque la première valeur de &lt;code&gt;IP&lt;/code&gt; (même pas initialisée) y sera poussée par &lt;code&gt;DOCOL&lt;/code&gt;. À voir lequel du bootstrap par &lt;code&gt;IP&lt;/code&gt; + &lt;code&gt;NEXT&lt;/code&gt; ou par &lt;code&gt;W&lt;/code&gt; + &lt;code&gt;DOCOL&lt;/code&gt; est le plus intéressant.&lt;/p&gt;
&lt;h2&gt;Moving Forth, épisode 4&lt;/h2&gt;
&lt;p&gt;C'est un tout petit article que cette &lt;a href="https://www.bradrodriguez.com/papers/moving1.htm"&gt;quatrième partie de la série Moving Forth&lt;/a&gt;, tout comme ma partie d'implémentation ci-dessus.&lt;/p&gt;
&lt;p&gt;Cette partie pose la question : comment est-ce qu'on &lt;strong&gt;démarre l'implémentation&lt;/strong&gt; d'un Forth ? Cool ! Mais j'ai déjà commencé. En vrai, j'ai déjà lu plusieurs fois cette série d'articles, il n'y a donc pas de surprise et cette partie entre autres m'a guidé dans mes choix initiaux.&lt;/p&gt;
&lt;p&gt;L'article commence par mettre sur la table &lt;strong&gt;deux choix&lt;/strong&gt; d'implémentation : une implémentation en &lt;strong&gt;assembleur&lt;/strong&gt; en direct sur la machine hôte, ou une implémentation par &lt;strong&gt;méta-compilateur&lt;/strong&gt;, c'est-à-dire un autre Forth qui génère le code machine du Forth cible. Pas de surprise si vous avez suivi jusque-là, c'est la version assembleur que j'ai choisie. L'auteur lui, après avoir indiqué que la voie du méta-compilateur est plus complexe, préfère néanmoins celle-ci, plus portable et plus moderne (même pour 1993).&lt;/p&gt;
&lt;p&gt;J'avais l'idée éventuellement d'avoir aussi un méta-compilateur avec lequel des programmes pourraient être écrits en Forth pour la machine cible, ici la Famicom. Mais je ne suis pas certain de l'intérêt. Ma démarche est celle d'offrir à la Famicom un parallèle Forth au Family BASIC, avec un interpréteur interactif sur la machine et son clavier. Pour créer des jeux modernes sur Famicom, il y a déjà des outils je pense plus adaptés.&lt;/p&gt;
&lt;p&gt;Donc : &lt;strong&gt;Forth en assembleur&lt;/strong&gt; ! Tout du moins son &lt;strong&gt;noyau&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Même si un méta-compilateur serait intéressant pour développer les mots au-delà du noyau... mmmhhhh... Bon on verra.&lt;/p&gt;
&lt;p&gt;L'article continue en parlant de &lt;strong&gt;Forth en C&lt;/strong&gt; comme d'une question qui ne peut pas ne pas se poser. Peut-être parce qu'en 1993, le C est le langage sérieux pour le développement système ? C'est un chemin que j'avais pris il y a quelques années quand je m'étais intéressé au Forth. Mais rapidement, j'étais arrivé à la conclusion que ce sont deux langages aux &lt;strong&gt;philosophies&lt;/strong&gt; (et modèles) &lt;strong&gt;très différents&lt;/strong&gt;, et l'implémentation faisait un peu gymnastique de contorsion.&lt;/p&gt;
&lt;p&gt;Au final, pourquoi pas, en implémentant une machine virtuelle Forth en C, avec quelques commandes de base du noyau. Ça fait partie des choses sur lesquelles je voudrais revenir maintenant que je maîtrise mieux le Forth. Vous le sentez venir le rabbit hole ? Allez, sur la pile !&lt;/p&gt;
&lt;h2&gt;Prochain épisode&lt;/h2&gt;
&lt;p&gt;Un article très court donc. Le suivant sera plus intéressant pour la suite de l'implémentation car il traitera de ce qui forme un &lt;strong&gt;noyau Forth&lt;/strong&gt; : les mots de base, les primitives, sur lequel le reste est construit.&lt;/p&gt;
&lt;p&gt;Et je pense qu'il sera temps de faire un détour vers le passage à des &lt;strong&gt;mots Forth complets&lt;/strong&gt;, avec leur entête et leur chaînage.&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category></entry><entry><title>Forth sur 6502, épisode 4</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-4.html" rel="alternate"></link><published>2025-12-21T00:00:00+01:00</published><updated>2025-12-21T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-21:/forth-sur-6502-episode-4.html</id><summary type="html">&lt;h2&gt;NEXT&lt;/h2&gt;
&lt;p&gt;Nous y voilà ! Après avoir mis en place un &lt;strong&gt;framework de tests&lt;/strong&gt; dans l'&lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-3.html"&gt;article précédent&lt;/a&gt;, il est temps d'implémenter le mot &lt;code&gt;NEXT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Un petit rappel du premier article de &lt;a href="https://www.bradrodriguez.com/papers/moving1.htm"&gt;Moving Forth&lt;/a&gt; : &lt;code&gt;NEXT&lt;/code&gt; est le mot qui permet de &lt;strong&gt;faire avancer l'exécution&lt;/strong&gt; d'une séquence de pointeurs vers des mots Forth. Son pseudo-code (en modèle &lt;em&gt;Indirect Threaded Code&lt;/em&gt;) est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;récupère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mémoire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pointée&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;W&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maintenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;avance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;compteur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;programme&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;récupère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mémoire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pointée&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maintenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;JP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;saute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;à&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;présente&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Implémentation&lt;/h3&gt;
&lt;p&gt;En 6502, le code est un peu long, car &lt;strong&gt;l'adressage indirect&lt;/strong&gt; nécessite de passer par des registres en page zéro. Et les manipuler demande plusieurs instructions. Je …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;NEXT&lt;/h2&gt;
&lt;p&gt;Nous y voilà ! Après avoir mis en place un &lt;strong&gt;framework de tests&lt;/strong&gt; dans l'&lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-3.html"&gt;article précédent&lt;/a&gt;, il est temps d'implémenter le mot &lt;code&gt;NEXT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Un petit rappel du premier article de &lt;a href="https://www.bradrodriguez.com/papers/moving1.htm"&gt;Moving Forth&lt;/a&gt; : &lt;code&gt;NEXT&lt;/code&gt; est le mot qui permet de &lt;strong&gt;faire avancer l'exécution&lt;/strong&gt; d'une séquence de pointeurs vers des mots Forth. Son pseudo-code (en modèle &lt;em&gt;Indirect Threaded Code&lt;/em&gt;) est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;récupère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mémoire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pointée&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;W&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maintenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;avance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;compteur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;programme&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;récupère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mémoire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pointée&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maintenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;JP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;saute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;à&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;présente&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Implémentation&lt;/h3&gt;
&lt;p&gt;En 6502, le code est un peu long, car &lt;strong&gt;l'adressage indirect&lt;/strong&gt; nécessite de passer par des registres en page zéro. Et les manipuler demande plusieurs instructions. Je ne suis pas très versé en 6502, on verra s'il y a moyen de faire mieux plus tard.&lt;/p&gt;
&lt;p&gt;Dans certains Forth, &lt;code&gt;NEXT&lt;/code&gt; est tellement court qu'il se pose la question d'en faire une macro. Ici, la réponse est assez simple : c'est non. Le code est assez long, et donc &lt;code&gt;NEXT&lt;/code&gt; sera appelé avec un &lt;code&gt;JMP&lt;/code&gt; à son adresse.&lt;/p&gt;
&lt;p&gt;Très bien, j'ai donc &lt;code&gt;NEXT&lt;/code&gt;. Il me faut aussi une &lt;strong&gt;liste de mots&lt;/strong&gt; à appeler. Le but étant d'implémenter l'écriture d'une valeur en mémoire, je vais créer un pseudo-mot &lt;code&gt;TEST-WORD&lt;/code&gt;. Puis comme il faut faire cela en boucle, un second mot qui réinitialisera l'&lt;code&gt;IP&lt;/code&gt; (Instruction Pointer) au début de la séquence, que je vais appeler &lt;code&gt;RESET-CODE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Cela donne quelque chose comme ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;loop_words:
    .word test_word_cfa
    .word reset_code_cfa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les pointeurs sont vers les &lt;code&gt;CFA&lt;/code&gt; (Code Field Address) des mots. Pour rappel, le &lt;code&gt;CFA&lt;/code&gt; est l'adresse où se trouve le code machine qui sera en charge d'exécuter le mot suivant (oui, c'est bien du &lt;em&gt;Indirect Threaded Code&lt;/em&gt;, c'est indirect).&lt;/p&gt;
&lt;p&gt;Par exemple, pour &lt;code&gt;TEST-WORD&lt;/code&gt;, le &lt;code&gt;CFA&lt;/code&gt; est l'adresse de la première instruction assembleur qui compose le mot :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;test_word_cfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;test_word_pfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;test_word_pfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;#$42&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;$7FF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;NEXT&lt;/code&gt; va lire le &lt;code&gt;CFA&lt;/code&gt;, puis &lt;strong&gt;sauter à l'adresse&lt;/strong&gt; indiquée, qui est &lt;code&gt;test_word_pfa&lt;/code&gt;. Et donc exécuter le code qui place la valeur &lt;code&gt;$42&lt;/code&gt; à l'adresse &lt;code&gt;$07FF&lt;/code&gt;, avant de redonner la main à &lt;code&gt;NEXT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;J'ai dit plus haut que c'était un &lt;em&gt;pseudo-mot&lt;/em&gt;. En effet, le &lt;code&gt;CFA&lt;/code&gt; et le &lt;code&gt;PFA&lt;/code&gt; ne sont qu'une partie de &lt;strong&gt;la définition d'un mot complet&lt;/strong&gt; en Forth. Mais comme cette partie n'a pas été abordée pour le moment, et qu'elle n'est pas nécessaire pour faire fonctionner &lt;code&gt;NEXT&lt;/code&gt;, je laisse ceci de côté.&lt;/p&gt;
&lt;p&gt;Reste à &lt;strong&gt;bootstrapper&lt;/strong&gt; l'&lt;code&gt;IP&lt;/code&gt; pour qu'il pointe sur &lt;code&gt;loop_words&lt;/code&gt; au démarrage du programme. J'ajoute donc un petit code d'initialisation qui... sera aussi le code du mot &lt;code&gt;RESET-CODE&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;boot_forth&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Instruction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;temporary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Forth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;reset_code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;loop_words&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;REG_IP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;lda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;loop_words&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;REG_IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Jump&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Forth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loop&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Plus tard, il faudra aussi initialiser d'autres registres dans ce code. Mais pour le moment, ça suffit.&lt;/p&gt;
&lt;p&gt;J'enlève l'ancien code d'écriture en mémoire de la boucle principale, je remplace par un appel à &lt;code&gt;boot_forth&lt;/code&gt;, et voilà ! &lt;strong&gt;Les tests passent&lt;/strong&gt;... Mais le code d'affichage n'affiche plus le &lt;code&gt;HELLO FAMICOM&lt;/code&gt; du squelette. C'est normal puisque la boucle principale Forth n'appelle pas le code de synchro et d'affichage.&lt;/p&gt;
&lt;h3&gt;La boucle complète&lt;/h3&gt;
&lt;p&gt;J'ai tous les éléments pour remettre en place la boucle principale. Il suffit de créer deux mots (ou plutôt pseudo-mots) qui feront juste un appel aux deux routines présentes initialement dans la boucle principale.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;read_joy_safe_word_cfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_joy_safe_word_pfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;read_joy_safe_word_pfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jsr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_joy_safe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nv"&gt;post_logic_word_cfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;.&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;post_logic_word_pfa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;post_logic_word_pfa&lt;/span&gt;:&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jsr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;post_logic&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et de modifier la liste des mots à appeler dans &lt;code&gt;loop_words&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;loop_words:
    .word read_joy_safe_word_cfa
    .word test_word_cfa
    .word post_logic_word_cfa
    .word reset_code_cfa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et l'affichage remarche. Avec &lt;strong&gt;beaucoup plus d'indirections&lt;/strong&gt; et donc plus lent, c'est vrai. Je verrai plus tard comment regrouper les appels. Ou comment modifier les sous-routines pour les implémenter directement comme des mots.&lt;/p&gt;
&lt;p&gt;En tout cas pour le moment, j'ai retrouvé &lt;strong&gt;le comportement initial&lt;/strong&gt;. Parfait.&lt;/p&gt;
&lt;h2&gt;DOCOL et ;S&lt;/h2&gt;
&lt;p&gt;Dans &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-2.html"&gt;la partie 2 de cette série&lt;/a&gt;, j'avais listé les mots &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt; comme &lt;strong&gt;prioritaires à implémenter&lt;/strong&gt;. En effet, ces mots permettent d'appeler des mots définis par d'autres mots. C'est exactement ce qui est fait avec &lt;code&gt;loop_words&lt;/code&gt;. Sauf que cela n'est pas un vrai mot. Il n'a même pas de &lt;code&gt;CFA&lt;/code&gt;. Cette liste est démarrée manuellement par le code d'initialisation, que je rappelle en boucle.&lt;/p&gt;
&lt;p&gt;Mais cette boucle est aussi un &lt;strong&gt;petit hack&lt;/strong&gt; avec le &lt;code&gt;RESET-CODE&lt;/code&gt;. Je ne peux pas l'utiliser proprement pour démontrer &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt;. Je vais donc créer un autre pseudo-mot&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;main_loop_cfa:
    .word docol
main_loop_pfa:
    .word read_joy_safe_word_cfa
    .word test_word_cfa
    .word post_logic_word_cfa
    .word do_semi_cfa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;docol&lt;/code&gt; étant le code machine de &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;do_semi_cfa&lt;/code&gt; le pointeur sur le &lt;code&gt;CFA&lt;/code&gt; de &lt;code&gt;;S&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La boucle « hack » se retrouve donc remplacée par :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;loop_words:
    .word main_loop_cfa
    .word reset_code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Pseudo-code pour les deux mots&lt;/h3&gt;
&lt;p&gt;Le pseudo-code de &lt;code&gt;DOCOL&lt;/code&gt; est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;PUSH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;pousse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;retour&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puisque&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pointait&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;adresse du Parameter Field.&lt;/span&gt;
&lt;span class="s"&gt;                Le Parameter Field contient la liste des&lt;/span&gt;
&lt;span class="s"&gt;                adresses des mots à exécuter. IP pointe&lt;/span&gt;
&lt;span class="s"&gt;                donc sur cette liste.&lt;/span&gt;
&lt;span class="s"&gt;   JUMP NEXT    saute à NEXT pour continuer l&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le pseudo-code de &lt;code&gt;;S&lt;/code&gt; est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;POP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IP&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;r&lt;/span&gt;é&lt;span class="nv"&gt;cup&lt;/span&gt;è&lt;span class="nv"&gt;re&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;adresse de retour depuis&lt;/span&gt;
&lt;span class="err"&gt;                la pile de retour et la place dans IP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;JUMP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;saute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;à&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;continuer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Et ça fonctionne&lt;/h3&gt;
&lt;p&gt;À nouveau, les tests passent et l'affichage fonctionne. Les trois premiers mots Forth sont donc implémentés : &lt;code&gt;NEXT&lt;/code&gt;, &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Moving Forth, article 3&lt;/h2&gt;
&lt;p&gt;Jetons à présent un œil sur le &lt;a href="https://www.bradrodriguez.com/papers/moving3.htm"&gt;troisième article&lt;/a&gt; de la série Moving Forth. Son titre est « Demystifying DOES&amp;gt; », mais il en profite surtout pour &lt;strong&gt;décortiquer le fonctionnement&lt;/strong&gt; des &lt;code&gt;CFA&lt;/code&gt; et &lt;code&gt;PFA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On passe sur l'introduction, qui revient sur des erreurs dans les parties précédentes pour arriver à l'explication du &lt;strong&gt;Code Field&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le Code Field, c'est &lt;strong&gt;le cœur du fonctionnement&lt;/strong&gt; d'un mot en Forth. C'est un indicateur de la &lt;strong&gt;nature du mot&lt;/strong&gt;, de la façon dont il va se comporter, être exécuté. Le Code Field indique quoi faire avec les paramètres du mot, les paramètres étant situés dans le Parameter Field, qui suit le Code Field.&lt;/p&gt;
&lt;p&gt;Ainsi, on peut définir &lt;strong&gt;différents fonctionnements&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un mot qui exécute les paramètres comme du code machine,&lt;/li&gt;
&lt;li&gt;un mot qui traite les paramètres comme des référence à d'autres mots,&lt;/li&gt;
&lt;li&gt;un mot qui traite les paramètres comme un emplacement mémoire réservé pour une variable,&lt;/li&gt;
&lt;li&gt;etc...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En quelque sorte, le Code Field représente &lt;strong&gt;une routine&lt;/strong&gt; avec un paramètre implicite : le Parameter Field.&lt;/p&gt;
&lt;p&gt;L'article fait un parallèle avec la programmation objet, où le Code Field serait la méthode unique d'une classe, et le Parameter Field l'instance de cette classe pour chaque mot utilisant ce Code Field. Je ne suis pas certain que ce parallèle aide beaucoup... mais pourquoi pas.&lt;/p&gt;
&lt;h3&gt;Code Field et Indirect Threaded Code&lt;/h3&gt;
&lt;p&gt;Dans le modèle &lt;code&gt;ITC&lt;/code&gt; (Indirect Threaded Code), le &lt;strong&gt;Code Field&lt;/strong&gt; est une adresse qui pointe vers un code machine chargé d'interpréter le contenu du Parameter Field. On a vu deux cas pour le moment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un Code Field qui pointe vers &lt;code&gt;DOCOL&lt;/code&gt; entraîne l'appel successif de tous les mots dont les listés dans le &lt;code&gt;PFA&lt;/code&gt;. Ces mots sont eux-mêmes représentés par leur &lt;code&gt;CFA&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;un Code Field qui pointe vers directement sur l'adresse du Parameter Field. Dans ce cas, le code machine est directement dans le &lt;code&gt;PFA&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il existe différents Code Field standards en Forth, mais rien n'empêche l'utilisateur d'en &lt;strong&gt;définir de nouveaux&lt;/strong&gt;. Et c'est exactement ce que fait le mot &lt;code&gt;DOES&amp;gt;&lt;/code&gt; mentionné par le titre. Cependant, son fonctionnement nécessitera probablement un article à lui seul. Retenez juste que &lt;code&gt;DOES&amp;gt;&lt;/code&gt; permet de définir une nouvelle classe de mots partageant un même Code Field personnalisé.&lt;/p&gt;
&lt;p&gt;L'article mentionne aussi les mots &lt;code&gt;CREATE&lt;/code&gt; ou encore &lt;code&gt;;CODE&lt;/code&gt;, qui respectivement permettent de définir un nouveau mot et de définir un mot dont le code est écrit en assembleur. Là encore, ce sont des sujets pour plus tard lorsqu'il sera question de définir des mots par programmation.&lt;/p&gt;
&lt;p&gt;Pour le moment, je n'ai toujours que des pseudo-mots, et ils sont tous définis directement dans le code assembleur.&lt;/p&gt;
&lt;p&gt;L'article est plus long car il aborde ces sujets dans les différents modèles d'exécution de Forth, ainsi que les mots &lt;code&gt;CONSTANT&lt;/code&gt; et &lt;code&gt;VARIABLE&lt;/code&gt;, qui sont des mots de constructions avec un Code Field particulier, que nous verrons plus tard.&lt;/p&gt;
&lt;h2&gt;La suite&lt;/h2&gt;
&lt;p&gt;J'ai à présent les premiers pseudo-mots pour mon Forth, mais il m'en manque un pour créer la boucle en entier. En effet, pour le moment je réinitialise l'interpréteur pour relancer la boucle. Ce n'est pas une vraie boucle Forth. Je pense que ma prochaine étape sera donc de créer le mot &lt;code&gt;BRANCH&lt;/code&gt;, qui modifie le registre &lt;code&gt;IP&lt;/code&gt;.&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category></entry><entry><title>Forth sur 6502, épisode 3</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-3.html" rel="alternate"></link><published>2025-12-20T00:00:00+01:00</published><updated>2025-12-20T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-20:/forth-sur-6502-episode-3.html</id><summary type="html">&lt;h2&gt;Des tests&lt;/h2&gt;
&lt;p&gt;Depuis le &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-2.html"&gt;dernier article&lt;/a&gt;, je me suis surtout concentré sur la mise en place d'un &lt;strong&gt;framework de tests&lt;/strong&gt;, ainsi que sur une réflexion de « comment commencer » ?&lt;/p&gt;
&lt;p&gt;La lecture de l'&lt;a href="https://www.bradrodriguez.com/papers/moving2.htm"&gt;article 2 de Moving Forth&lt;/a&gt; m'a donné une liste de mots à implémenter en priorité : &lt;code&gt;NEXT&lt;/code&gt;, &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt;. Cela afin d’arriver rapidement sur une boucle écrite en Forth. J'y reviendrai plus loin dans l'article.&lt;/p&gt;
&lt;p&gt;Côté tests, ça a été une aventure en plusieurs étapes. Dans l'idée d'augmenter le nombre de tests, je voulais m'appuyer sur un framework de tests LUA tout fait. J'en ai trouvé un, &lt;strong&gt;&lt;a href="https://github.com/bluebird75/luaunit/"&gt;luaunit&lt;/a&gt;&lt;/strong&gt; qui m'a semblé tout à fait répondre à mes attentes. Pour l'utiliser, je dois utiliser un &lt;code&gt;require("luaunit")&lt;/code&gt; dans mon script de tests. Et là ont &lt;strong&gt;commencé les ennuis&lt;/strong&gt;. Tout d'abord, &lt;code&gt;require()&lt;/code&gt; n'est pas permis par défaut dans Mesen2, il faut aller permettre les fonction &lt;code&gt;E/S&lt;/code&gt; dans les …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Des tests&lt;/h2&gt;
&lt;p&gt;Depuis le &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-2.html"&gt;dernier article&lt;/a&gt;, je me suis surtout concentré sur la mise en place d'un &lt;strong&gt;framework de tests&lt;/strong&gt;, ainsi que sur une réflexion de « comment commencer » ?&lt;/p&gt;
&lt;p&gt;La lecture de l'&lt;a href="https://www.bradrodriguez.com/papers/moving2.htm"&gt;article 2 de Moving Forth&lt;/a&gt; m'a donné une liste de mots à implémenter en priorité : &lt;code&gt;NEXT&lt;/code&gt;, &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt;. Cela afin d’arriver rapidement sur une boucle écrite en Forth. J'y reviendrai plus loin dans l'article.&lt;/p&gt;
&lt;p&gt;Côté tests, ça a été une aventure en plusieurs étapes. Dans l'idée d'augmenter le nombre de tests, je voulais m'appuyer sur un framework de tests LUA tout fait. J'en ai trouvé un, &lt;strong&gt;&lt;a href="https://github.com/bluebird75/luaunit/"&gt;luaunit&lt;/a&gt;&lt;/strong&gt; qui m'a semblé tout à fait répondre à mes attentes. Pour l'utiliser, je dois utiliser un &lt;code&gt;require("luaunit")&lt;/code&gt; dans mon script de tests. Et là ont &lt;strong&gt;commencé les ennuis&lt;/strong&gt;. Tout d'abord, &lt;code&gt;require()&lt;/code&gt; n'est pas permis par défaut dans Mesen2, il faut aller permettre les fonction &lt;code&gt;E/S&lt;/code&gt; dans les paramètres.&lt;/p&gt;
&lt;p&gt;Malgré cela, le script ne semble pas être trouvé, alors qu'il est bien dans un répertoire de recherche (vérifié avec le contenu de la variable &lt;code&gt;package.path&lt;/code&gt;). En tout cas pas en mode &lt;code&gt;--testrunner&lt;/code&gt;, car en debug depuis l'interface graphique, ça fonctionne ! Après étude des sources de Mesen2, je vois le soucis (qui était bien affiché dans mes logs, mais assez subtil pour que je passe à côté) : le mode testrunner et le mode UI &lt;strong&gt;résolvent différemment&lt;/strong&gt; le chemin des scripts, à un séparateur de chemin près.&lt;/p&gt;
&lt;p&gt;La correction est simple, je la fais et je suis prêt à faire un &lt;em&gt;merge request&lt;/em&gt;... pour m'apercevoir que le &lt;strong&gt;dépôt est fermé&lt;/strong&gt; aux contributions. Après enquête, il semblerait que le développeur a disparu de la circulation en juillet 2025. Puisque le dépôt est fermé, j'imagine que c'est un retrait volontaire et non un événement malheureux. Je l'espère. On me dit qu'il aurait déjà fait ça dans le passé lorsqu'il avait eu besoin de se concentrer.&lt;/p&gt;
&lt;p&gt;En attendant, j'ai donc créé ma version de Mesen2 avec cette correction (et une autre trouvée dans un autre fork qui me semblait intéressante). &lt;strong&gt;Merci l'open source&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Vient ensuite mon deuxième soucis : &lt;code&gt;luaunit&lt;/code&gt; &lt;strong&gt;ne va pas convenir&lt;/strong&gt;. Comme tous (?) les frameworks de tests, le framework gère des contextes cloisonnés, s'occupe de lancer les tests, de capturer les erreurs, etc. Bref, il a les commandes. Sauf que Mesen2 requiert que certaines fonctions de contrôle de l'émulateur soient appelées depuis des callbacks. Autrement dit, Mesen2 veut aussi avoir le contrôle.&lt;/p&gt;
&lt;p&gt;Après avoir retourné le problème quelques temps, je me suis dit que finalement, j'allais faire un petit &lt;strong&gt;framework sur mesure&lt;/strong&gt; adapté à Mesen2. Il aura certainement moins de fonctionnalités qu'une solution complète, mais tant pis. J'ai donc écrit un framework basé sur une machine à états qui fait avancer les tests au fur et à mesure que l'émulateur lance des callbacks. Ça fonctionne, mais c'est un peu verbeux à l'écriture pour le moment. J'espère pouvoir dégager quelques fonctions utilitaires pour simplifier l'écriture des tests par la suite, si besoin.&lt;/p&gt;
&lt;p&gt;Ah, et j'englobe l'appel des tests dans un &lt;strong&gt;&lt;code&gt;xpcall()&lt;/code&gt;&lt;/strong&gt;, une fonction bien pratique en LUA qui permet de capturer les erreurs, et donc d'arrêter l'émulateur proprement en cas de problème avec affichage du message d'erreur.&lt;/p&gt;
&lt;h3&gt;Mes trois tests&lt;/h3&gt;
&lt;p&gt;Pour le moment, j'ai &lt;strong&gt;trois tests&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le premier test vérifie que les &lt;strong&gt;symboles&lt;/strong&gt; des registres Forth sont bien présents dans les symboles. Il y a peu de chance que ça ne passe pas, mais c'est ce qu'on se dit avant que ça ne passe pas...&lt;/li&gt;
&lt;li&gt;Le deuxième test vérifie que le programme arrive jusqu'à la boucle principale. Un &lt;strong&gt;smoke test&lt;/strong&gt; de base.&lt;/li&gt;
&lt;li&gt;Le troisième test vérifie qu'une &lt;strong&gt;adresse mémoire&lt;/strong&gt; particulière est modifiée. C'est actuellement l'action qui est faite dans la boucle principale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En fait, il y a pas mal d'autres choses qui sont faites dans la boucle principale par le squelette de projet que j'utilise. Je verrai si j'ai besoin à un moment de tester cette partie, mais pour le moment, dans une &lt;strong&gt;logique TDD&lt;/strong&gt;, tant que je n'y touche pas, je ne teste pas.&lt;/p&gt;
&lt;h2&gt;La suite&lt;/h2&gt;
&lt;p&gt;Pas de lecture de la partie 3 de Moving Forth pour le moment. En effet, celle-ci se concentre sur le &lt;strong&gt;&lt;code&gt;CFA&lt;/code&gt;&lt;/strong&gt; (Code Field) et le &lt;code&gt;PFA&lt;/code&gt; (Parameter Field), puis enchaîne sur les mots de construction. Je n'en suis pas encore là. Je reprendrai les résumés lorsque j'aurai une boucle Forth fonctionnelle.&lt;/p&gt;
&lt;p&gt;Car c'est la prochaine étape : pour le moment, le code contient une &lt;strong&gt;boucle assembleur&lt;/strong&gt; qui :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lit les entrées des pads&lt;/li&gt;
&lt;li&gt;écrit une valeur à une adresse mémoire fixe (pour le test)&lt;/li&gt;
&lt;li&gt;attend la synchronisation verticale&lt;/li&gt;
&lt;li&gt;exécute une file d'instruction PPU (pour l'affichage)&lt;/li&gt;
&lt;li&gt;boucle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ma prochaine étape est de remplacer cette boucle par la même chose en Forth. Pour cela, je dois implémenter au moins le mot &lt;code&gt;NEXT&lt;/code&gt; qui appellera ce même code suivant le schéma Forth. Autrement dit, ces routines devront se terminer par un appel à &lt;code&gt;NEXT&lt;/code&gt; pour continuer l'exécution, plutôt que de se terminer par un &lt;code&gt;RTS&lt;/code&gt; (return from subroutine).&lt;/p&gt;
&lt;h2&gt;Point d'étape&lt;/h2&gt;
&lt;p&gt;J'ai donc à présent un &lt;strong&gt;environnement&lt;/strong&gt; d'assemblage et de tests, une &lt;strong&gt;boucle minimale&lt;/strong&gt;. Le prochain article sera écrit lorsque j'aurai a minima un &lt;code&gt;NEXT&lt;/code&gt; fonctionnel.&lt;/p&gt;
&lt;p&gt;Et pour terminer, voici la sortie des tests actuels :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mesen --testrunner out/nes_template.nes start_tests.lua
-- STARTING TESTS --
[1/3] Running: Forth symbols exist
  ✓ PASSED
[2/3] Running: Program boots and reaches main loop
  ✓ PASSED
[3/3] Running: Verify memory change at specific address
  ✓ PASSED
============================================================
TEST REPORT
============================================================
Total: 3 | Passed: 3 | Failed: 0
============================================================
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category></entry><entry><title>Forth sur 6502, épisode 2</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-2.html" rel="alternate"></link><published>2025-12-12T00:00:00+01:00</published><updated>2025-12-12T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-12:/forth-sur-6502-episode-2.html</id><summary type="html">&lt;h2&gt;Le projet minimal&lt;/h2&gt;
&lt;p&gt;Avant de passer à la lecture de l'&lt;a href="https://www.bradrodriguez.com/papers/moving2.htm"&gt;article 2 de la série Moving Forth&lt;/a&gt;, je veux mettre en place un &lt;strong&gt;projet « minimal »&lt;/strong&gt;. Plus exactement, c'est initialement ce que je voulais faire, avec un petit code source pour Famicom qui affiche un texte, un Makefile et bien entendu, un framework de tests.&lt;/p&gt;
&lt;p&gt;Mais les notes que j'avais prises sur la Famicom remontaient à un petit moment, et il y a quelques trucs à initialiser avant d'afficher un caractère à l'écran. J'ai donc cherché un squelette de projet déjà fait. Sur une machine populaire, ça doit bien
exister.&lt;/p&gt;
&lt;p&gt;Mon choix s'est porté sur &lt;strong&gt;&lt;a href="https://github.com/Mikejmoffitt/nes-template/"&gt;Nes Template&lt;/a&gt;&lt;/strong&gt; de Mike Moffitt. Le squelette n'est
pas minimaliste, mais a une bonne base, avec un système de configuration flexible pour la ROM destination, et assez de quoi
écrire un message à l'écran, ainsi que manipuler des banques de mémoire. C'est bien écrit, bien …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Le projet minimal&lt;/h2&gt;
&lt;p&gt;Avant de passer à la lecture de l'&lt;a href="https://www.bradrodriguez.com/papers/moving2.htm"&gt;article 2 de la série Moving Forth&lt;/a&gt;, je veux mettre en place un &lt;strong&gt;projet « minimal »&lt;/strong&gt;. Plus exactement, c'est initialement ce que je voulais faire, avec un petit code source pour Famicom qui affiche un texte, un Makefile et bien entendu, un framework de tests.&lt;/p&gt;
&lt;p&gt;Mais les notes que j'avais prises sur la Famicom remontaient à un petit moment, et il y a quelques trucs à initialiser avant d'afficher un caractère à l'écran. J'ai donc cherché un squelette de projet déjà fait. Sur une machine populaire, ça doit bien
exister.&lt;/p&gt;
&lt;p&gt;Mon choix s'est porté sur &lt;strong&gt;&lt;a href="https://github.com/Mikejmoffitt/nes-template/"&gt;Nes Template&lt;/a&gt;&lt;/strong&gt; de Mike Moffitt. Le squelette n'est
pas minimaliste, mais a une bonne base, avec un système de configuration flexible pour la ROM destination, et assez de quoi
écrire un message à l'écran, ainsi que manipuler des banques de mémoire. C'est bien écrit, bien commenté. Ça me convient bien.&lt;/p&gt;
&lt;p&gt;J'y ai ajouté un script Lua pour &lt;strong&gt;automatiser des tests&lt;/strong&gt; en utilisant l'émulateur &lt;a href="https://github.com/SourMesen/Mesen2"&gt;Mesen2&lt;/a&gt;. Le script place une callback à une adresse mémoire spécifique et s'y arrête lorsque cette adresse est atteinte par le registre PC.&lt;/p&gt;
&lt;p&gt;Et voilà ce que cela donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mesen --testrunner out/nes_template.nes tests/tests.lua
-- STARTING TESTS --
Setting callback at address: 0xC0D2
Memory position reached: 0xC0D2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Le mapping mémoire&lt;/h3&gt;
&lt;p&gt;À la fin de &lt;a href="https://www.triceraprog.fr/forth-sur-6502-episode-1.html"&gt;l'article précédent&lt;/a&gt;, j'avais évoqué le mapping mémoire afin de vérifier les contraintes de la Famicom.&lt;/p&gt;
&lt;p&gt;Voici un &lt;strong&gt;mapping rapide&lt;/strong&gt; (que l'ont peut retrouver plus en détail sur &lt;a href="https://www.nesdev.org/wiki/CPU_memory_map"&gt;Nesdev&lt;/a&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$0000-$00FF : Page zéro     (256 octets)
$0100-$01FF : Pile          (256 octets)
$0200-$07FF : RAM interne   (1536 octets)

$2000-$2007 : Registres PPU (le processeur graphique)
$4000-$4017 : Registres APU (le processeur audio) et E/S

$6000-$7FFF : RAM sur cartouche     (si présente)
$8000-$FFFF : PRG ROM sur cartouche (si présente)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les deux dernières zones sont dépendantes de la cartouche et du « mapper » utilisé. Dans la configuration par défaut du projet template que j'utilise, il n'y a pas de RAM configurée sur la cartouche. Il y a par contre &lt;strong&gt;16 banques&lt;/strong&gt; de 16 Ko de PRG ROM (de la ROM accessible par le CPU), mappée de &lt;code&gt;$8000&lt;/code&gt; à &lt;code&gt;$FFFF&lt;/code&gt;. Une banque de 16 Ko est fixe (la dernière, de &lt;code&gt;$C000&lt;/code&gt; à &lt;code&gt;$FFFF&lt;/code&gt;) et l'une des autres banques peut être mappée de &lt;code&gt;$8000&lt;/code&gt; à &lt;code&gt;$BFFF&lt;/code&gt;. Certaines de ces banques sont utilisées pour stocker les ressources graphiques, qui sont ensuite envoyées à de la &lt;strong&gt;mémoire vidéo&lt;/strong&gt; présente sur la cartouche.&lt;/p&gt;
&lt;p&gt;Il faudra très certainement ajouter de la RAM sur cartouche pour faire quelque chose d'intéressant avec Forth. Je verrai à la fin du développement quel mémoire serait nécessaire pour une production sur cartouche. De toute façon, pendant le développement, j'utiliserai un &lt;strong&gt;émulateur&lt;/strong&gt; la plupart du temps et une &lt;strong&gt;cartouche de développement&lt;/strong&gt; pour vérifier sur vrai matériel.&lt;/p&gt;
&lt;p&gt;Le projet template permet de réserver assez facilement des pointeurs dans la &lt;strong&gt;page zéro&lt;/strong&gt;. Il définit d'ailleurs déjà un certain nombre de variables temporaires. Je vais tout simplement utiliser ce système pour déclarer les registres Forth.&lt;/p&gt;
&lt;p&gt;Pour la &lt;strong&gt;pile des paramètres&lt;/strong&gt;, je vais m'inspirer de ce que le template utilise pour sa queue de commandes graphiques : réservation d'un espace mémoire non initialisé dans la RAM interne et définition d'un pointeur associé dans la page zéro.&lt;/p&gt;
&lt;h2&gt;Moving Forth, article 2&lt;/h2&gt;
&lt;p&gt;Dans le &lt;a href="https://www.bradrodriguez.com/papers/moving2.htm"&gt;deuxième article&lt;/a&gt; de la série Moving Forth, l'auteur commence par lister les mots essentiels au Forth. Les mots sur lesquels le reste repose, et qui nécessitent d'être efficace.&lt;/p&gt;
&lt;h3&gt;Les mots&lt;/h3&gt;
&lt;p&gt;En premier, il y a les mots qui forment l'interpréteur lui-même :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NEXT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DOCOL&lt;/code&gt; (aussi appelé ENTER dans l'article)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;;S&lt;/code&gt; (aussi appelé EXIT dans l'article)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;NEXT&lt;/code&gt; est le cœur de l'interpréteur, le mot qui fait avancer toute la machinerie. Il récupère l'adresse du mot à exécuter depuis l'instruction pointer (&lt;code&gt;IP&lt;/code&gt;), puis incrémente l'&lt;code&gt;IP&lt;/code&gt; pour le mot suivant. Ensuite, il récupère l'adresse de la routine associée au mot (dans le cas de l'Indirect Threaded Code, choisi ici, c'est une adresse mémoire qui pointe vers l'adresse de la routine) et saute à cette adresse pour exécuter le mot. Il vaut mieux lire cette ligne lentement...&lt;/p&gt;
&lt;p&gt;C'est évidemment le premier mot à implémenter. Et il est d'ailleurs possible de faire tourner un petit programme avec seulement ce mot. &lt;code&gt;NEXT&lt;/code&gt; ne fait qu'appeler une liste de routines. Et ces routines appellent à leur tour &lt;code&gt;NEXT&lt;/code&gt; pour continuer l'exécution.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DOCOL&lt;/code&gt; est le mot qui gère l'appel d'un mot défini par d'autres mots. Il sauvegarde l'&lt;code&gt;IP&lt;/code&gt; actuel sur la pile de retour, puis positionne l'&lt;code&gt;IP&lt;/code&gt; à l'adresse du code du mot appelé. Ensuite, il saute à &lt;code&gt;NEXT&lt;/code&gt; pour continuer l'exécution.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;;S&lt;/code&gt; est le mot qui gère le retour d'un mot défini par d'autres mots. Il récupère l'adresse de retour depuis la pile de retour et la place dans l'&lt;code&gt;IP&lt;/code&gt;, puis saute à &lt;code&gt;NEXT&lt;/code&gt; pour continuer l'exécution.&lt;/p&gt;
&lt;p&gt;Ensuite, l'article liste les deux mots de constructions que sont &lt;code&gt;DOVAR&lt;/code&gt; et &lt;code&gt;DOCON&lt;/code&gt;, respectivement pour définir des variables et des constantes. Ainsi que &lt;code&gt;LIT&lt;/code&gt;, pour charger une valeur littérale sur la pile de paramètres.&lt;/p&gt;
&lt;p&gt;Il liste aussi &lt;code&gt;DODOES&lt;/code&gt; que je laisserai de côté dans un premier temps. C'est un mot un peu plus complexe qui permet l'extension des mots définis par &lt;code&gt;BUILD&lt;/code&gt;/&lt;code&gt;DOES&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Et bien entendu, les mots standards :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@&lt;/code&gt; (fetch)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt; (store)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt; (addition)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SWAP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OVER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ROT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0=&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+!&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Les études de cas&lt;/h3&gt;
&lt;p&gt;L'article aborde ensuite plusieurs études de cas avec différents processeurs. Il ne cite pas le 6502, je ne m'y attarde donc pas.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;L'étape suivante sera l'&lt;strong&gt;implémentation&lt;/strong&gt; de au moins &lt;code&gt;NEXT&lt;/code&gt;, &lt;code&gt;DOCOL&lt;/code&gt; et &lt;code&gt;;S&lt;/code&gt;, afin de pouvoir exécuter un petit programme composé de routines en assembleur. Comme je compte tester le programme, il me faudra aussi un framework de test un peu plus sérieux que le petit script Lua que j'ai écrit pour l'instant.&lt;/p&gt;
&lt;p&gt;En attendant, j'ai placé les &lt;strong&gt;registres Forth&lt;/strong&gt; dans la page zéro et réservé un espace mémoire pour la pile des paramètres. Le test donne à présent :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mesen --testrunner out/nes_template.nes tests/tests.lua
-- STARTING TESTS --
Found symbol REG_W at 0x0010
Found symbol REG_IP at 0x0012
Found symbol REG_PSP at 0x0014
Found symbol REG_TOS at 0x0016
All required symbols found
Setting callback at address: 0xC0D2
Memory position reached: 0xC0D2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category><category term="Famicom"></category></entry><entry><title>Forth sur 6502, épisode 1</title><link href="https://www.triceraprog.fr/forth-sur-6502-episode-1.html" rel="alternate"></link><published>2025-12-07T00:00:00+01:00</published><updated>2025-12-07T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-12-07:/forth-sur-6502-episode-1.html</id><summary type="html">&lt;h2&gt;Family Forth, le projet&lt;/h2&gt;
&lt;p&gt;En m'intéressant au langage de &lt;strong&gt;programmation Forth&lt;/strong&gt;, j'ai parfois croisé l'affirmation que pour bien comprendre Forth, il fallait en développer un. &lt;/p&gt;
&lt;p&gt;C'est cohérent avec son histoire, qui débute comme une trousse à outils de son inventeur pour lui faciliter les développements qu'il fait pour ses employeurs. &lt;/p&gt;
&lt;p&gt;J'ai lu un certain nombre de documents sur Forth, parcouru quelques implémentations et même développé un jeu dans ce langage pour &lt;a href="https://www.triceraprog.fr/un-jeu-en-forth-pour-hector-hrx-picthorix.html"&gt;Hector HRX&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Plus récemment, en m'amusant avec le &lt;a href="https://www.triceraprog.fr/family-basic-le-basic-sur-famicom.html"&gt;BASIC pour &lt;strong&gt;Famicom&lt;/strong&gt;&lt;/a&gt;, je me suis demandé ce qui pourrait être développé sur la console pour tirer parti du clavier. Alors, pourquoi pas un Forth interactif sur Famicom ?&lt;/p&gt;
&lt;p&gt;Une rapide recherche m'a montré que des expériences en Forth pour Famicom avaient déjà été faites, mais pas forcément sous l'angle interactif. Et bien entendu, il existe déjà des Forth pour 6502, le processeur qui équipe cette machine (même si c'est une version …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Family Forth, le projet&lt;/h2&gt;
&lt;p&gt;En m'intéressant au langage de &lt;strong&gt;programmation Forth&lt;/strong&gt;, j'ai parfois croisé l'affirmation que pour bien comprendre Forth, il fallait en développer un. &lt;/p&gt;
&lt;p&gt;C'est cohérent avec son histoire, qui débute comme une trousse à outils de son inventeur pour lui faciliter les développements qu'il fait pour ses employeurs. &lt;/p&gt;
&lt;p&gt;J'ai lu un certain nombre de documents sur Forth, parcouru quelques implémentations et même développé un jeu dans ce langage pour &lt;a href="https://www.triceraprog.fr/un-jeu-en-forth-pour-hector-hrx-picthorix.html"&gt;Hector HRX&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Plus récemment, en m'amusant avec le &lt;a href="https://www.triceraprog.fr/family-basic-le-basic-sur-famicom.html"&gt;BASIC pour &lt;strong&gt;Famicom&lt;/strong&gt;&lt;/a&gt;, je me suis demandé ce qui pourrait être développé sur la console pour tirer parti du clavier. Alors, pourquoi pas un Forth interactif sur Famicom ?&lt;/p&gt;
&lt;p&gt;Une rapide recherche m'a montré que des expériences en Forth pour Famicom avaient déjà été faites, mais pas forcément sous l'angle interactif. Et bien entendu, il existe déjà des Forth pour 6502, le processeur qui équipe cette machine (même si c'est une version custom, cela ne change pas grand chose).&lt;/p&gt;
&lt;p&gt;Mais la prémisse reste : l'intérêt est de développer &lt;strong&gt;son propre Forth&lt;/strong&gt;. Et c'est donc ce que je vais faire dans une série d'articles qui me serviront à poser mes idées, comme pense bête. Et pourquoi pas comme inspiration pour d'autres, si vous voulez bien me suivre, qui sait ? &lt;/p&gt;
&lt;p&gt;Pour initier le développement, j'ai décidé de suivre la série d'articles &lt;strong&gt;Moving Forth&lt;/strong&gt;, qui a été publiée à partir du numéro 59 du « The Computer Journal », en janvier/février 1993.&lt;/p&gt;
&lt;p&gt;Cette série d'articles est intéressante car elle étudie pour différentes étapes les options d'implémentations qui s'offrent, avec des références. Elle donne aussi des implémentations pour divers CPUs, mais pas pour 6502, ce qui me laissera un peu de choix dans mes réflexions, même si je doute que ceux-ci soient très originaux. &lt;/p&gt;
&lt;p&gt;Ces articles étant assez anciens, ils renvoient aussi à une conception pas trop moderne de Forth, qui a évolué depuis, et donc plus proche de ce qu'on pourrait attendre sur Famicom. Enfin peut-être, on verra. &lt;/p&gt;
&lt;p&gt;Le 6502 est aussi un CPU que j'ai très peu pratiqué, c'est donc une occasion de gagner en expérience dessus.&lt;/p&gt;
&lt;h2&gt;Moving Forth, article 1&lt;/h2&gt;
&lt;p&gt;De chaque article de Moving Forth, je vais retirer les informations qui me semblent importantes dans la démarche de développement. Et je commence donc par... le &lt;a href="https://www.bradrodriguez.com/papers/moving1.htm"&gt;premier article&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Quelques choix&lt;/h3&gt;
&lt;p&gt;Tout d'abord, la taille des mots. Sur un tel processeur, le choix est assez facile : 16 bits est le minimum pour manipuler des adresses mémoire. Les &lt;strong&gt;mots seront donc sur 16 bits&lt;/strong&gt;. L'article rappelle d'ailleurs qu'il vaut mieux utiliser le mot « cellule » (CELL) car un « mot » est quelque chose d'autre en Forth.&lt;/p&gt;
&lt;p&gt;Vient ensuite le choix du modèle de fonctionnement. Il y a plusieurs moyens de faire fonctionner un Forth, l'article mentionne le « Indirect Threaded Code » (ITC), le « Direct Threaded Code » (DTC), le « Subroutine Threaded Code » (STC) et le « Token Threaded Code » (TTC). Il mentionne aussi le « Segment Threaded Code », mais c'est particulier au 8086, donc pas pertinent ici.&lt;/p&gt;
&lt;p&gt;Le choix classique pour des machines 8 bits est le &lt;strong&gt;« Indirect Threaded Code »&lt;/strong&gt;. Je vais suivre le mouvement et choisir cette méthode. L'article indique que ça n'est ni la méthode la plus rapide ni la plus compacte, qu'elle a un avantage de simplicité, mais que c'est surtout une habitude historique.&lt;/p&gt;
&lt;p&gt;Cependant, c'est aussi la méthode dont j'ai l'habitude lorsque j'ai pratiqué Forth sur d'autres machines 8 bits. Je me note cependant dans un coin de peut-être étudier plus tard les autres méthodes.&lt;/p&gt;
&lt;h3&gt;Registres&lt;/h3&gt;
&lt;p&gt;Il nous faut aussi des registres. On parle là de registres Forth, et de la manière dont ils seront implémentés sur le CPU, ici le 6502. &lt;/p&gt;
&lt;p&gt;Voici la liste des registres pour lesquels il faudra trouver une place, par ordre d'importance décroissante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;W (working register)&lt;/li&gt;
&lt;li&gt;IP (instruction pointer)&lt;/li&gt;
&lt;li&gt;PSP (parameter stack pointer)&lt;/li&gt;
&lt;li&gt;RSP (return stack pointer)&lt;/li&gt;
&lt;li&gt;TEMP (temporary register)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rappel, tous ces registres doivent être sur 16 bits.&lt;/p&gt;
&lt;p&gt;L'article mentionne un registre TOS (top of stack), optionnel mais qui peut optimiser certaines opérations. Pour le moment, je vais le laisser de côté.&lt;/p&gt;
&lt;p&gt;Il est aussi fait mention d'un mapping possible des registres sur 6502, que voici :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emplacement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zéro&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emplacement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zéro&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PSP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`X`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6502&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RSP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`SP`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6502&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emplacement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mémoire&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;X&lt;/code&gt; et &lt;code&gt;SP&lt;/code&gt; étant des registres 8 bits, cela limite la taille de la pile de paramètres et de la pile de retour. À voir si c'est un problème ou pas.&lt;/p&gt;
&lt;p&gt;Ce qui me fait penser qu'il y aura tout intérêt d'écrire un maximum de mots Forth à partir d'autres mots Forth et de limiter les mots en assembleur, au moins dans un premier temps. Ceci afin de limiter la réécriture de routines si je change d'avis sur le mapping des registres.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Très bien, après tout cela, il est temps de passer à la définition d'un projet minimal sur la machine cible. Entre autre, il faudra vérifier les emplacements déjà réservés, que ce soit dans la page zéro ou ailleurs en mémoire.&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="6502"></category></entry><entry><title>Compression de données, Huffman</title><link href="https://www.triceraprog.fr/compression-de-donnees-huffman.html" rel="alternate"></link><published>2025-11-15T00:00:00+01:00</published><updated>2025-11-15T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-11-15:/compression-de-donnees-huffman.html</id><summary type="html">&lt;p&gt;Voici un nouvel article de la série sur la compression de données, qui fait suite à celui sur la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-compter-les-repetitions.html"&gt;compression RLE&lt;/a&gt;, la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-referencer-les-repetitions.html"&gt;compression LZ&lt;/a&gt; et la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-le-format-zx0.html"&gt;compression ZX0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;À la fin de l'article sur la compression LZ, il avait été question de fréquence d'apparition des nombres pour les offsets de référence et les longueurs de motif. Cette constatation avait amené lors de l'article sur ZX0 à regarder le codage gamma, qui permet de coder des entiers avec un nombre de bits variable afin d'optimiser la taille des petits nombres (qui sont plus fréquents).&lt;/p&gt;
&lt;p&gt;Revenons sur cette histoire de fréquence en l'étendant à tous les symboles présents dans les données à compresser. Il serait intéressant d'avoir un codage dépendant de la fréquence d'apparition des symboles : plus le symbole est fréquent, plus son code est court.&lt;/p&gt;
&lt;p&gt;Ce codage est obtenu avec l'&lt;strong&gt;algorithme de Huffman&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;En plus d'avoir des codes de longueurs …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Voici un nouvel article de la série sur la compression de données, qui fait suite à celui sur la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-compter-les-repetitions.html"&gt;compression RLE&lt;/a&gt;, la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-referencer-les-repetitions.html"&gt;compression LZ&lt;/a&gt; et la &lt;a href="https://www.triceraprog.fr/compression-de-donnees-le-format-zx0.html"&gt;compression ZX0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;À la fin de l'article sur la compression LZ, il avait été question de fréquence d'apparition des nombres pour les offsets de référence et les longueurs de motif. Cette constatation avait amené lors de l'article sur ZX0 à regarder le codage gamma, qui permet de coder des entiers avec un nombre de bits variable afin d'optimiser la taille des petits nombres (qui sont plus fréquents).&lt;/p&gt;
&lt;p&gt;Revenons sur cette histoire de fréquence en l'étendant à tous les symboles présents dans les données à compresser. Il serait intéressant d'avoir un codage dépendant de la fréquence d'apparition des symboles : plus le symbole est fréquent, plus son code est court.&lt;/p&gt;
&lt;p&gt;Ce codage est obtenu avec l'&lt;strong&gt;algorithme de Huffman&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;En plus d'avoir des codes de longueurs variables en fonction de la fréquence, Huffman garantit qu'aucun code n'est le préfixe d'un autre code, ce qui rend l'algorithme de décodage très facile.
Le codage est aussi optimal : il n'y a pas de codage préfixe plus court pour les fréquences données.&lt;/p&gt;
&lt;h2&gt;Algorithme de compression de Huffman&lt;/h2&gt;
&lt;p&gt;L'idée générale de l'algorithme est la suivante : après avoir calculé les fréquences d'apparition des symboles, on construit un arbre binaire où chaque symbole est une feuille de l'arbre, avec les symboles les plus fréquents proches de la racine. Le code d'un symbole correspond alors au parcours depuis la racine jusqu'à la feuille, en prenant 0 pour une branche et 1 pour l'autre.&lt;/p&gt;
&lt;p&gt;Pour initier la construction de l'arbre, on crée une liste de nœuds, un par symbole associé à sa fréquence. Ensuite et itérativement jusqu'à avoir l'arbre complet, on prend les deux nœuds de plus petite fréquence et on crée un nouveau nœud parent avec comme fréquence la somme des deux fréquences.&lt;/p&gt;
&lt;p&gt;Reprenons l'exemple qui nous suit depuis le début. Pour rappel, il s'agit de cette image :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;................
....#######.....
..##@@@@@@@##...
.##@OOOOOOO@##..
.#@OoooooooO@#..
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
.#@OoooooooO@#..
.##@OOOOOOO@##..
..##@@@@@@@##...
....#######.....
................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On commence donc par calculer les fréquences (ou occurrences, cela revient au même) des symboles :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Fréquences des symboles :
  &amp;#39;.&amp;#39;: 78 (28.78%)
  &amp;#39;o&amp;#39;: 68 (25.09%)
  &amp;#39;#&amp;#39;: 46 (16.97%)
  &amp;#39;@&amp;#39;: 34 (12.55%)
  &amp;#39;O&amp;#39;: 30 (11.07%)
  &amp;#39;\\n&amp;#39;: 15 (5.54%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Donc, plein de '.' et de "o", et pas beaucoup de retours à la ligne. À noter qu'avec 6 symboles différents, on pourrait utiliser un codage fixe sur 3 bits par symbole (2^3 = 8 possibilités). Voyons ce que donne Huffman en déroulant l'algorithme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On prend les deux nœuds de plus petites occurrences : '\n' (15) et 'O' (30)&lt;/li&gt;
&lt;li&gt;On crée un nœud parent "\nO" avec occurrences 45 (15 + 30)&lt;/li&gt;
&lt;li&gt;On prend les deux nœuds de plus petites occurrences : '@' (34) et le "\nO" (45)&lt;/li&gt;
&lt;li&gt;On crée un nœud parent "@\nO" avec occurrences 79 (34 + 45)&lt;/li&gt;
&lt;li&gt;On prend les deux nœuds de plus petites occurrences : '#' (46) et 'o' (68)&lt;/li&gt;
&lt;li&gt;On crée un nœud parent "#o" avec occurrences 114 (46 + 68)&lt;/li&gt;
&lt;li&gt;On prend les deux nœuds de plus petites occurrences : '.' (78) et le "@\nO" (79)&lt;/li&gt;
&lt;li&gt;On crée un nœud parent ".@\nO" avec occurrences 157 (78 + 79)&lt;/li&gt;
&lt;li&gt;On prend les deux nœuds de plus petites occurrences : "#o" (114) et ".@\nO" (157)&lt;/li&gt;
&lt;li&gt;On crée un nœud racine avec occurrences 271 (114 + 157)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui nous amène à l'arbre suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            [271]
           /     \
   &amp;lt;-- 0  /       \  1 --&amp;gt;
         /         \
      [114]        [157]
     /     \      /     \
   [46]   [68]  [78]   [79]
     #      o     .   /    \
                    [34]  [45]
                      @  /    \
                        [15] [30]
                         \n    O
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour trouver les codes associé à chaque symbole, on parcourt l'arbre depuis la racine jusqu'à chaque feuille, en prenant 0 pour la branche de gauche et 1 pour la branche de droite. Et cela donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  &amp;#39;.&amp;#39;  : 10   (longueur=2)
  &amp;#39;o&amp;#39;  : 01   (longueur=2)
  &amp;#39;#&amp;#39;  : 00   (longueur=2)
  &amp;#39;@&amp;#39;  : 110  (longueur=3)
  &amp;#39;O&amp;#39;  : 1111 (longueur=4)
  &amp;#39;\\n&amp;#39;: 1110 (longueur=4)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En prenant la moyenne des longueurs pondérées par les occurrences, on obtient une taille moyenne de 2.45 bits environ par symbole. C'est mieux que les 3 bits fixes, mais pas extraordinaire non plus en considérant que 3 bits auraient pu coder 8 symboles.&lt;/p&gt;
&lt;p&gt;Cependant, il n'y a pas besoin de faire l'analyse au préalable et à la main pour savoir combien de bits sont nécessaires. L'algorithme de Huffman le fait tout seul.&lt;/p&gt;
&lt;p&gt;La compression elle-même consiste ensuite à remplacer chaque symbole par son code binaire. Pour notre exemple, cela donne pour la première ligne la suite de bits suivante : &lt;code&gt;10101010101010101010101010101010&lt;/code&gt;, ce qui fait une suite d'octets : &lt;code&gt;0xAA&lt;/code&gt; &lt;code&gt;0xAA&lt;/code&gt; &lt;code&gt;0xAA&lt;/code&gt; &lt;code&gt;0xAA&lt;/code&gt;. On passe de 16 octets à 4. On voit aussi qu'un motif se répète... intéressant non ? J'évoquerai cela à la fin de l'article.&lt;/p&gt;
&lt;h2&gt;Algorithme de décompression&lt;/h2&gt;
&lt;p&gt;La décompression est très simple : avec le flux compressé et l'arbre, on parcours l'arbre en lisant les bits un par un. À chaque 0, on descend sur la branche de gauche, à chaque 1 sur la branche de droite. Lorsqu'on atteint une feuille, on émet le symbole correspondant et on repart de la racine.&lt;/p&gt;
&lt;p&gt;Je vous laisse faire l'exercice avec &lt;code&gt;0xAA&lt;/code&gt; (c'est-à-dire &lt;code&gt;10101010&lt;/code&gt;) pour retrouver une série de quatre '.'.&lt;/p&gt;
&lt;h2&gt;Et l'arbre ?&lt;/h2&gt;
&lt;p&gt;C'est bien beau d'avoir codé les données grâce à l'arbre. Mais il nous faut l'arbre pour décoder le flux compressé. Il est donc nécessaire de le transmettre avec les données compressées. Il y a plusieurs manières de faire, mais voici une approche simple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pour chaque nœud interne, on écrit un 0 (en bit) et on sérialise récursivement les deux nœuds enfants.&lt;/li&gt;
&lt;li&gt;Pour chaque feuille, on écrit un 1 suivi du code du symbole (sur 8 bits).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En commençant par la racine, on obtient un parcours en profondeur de l'arbre. Pour notre exemple, cela donne la séquence de bits suivante (les caractères sont ici pour la lisibilité, mais en pratique ce sont leur représentation binaire qui est utilisée) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;0
  0
    1 `#`
    1 `o`
  0
    1 `.`
    0
      1 `@`
      1 `\n`
    1 `O`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cela fonctionne puisque, par construction, chaque nœud interne a toujours deux enfants, sauf s'il n'y a qu'un seul symbole dans les données.&lt;/p&gt;
&lt;p&gt;L'exemple ici prend 8 octets (avec quelques bits non utilisés dans le dernier octet). C'est assez petit par rapport aux données, ça va.&lt;/p&gt;
&lt;h2&gt;Les chiffres&lt;/h2&gt;
&lt;p&gt;Avec les données de l'exemple,. on obtient les résultats suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Taille originale : 271 octets (2168 bits)&lt;/li&gt;
&lt;li&gt;Taille compressée : 666 bits (84 octets, avec 6 bits de padding)&lt;/li&gt;
&lt;li&gt;Taille de l'arbre : 8 octets&lt;/li&gt;
&lt;li&gt;Taille totale compressée : 92 octets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui donne une taille finale compressée, arbre compris, de 33.95% de la taille originale.&lt;/p&gt;
&lt;h2&gt;Combinaisons&lt;/h2&gt;
&lt;p&gt;Si on regarde le flux compressé (hors arbre), voici ce que cela donne en hexadécimal :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xEA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xA0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x2A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xA0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x6D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xB0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xD0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x6F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xC1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x5D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x1B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xD5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x57&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x1B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xD5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x5F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xC5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xC6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xF5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x57&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xF1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x71&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xBD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x5C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x6F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x7F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x1B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xD5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x5F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xC5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xC6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xF5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x57&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xF1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x74&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x6F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x57&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xF1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x5D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x06&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xFC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xD4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x1B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x6D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xB6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x0A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xBA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xA8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x0A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;xAA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Comme indiqué plus haut, on remarque des motifs qui se répètent. Ce flux est donc probablement un bon candidat pour une compression supplémentaire avec LZ par exemple. Pourquoi pas ?&lt;/p&gt;
&lt;p&gt;L'algorithme DEFLATE (utilisé dans le format .zip par exemple) fait le contraire : il applique d'abord LZ77 pour compresser les motifs répétitifs, puis applique Huffman pour compresser les symboles résultants. C'est un peu plus compliqué que cela, mais c'est l'idée générale, et c'est l'idée générale derrière plusieurs formats de compressions : des mélanges d'algorithmes.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Huffman est un algorithme de compression efficace sur des données avec des fréquences d'apparition de symboles non uniformes. Si tous les symboles sont également fréquents, il n'y aura pas d'avantage à utiliser Huffman par rapport à un codage fixe. De plus, il faut stocker l'arbre, il est donc important de vérifier que la taille gagnée par la compression compense la taille de l'arbre (il est aussi possible d'utiliser des arbres statiques connus à l'avance pour certains types de données, mais cela sera potentiellement moins efficace).&lt;/p&gt;
&lt;p&gt;On retrouve cet algorithme dans de nombreux formats de compression, souvent combiné avec d'autres algorithmes. C'est une des bases de la compression de données, il est donc intéressant de connaître son principe de fonctionnement.&lt;/p&gt;
&lt;p&gt;Cet article termine la petite série sur la compression de données sans perte.&lt;/p&gt;
&lt;h3&gt;Supplément&lt;/h3&gt;
&lt;p&gt;Le code que j'ai utilisé lors de l'écriture pour vérifier les exemples est &lt;a href="https://www.triceraprog.fr/files/202511/20251109-huffman.py"&gt;disponible ici&lt;/a&gt;.&lt;/p&gt;</content><category term="Algorithmes"></category><category term="Compression"></category><category term="Huffman"></category></entry><entry><title>Compression de données, le format ZX0</title><link href="https://www.triceraprog.fr/compression-de-donnees-le-format-zx0.html" rel="alternate"></link><published>2025-11-02T00:00:00+01:00</published><updated>2025-11-02T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-11-02:/compression-de-donnees-le-format-zx0.html</id><summary type="html">&lt;p&gt;Après avoir présenté dans l'&lt;a href="https://www.triceraprog.fr/compression-de-donnees-referencer-les-repetitions.html"&gt;article précédent sur la compression LZ&lt;/a&gt; l'idée générale de référencement arrière de données déjà présentes en mémoire, cet article va se concentrer sur une implémentation spécifique de la famille LZ : le ZX0, un algorithme développé par &lt;a href="https://github.com/einar-saukas/ZX0"&gt;Einar Saukas&lt;/a&gt; avec pour double objectif une taille très compacte pour le code de décompression et une recherche des choix optimaux lors de la compression.&lt;/p&gt;
&lt;p&gt;Au niveau du code de décompression, sur Z80 et pour reprendre les exemples fournis dans le README officiel, on a les chiffres suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routine "Standard" : 68 octets&lt;/li&gt;
&lt;li&gt;Routine "Turbo" : 126 octets, environ 21% plus rapide&lt;/li&gt;
&lt;li&gt;Routine "Fast" : 187 octets, environ 25% plus rapide  &lt;/li&gt;
&lt;li&gt;Routine "Mega" : 673 octets, environ 28% plus rapide&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour obtenir un code de décompression aussi compact, les choix faits dans le format ZX0 sont adaptés à un décodage avec peu de calculs et des calculs simples.&lt;/p&gt;
&lt;p&gt;Rentrons dans les détails.&lt;/p&gt;
&lt;h2&gt;Le …&lt;/h2&gt;</summary><content type="html">&lt;p&gt;Après avoir présenté dans l'&lt;a href="https://www.triceraprog.fr/compression-de-donnees-referencer-les-repetitions.html"&gt;article précédent sur la compression LZ&lt;/a&gt; l'idée générale de référencement arrière de données déjà présentes en mémoire, cet article va se concentrer sur une implémentation spécifique de la famille LZ : le ZX0, un algorithme développé par &lt;a href="https://github.com/einar-saukas/ZX0"&gt;Einar Saukas&lt;/a&gt; avec pour double objectif une taille très compacte pour le code de décompression et une recherche des choix optimaux lors de la compression.&lt;/p&gt;
&lt;p&gt;Au niveau du code de décompression, sur Z80 et pour reprendre les exemples fournis dans le README officiel, on a les chiffres suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routine "Standard" : 68 octets&lt;/li&gt;
&lt;li&gt;Routine "Turbo" : 126 octets, environ 21% plus rapide&lt;/li&gt;
&lt;li&gt;Routine "Fast" : 187 octets, environ 25% plus rapide  &lt;/li&gt;
&lt;li&gt;Routine "Mega" : 673 octets, environ 28% plus rapide&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour obtenir un code de décompression aussi compact, les choix faits dans le format ZX0 sont adaptés à un décodage avec peu de calculs et des calculs simples.&lt;/p&gt;
&lt;p&gt;Rentrons dans les détails.&lt;/p&gt;
&lt;h2&gt;Le double flux&lt;/h2&gt;
&lt;p&gt;ZX0 utilise deux flux de données distincts. Le premier flux contient les informations sur les blocs : quel type de bloc (littéral ou référence arrière), les offsets et les longueurs. Ce flux est lu bit par bit. Le second flux contient les données littérales elles-mêmes, lues octet par octet.&lt;/p&gt;
&lt;p&gt;Il suffit donc d'avoir une routine qui lit le bit suivant du premier flux et une routine qui lit l'octet suivant du second flux. Un pointeur suffit pour le second flux. Le premier flux est un peu plus complexe : il nécessite un pointeur, un octet courant et un compteur de bits restants dans l'octet courant. Cela reste très simple.&lt;/p&gt;
&lt;p&gt;Ces deux flux sont entrelacés. Lorsque l'une des deux routines a besoin d'un nouvel octet, elle le lit depuis les données compressées. Cela signifie qu'en fait, un seul pointeur est nécessaire pour parcourir les deux flux. De manière symétrique, cela signifie que lors de la compression, les données doivent être écrites en un seul flux en entrelaçant les deux types de données au fur et à mesure qu'elles forment un octet complet.&lt;/p&gt;
&lt;h2&gt;Encodage des nombres&lt;/h2&gt;
&lt;p&gt;À la fin de l'article précédent, la constatation était que les références avaient souvent des petites longueurs et qu'il pouvait être intéressant de trouver un moyen d'encoder ces petites longueurs de manière efficace.&lt;/p&gt;
&lt;p&gt;ZX0 prend acte et utilise un codage nommé « &lt;a href="https://fr.wikipedia.org/wiki/Codage_gamma"&gt;codage gamma&lt;/a&gt; » ou encore « codage gamma d'Elias » ("Elias Gamma coding").&lt;/p&gt;
&lt;h3&gt;Principe du codage gamma&lt;/h3&gt;
&lt;p&gt;Le codage gamma propose d’écrire un nombre en deux parties : la longueur binaire nécessaire et la valeur restante depuis la puissance de 2 inférieure.&lt;/p&gt;
&lt;p&gt;La longueur du nombre en binaire est encodée de manière unaire : on regarde combien de bits sont nécessaires pour écrire le nombre en binaire, on écrit cette valeur moins un en unaire (avec autant de 0 que le nombre voulu), puis on termine avec un 1. Incidemment, cela représente la puissance de deux inférieure nécessaire pour coder le nombre.&lt;/p&gt;
&lt;p&gt;Par exemple, pour le nombre 3, qui s'écrit &lt;code&gt;11&lt;/code&gt; en binaire (2 bits), on écrit &lt;code&gt;01&lt;/code&gt; (un 0 suivi d'un 1). Pour le nombre 10, qui s'écrit &lt;code&gt;1010&lt;/code&gt; en binaire (4 bits), on écrit &lt;code&gt;0001&lt;/code&gt; (trois 0 suivis d'un 1).&lt;/p&gt;
&lt;p&gt;Pour la valeur restante, on prend le nombre, on enlève la plus grande puissance de 2 qui ne dépasse pas ce nombre, puis on écrit le reste en binaire, sur le nombre de bits calculé précédemment (le nombre de fois où on a trouvé 0 avant le 1).&lt;/p&gt;
&lt;p&gt;Par exemple, pour le nombre 3, la plus grande puissance de 2 inférieure est &lt;code&gt;2&lt;/code&gt; ($2^1$), donc le reste est $3 - 2 = 1$, qui s'écrit &lt;code&gt;1&lt;/code&gt; en binaire sur 1 bit. Pour le nombre 10, la plus grande puissance de 2 inférieure est &lt;code&gt;8&lt;/code&gt; ($2^3$), donc le reste est $10 - 8 = 2$, qui s'écrit &lt;code&gt;010&lt;/code&gt; en binaire sur 3 bits.&lt;/p&gt;
&lt;p&gt;Ainsi on a :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;3  -&amp;gt;   01 1    (pour un total de 3 bits)
10 -&amp;gt; 0001 010  (pour un total de 7 bits)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce codage est efficace pour les petits nombres (jusqu'à 15), car il peut les écrire avec moins de 8 bits. En revanche, il devient moins efficace pour les nombres plus grands (par exemple 16 occupe 9 bits en codage gamma).&lt;/p&gt;
&lt;p&gt;Ce codage offre aussi l'avantage d'être sur un nombre de bits variable et de permettre la « découverte » de cette taille lors de la lecture. &lt;/p&gt;
&lt;p&gt;Mais pour rendre le décodage encore plus simple, ZX0 utilise une variante appelée « codage gamma entrelacé » qui permet de lire tous les bits dans l'ordre en une seule passe. L'entrelacement se fait entre la partie unaire et la partie binaire (dans le sens du plus petit bit vers le plus grand). Les bits de la première partie (unaire) sont les bits impaires et les bits de la seconde partie (binaire) sont les bits paires.&lt;/p&gt;
&lt;p&gt;Exemples :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;3  codé   01 1   devient 011
10 codé 0001 010 devient 0001001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ce système, il suffit de lire un bit et s'arrêter s'il est à 1, sinon lire un autre bit pour la partie binaire, l'ajouter à l'accumulateur préalablement décalé vers la gauche. Puis recommencer jusqu'à trouver un 1. Pour que l'algorithme fonctionne, l'accumulateur doit être initialisé à 1.&lt;/p&gt;
&lt;p&gt;Par exemple, pour décoder &lt;code&gt;011&lt;/code&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lire 0 (unaire), on continue&lt;/li&gt;
&lt;li&gt;Lire 1 (binaire), accumulateur = 1 &amp;lt;&amp;lt; 1 | 1 = 3&lt;/li&gt;
&lt;li&gt;Lire 1 (unaire), on s'arrête, valeur finale = 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et pour décoder &lt;code&gt;0001001&lt;/code&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lire 0 (unaire), on continue&lt;/li&gt;
&lt;li&gt;Lire 0 (binaire), accumulateur = 1 &amp;lt;&amp;lt; 1 | 0 = 2&lt;/li&gt;
&lt;li&gt;Lire 0 (unaire), on continue&lt;/li&gt;
&lt;li&gt;Lire 1 (binaire), accumulateur = 2 &amp;lt;&amp;lt; 1 | 1 = 5&lt;/li&gt;
&lt;li&gt;Lire 0 (unaire), on continue&lt;/li&gt;
&lt;li&gt;Lire 0 (binaire), accumulateur = 5 &amp;lt;&amp;lt; 1 | 0 = 10&lt;/li&gt;
&lt;li&gt;Lire 1 (unaire), on s'arrête, valeur finale = 10&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Les types de blocs&lt;/h2&gt;
&lt;p&gt;Maintenant que l'on sait qu'il y a deux flux et comment encoder les nombres, voyons comment ZX0 organise les blocs de données. Il existe trois types de blocs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloc littéral : contient les données littérales. Est associé à une longueur.&lt;/li&gt;
&lt;li&gt;Bloc de référence : référence une séquence de données précédemment rencontrée. Est associé à un offset et une longueur.&lt;/li&gt;
&lt;li&gt;Bloc de référence de même offset : tout comme un bloc de référence, mais réutilise le dernier offset utilisé et ne spécifie donc que la longueur.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour différencier ces trois types de blocs, ZX0 utilise un seul bit. Un seul bit pour désigner trois types de blocs ? Cela est possible car certaines contraintes logiques existent entre les blocs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deux blocs littéraux ne peuvent pas se suivre (sinon ils seraient fusionnés en un seul bloc littéral).&lt;/li&gt;
&lt;li&gt;Un bloc de référence de même offset ne peut apparaître qu'après un bloc littéral.&lt;/li&gt;
&lt;li&gt;Le premier bloc est toujours un bloc littéral (et d'ailleurs le tout premier bit qui devrait indiquer le type de bloc est omis).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ainsi, le bloc littéral et le bloc de référence de même offset sont tous deux indiqués par un 0 et le bloc de référence avec nouvel offset est indiqué par un 1. Le contexte permet de savoir quel type de bloc est concerné entre les deux premiers.&lt;/p&gt;
&lt;p&gt;Les longueurs sont encodées en utilisant le codage gamma entrelacé décrit précédemment. Pour les offsets, c'est un peu plus compliqué : l'offset est divisé en deux parties, le MSB (Most Significant Byte) utilise le codage gamma entrelacé, tandis que le LSB (Least Significant Byte) est stocké tel quel sur 7 bits (au lieu de 8). Comme on ne peut pas encoder 0 en gamma, le MSB de l'offset est stocké avec une valeur augmentée de 1.&lt;/p&gt;
&lt;p&gt;Autre petite optimisation : puisqu'une référence avec nouvel offset a toujours une longueur minimale de 2, la longueur stockée pour une référence est en fait la longueur moins 1.&lt;/p&gt;
&lt;p&gt;Exemples :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;0 011               -&amp;gt; bloc littéral de longueur 3
                       (ou bien référence de longueur 3 selon le contexte)
1 1 0000011 0001001 -&amp;gt; bloc de référence avec nouvel offset de longueur 3
                       (1 en codage gamma pour MSB = 0)
                       (0000011 pour LSB = 3)
                       et longueur 11 (10 + 1)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Recherche optimale&lt;/h2&gt;
&lt;p&gt;Lors de l'article précédent qui présentait l'idée derrière la compression LZ, il avait été question de prendre en référence arrière la plus grande séquence identique possible. Cela fonctionne : c'est un type d'algorithme glouton (greedy). Cependant, cette méthode n'est pas forcément (pas souvent ?) optimale. Peut-être que prendre à un endroit le motif le plus long empêche de faire un meilleur choix de référence un peu plus loin. Ou bien peut-être que cela cause des codages gamma sur trop de bits. L'algorithme ZX0 fait le choix de trouver la solution optimale.&lt;/p&gt;
&lt;p&gt;Pour cela, à chaque position lors de la compression, l'algorithme va examiner tous les offsets possible et regarder s'il est possible de faire une référence arrière et maintenir une chaîne optimale en calculant le coût total si une référence devait être faite à cet endroit.&lt;/p&gt;
&lt;p&gt;L'algorithme fait appel à de la programmation dynamique pour obtenir un code compact et efficace. Efficace, mais pas rapide : la compression avec ZX0 est lente avec des fichiers un peu conséquents, c'est son principal inconvénient. Mais en échange, on est assuré que, avec les choix de codage de ce format, le résultat est le plus compact possible.&lt;/p&gt;
&lt;h2&gt;Test sur l'exemple&lt;/h2&gt;
&lt;p&gt;Reprenons à nouveau l'image en niveaux de gris des deux articles précédents et voyons ce que cela donne avec le format ZX0.&lt;/p&gt;
&lt;p&gt;L'exemple, pour rappel :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;................
....#######.....
..##@@@@@@@##...
.##@OOOOOOO@##..
.#@OoooooooO@#..
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
.#@OoooooooO@#..
.##@OOOOOOO@##..
..##@@@@@@@##...
....#######.....
................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le résultat de la compression avec ZX0 est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;File compressed from 272 to 51 bytes! (delta 3)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Soit un fichier final ayant un peu moins de 19% de la taille originale. Pour rappel, la compression RLE et LZ « naïve » avaient donné un fichier de 57% la taille originale. C'est nettement mieux.&lt;/p&gt;
&lt;p&gt;Voici le contenu de fichier final :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;0000000  95  2e  89  0a  2e  a4  23  f7  de  b9  ed  40  fe  ff  ef  de
0000010  ee  e0  4f  fe  7f  dc  fb  de  e1  6f  9f  fe  dd  fc  de  e0
0000020  f7  dc  91  de  1f  12  5d  d7  ce  75  8a  d9  46  1d  d7  02
0000030  55  55  80  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On peut s'amuser à décoder le début à la main.&lt;/p&gt;
&lt;p&gt;On garde le premier octet &lt;code&gt;$95&lt;/code&gt; (&lt;code&gt;10010101&lt;/code&gt; en binaire) en mémoire, il s'agit des informations de blocs. Le premier bloc est toujours un bloc littéral, on commence donc par une longueur en codage gamma entrelacé. &lt;code&gt;1&lt;/code&gt; signifie une longueur de 1. On lit donc le premier octet du flux littéral : &lt;code&gt;$2e&lt;/code&gt; (le caractère &lt;code&gt;.&lt;/code&gt;). Nous voici avec notre premier caractère décodé.&lt;/p&gt;
&lt;p&gt;On continue à lire ce qu'il reste de notre octet &lt;code&gt;$95&lt;/code&gt; : le bit suivant est un &lt;code&gt;0&lt;/code&gt;. Puisque le bloc précédent était un bloc littéral, ce 0 indique un bloc de référence de même offset. Le offset précédent est initialisé à 1 en début d'algorithme. On a donc une référence de 1 en arrière (le caractère &lt;code&gt;.&lt;/code&gt; déjà décodé). Reste à lire la longueur en codage gamma entrelacé : &lt;code&gt;010101...&lt;/code&gt; le nombre n'est pas terminé, il nous faut un nouvel octet depuis le flux. C'est &lt;code&gt;$89&lt;/code&gt; (&lt;code&gt;10001001&lt;/code&gt; en binaire).&lt;/p&gt;
&lt;p&gt;On continue la lecture : &lt;code&gt;1&lt;/code&gt;. Le bit de fin du codage gamma. Ce qui donne au final &lt;code&gt;0101011&lt;/code&gt;, soit &lt;code&gt;0001 111&lt;/code&gt; en désentrelacé, soit une longueur de &lt;code&gt;15&lt;/code&gt;. On copie donc 15 fois le caractère trouvé une position avant. Nous voici avec 16 caractères &lt;code&gt;.&lt;/code&gt; décodés. À noter qu'il n'y avait qu'un seul octet dans le flux littéral, mais la copie avance en recopiant le caractère déjà décodé. Avec une référence arrière de 1, il y a autant de copie de &lt;code&gt;.&lt;/code&gt; que nécessaire.&lt;/p&gt;
&lt;p&gt;Continuons. Le prochain bloc est indiqué par le bit suivant : &lt;code&gt;0&lt;/code&gt;. Puisque le bloc précédent était une référence, ce 0 indique un bloc littéral. On lit la longueur en codage gamma entrelacé : &lt;code&gt;001&lt;/code&gt;, soit &lt;code&gt;01 0&lt;/code&gt; en non entrelacé, ce qui signifie &lt;code&gt;2&lt;/code&gt;. On lit donc les deux octets suivants dans le flux littéral : &lt;code&gt;$0a&lt;/code&gt; (le caractère de retour chariot) et &lt;code&gt;$2e&lt;/code&gt; (le caractère &lt;code&gt;.&lt;/code&gt;). Nous venons de compléter la première ligne de l'image et de débuter la seconde.&lt;/p&gt;
&lt;p&gt;Vous pouvez continuer si vous le souhaitez, mais je m'arrête ici pour cet exemple.&lt;/p&gt;
&lt;h2&gt;Fonctionnalités avancées&lt;/h2&gt;
&lt;p&gt;Avant de refermer cet article, il est intéressant de noter que ZX0 propose quelques fonctionnalités supplémentaires.&lt;/p&gt;
&lt;h3&gt;La compression à rebours&lt;/h3&gt;
&lt;p&gt;Plutôt que de compresser les données du début à la fin du fichier d'entrée, ZX0 permet de compresser les données en commençant par la fin du fichier d'entrée. L'algorithme est le même, sauf que le flux commence par la fin et que les références « arrières » sont « plus loin » en mémoire (puisque le début du flux est à la fin du fichier).&lt;/p&gt;
&lt;p&gt;Cela est intéressant dans des scénarios où les données compressées et décompressées se recouvrent (ce qui est tout à fait possible aussi avec la compression standard) et que l'on veut « viser » l'adresse mémoire la plus haute disponible.&lt;/p&gt;
&lt;p&gt;En effet, lors d'un recouvrement, l'algorithme à besoin d'un « décalage minimum » entre les deux flux de données (indiqué par le « delta » affiché lors de la compression). Pour bien comprendre ce que signifie ce delta et l'intérêt de la compression à rebours, le mieux est de consulter les diagrammes fournis dans le README.&lt;/p&gt;
&lt;h3&gt;Compression avec préfixe&lt;/h3&gt;
&lt;p&gt;Très pratique pour des décompressions « par morceaux », il est possible de fournir au compresseur un préfixe de données que l'on sait seront déjà présentes en mémoire lors de la décompression juste avant les nouvelles données à décompresser.&lt;/p&gt;
&lt;p&gt;Le compresseur pourra donc piocher les références dans ce préfixe, sans pour autant inclure ces données dans le flux compressé. Bien entendu, il faut garantir que ces données seront bien présentes en mémoire lors de la décompression, puisque le décompresseur va les référencer.&lt;/p&gt;
&lt;h3&gt;Mode rapide&lt;/h3&gt;
&lt;p&gt;Enfin, du fait de la recherche optimale, la compression avec ZX0 peut être assez lente. Le compresseur propose donc une option « rapide » pour diminuer le temps de compression. L'option &lt;code&gt;-q&lt;/code&gt; a pour effet de réduire fortement la fenêtre de recherche des références arrière qui est normalement de 32640 octets et passe à 2176 octets.&lt;/p&gt;
&lt;p&gt;La recherche optimale est toujours effectuée, mais en allant chercher beaucoup moins loin les blocs pouvant être référencés. Cela diminue fortement le temps de compression, mais potentiellement aussi le taux de compression.&lt;/p&gt;
&lt;p&gt;Pour l'exemple ci-dessus, dont la taille totale est bien inférieure à 2176 octets, cela ne change rien du tout. Ni en temps, ni en taille finale.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;ZX0 est un algorithme de compression assez populaire sur les machines 8 bits. Le code source est disponible, il est simple à mettre en oeuvre, le code de décompression est très compact. Il a même été porté sur d'autres processeurs que le Z80.&lt;/p&gt;
&lt;p&gt;Bien qu'un peu lent à compresser, le résultat de compression est bon et la décompression rapide. Ça en fait un très bon choix.&lt;/p&gt;
&lt;p&gt;J'espère avoir pu vous donner une idée des choix faits par cet algorithme de compression/décompression et de son fonctionnement. Pas de code source dans cet article, j'ai directement utilisé l'&lt;a href="https://github.com/einar-saukas/ZX0"&gt;implémentation officielle&lt;/a&gt;.&lt;/p&gt;</content><category term="Algorithmes"></category><category term="Compression"></category><category term="ZX0"></category></entry><entry><title>Compression de données, référencer les répétitions</title><link href="https://www.triceraprog.fr/compression-de-donnees-referencer-les-repetitions.html" rel="alternate"></link><published>2025-10-24T00:00:00+02:00</published><updated>2025-10-24T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-10-24:/compression-de-donnees-referencer-les-repetitions.html</id><summary type="html">&lt;p&gt;Dans l'&lt;a href="https://www.triceraprog.fr/compression-de-donnees-compter-les-repetitions.html"&gt;article précédent sur la compression&lt;/a&gt;, l'idée était de remplacer les successions d'éléments identiques par un couple (nombre de répétitions, valeur). Cela fonctionne bien avec des plages de données contenant un même élément, mais beaucoup moins bien lorsque les données changent fréquemment.&lt;/p&gt;
&lt;p&gt;La séquence suivante, par exemple, sera très mal compressée par cette méthode RLE :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En effet, cette séquence ne contient aucune répétition d'un élément unique. Chaque élément est différent du précédent. Avec la méthode RLE, on devrait écrire :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(1, .), (1, #), (1, .), (1, #), ... 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On peut avoir envie de se dire, avec cette séquence, que le motif à répéter est &lt;code&gt;.#&lt;/code&gt; et qu'on le répète 16 fois. Mais on pourrait aussi se dire que c'est 4 fois le motif &lt;code&gt;.#.#.#.#&lt;/code&gt;. Ou encore 2 fois le motif &lt;code&gt;.#.#.#.#.#.#.#.#&lt;/code&gt;. Dans tous les cas, il nous faudrait une sorte de dictionnaire pour référencer les motifs que l'on voudrait répéter.&lt;/p&gt;
&lt;p&gt;Et c'est une manière assez courante de …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans l'&lt;a href="https://www.triceraprog.fr/compression-de-donnees-compter-les-repetitions.html"&gt;article précédent sur la compression&lt;/a&gt;, l'idée était de remplacer les successions d'éléments identiques par un couple (nombre de répétitions, valeur). Cela fonctionne bien avec des plages de données contenant un même élément, mais beaucoup moins bien lorsque les données changent fréquemment.&lt;/p&gt;
&lt;p&gt;La séquence suivante, par exemple, sera très mal compressée par cette méthode RLE :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En effet, cette séquence ne contient aucune répétition d'un élément unique. Chaque élément est différent du précédent. Avec la méthode RLE, on devrait écrire :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(1, .), (1, #), (1, .), (1, #), ... 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On peut avoir envie de se dire, avec cette séquence, que le motif à répéter est &lt;code&gt;.#&lt;/code&gt; et qu'on le répète 16 fois. Mais on pourrait aussi se dire que c'est 4 fois le motif &lt;code&gt;.#.#.#.#&lt;/code&gt;. Ou encore 2 fois le motif &lt;code&gt;.#.#.#.#.#.#.#.#&lt;/code&gt;. Dans tous les cas, il nous faudrait une sorte de dictionnaire pour référencer les motifs que l'on voudrait répéter.&lt;/p&gt;
&lt;p&gt;Et c'est une manière assez courante de compresser des données : référencer un dictionnaire.&lt;/p&gt;
&lt;p&gt;Cependant, un dictionnaire, ça prend de la place. Et dans la compression que nous allons voir aujourd'hui, la méthode est d'utiliser les données elles-mêmes comme dictionnaire pour éviter de construire (et stocker) un dictionnaire à part. C'est la méthode LZ (Lempel-Ziv), du nom de ses inventeurs, ou en tout cas une manière dérivée de LZ.&lt;/p&gt;
&lt;h2&gt;Le dictionnaire&lt;/h2&gt;
&lt;p&gt;L'idée est la suivante : lorsque l'on en est à un point du flux de décompression, toutes les données précédemment décompressées sont disponibles en mémoire.&lt;/p&gt;
&lt;p&gt;Imaginons par exemple, avec la séquence précédente, que l'on a déjà décompressé les deux premiers caractères : &lt;code&gt;.#&lt;/code&gt;. On peut tout à fait commencer à référencer ce motif dans le flux à decompresser qui arrive. La séquence à décompresser suivante pourrait être « répète le motif de longueur 2 qui commence 2 positions avant ». Ce qui donnerait, une fois ajouté aux données déjà décompressées : &lt;code&gt;.#.#&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;À l'étape suivante, on pourrait avoir : « répète le motif de longueur 4 qui commence 4 positions avant ». On aurait à présent : &lt;code&gt;.#.#.#.#&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Et ainsi de suite.&lt;/p&gt;
&lt;h2&gt;Codage général&lt;/h2&gt;
&lt;p&gt;Ainsi, il nous faut construire un flux compressé qui est une suite d'éléments unitaires (des séquences qui n'ont pas encore été vues) et de références à des motifs déjà vus (avec une paire (position en amont, longueur)).&lt;/p&gt;
&lt;p&gt;Sans entrer dans une implémentation précise, pour le motif précédent, on pourrait avoir ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.# (suite d&amp;#39;éléments unitaires)
(-2,2) (référence au motif de longueur 2, 2 positions avant)
(-4,4) (référence au motif de longueur 4, 4 positions avant)
(-8,8) (référence au motif de longueur 8, 8 positions avant)
(-16,16) (référence au motif de longueur 16, 16 positions avant)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si on utilise un élément marqueur pour indiquer si ce qui suit est une suite d'éléments unitaires ou une référence, cela donnerait globalement 15 éléments pour représenter les 32 éléments de l'original. Soit une taille finale d'un peu plus de 40% de l'original.&lt;/p&gt;
&lt;p&gt;Pas mal.&lt;/p&gt;
&lt;p&gt;Note : en vrai, on ne référencera pas des motifs aussi petits que deux éléments, car le gain en taille ne serait pas suffisant. Avec ce codage simpliste, il faut au moins 4 éléments pour référencer un motif de manière efficace.&lt;/p&gt;
&lt;h2&gt;Méthode de compression&lt;/h2&gt;
&lt;p&gt;Afin de compresser un flux de données avec cette méthode, à chaque étape, il faut chercher dans le flux en entrée si le motif qui suit est présent dans les données précédentes. Et ce pour la longueur la plus grande possible.&lt;/p&gt;
&lt;p&gt;Pour l'exemple, lorsque l'on commence le flux, le premier caractère est un &lt;code&gt;.&lt;/code&gt;. Ce caractère n'est pas encore dans les données présentes (puisque c'est le premier). On l'écrit donc comme élément unitaire dans le flux compressé. De même pour le caractère suivant, un &lt;code&gt;#&lt;/code&gt;, que l'on écrit aussi en tant qu'élément unitaires à la suite du premier.&lt;/p&gt;
&lt;p&gt;Pour la suite, on a dans le buffer à traiter une séquence &lt;code&gt;.#.#.#.#...&lt;/code&gt;. On cherche le plus long motif qui est déjà dans les données. Ici, c'est &lt;code&gt;.#&lt;/code&gt;, que l'on trouve à la position -2 (2 positions avant). On écrit donc la référence &lt;code&gt;(-2,2)&lt;/code&gt; dans le flux compressé.&lt;/p&gt;
&lt;p&gt;Et ainsi de suite, jusqu'à la fin du flux d'entrée.&lt;/p&gt;
&lt;h2&gt;Essai sur la séquence de l'article précédent&lt;/h2&gt;
&lt;p&gt;Je reprends l'image en niveaux de gris de l'article précédent sur la compression RLE :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;................
....#######.....
..##@@@@@@@##...
.##@OOOOOOO@##..
.#@OoooooooO@#..
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
.#@OoooooooO@#..
.##@OOOOOOO@##..
..##@@@@@@@##...
....#######.....
................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dans le cas RLE, j'avais supprimé les sauts de ligne pour ne garder qu'une suite d'éléments et profiter des plages formées par la fin d'une ligne et le début de la ligne suivante. Ici, je vais les garder, c'est beaucoup moins génant puisque la méthode compresse les séquences répétées.&lt;/p&gt;
&lt;p&gt;Passé par l'algorithme décrit précédemment, voici ce que l'on obtient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  Littéral:  (0, &amp;#39;....&amp;#39;)
  Référence: (1, (-4, 4))
  Référence: (1, (-8, 8))
  Littéral:  (0, &amp;#39;\n&amp;#39;)
  Référence: (1, (-5, 4))
  Littéral:  (0, &amp;#39;#######&amp;#39;)
  Référence: (1, (-17, 8))
  Littéral:  (0, &amp;#39;##@@@@@@@&amp;#39;)
  Référence: (1, (-19, 5))
  Littéral:  (0, &amp;#39;\n&amp;#39;)
  Référence: (1, (-16, 4))
  Littéral:  (0, &amp;#39;OOOOOOO&amp;#39;)
  Référence: (1, (-18, 5))
  Littéral:  (0, &amp;#39;\n.#@OoooooooO@&amp;#39;)
  Référence: (1, (-17, 4))
  Référence: (1, (-16, 10))
  Référence: (1, (-18, 6))
  Référence: (1, (-17, 17))
  Référence: (1, (-34, 34))
  Référence: (1, (-34, 34))
  Littéral:  (0, &amp;#39;\n.&amp;#39;)
  Référence: (1, (-18, 10))
  Référence: (1, (-16, 4))
  Référence: (1, (-17, 4))
  Littéral:  (0, &amp;#39;#@OOOOOOO@#&amp;#39;)
  Référence: (1, (-17, 5))
  Référence: (1, (-18, 4))
  Littéral:  (0, &amp;#39;@@@@@&amp;#39;)
  Référence: (1, (-16, 5))
  Référence: (1, (-17, 4))
  Référence: (1, (-19, 4))
  Littéral:  (0, &amp;#39;###&amp;#39;)
  Référence: (1, (-15, 5))
  Référence: (1, (-17, 7))
  Référence: (1, (-10, 5))
  Référence: (1, (-7, 7))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui donne une entrée de 272 éléments (256 éléments plus les retours chariots) compressée en 156 éléments, soit environ 57% de la taille initiale.&lt;/p&gt;
&lt;p&gt;C'est légèrement moins bien que la méthode RLE pour ce cas qui avait été construit spécialement pour que ça fonctionne bien en RLE. Donc... ce n'est pas mal du tout (et on a les retours chariots en bonus).&lt;/p&gt;
&lt;h2&gt;Peut-on faire mieux ?&lt;/h2&gt;
&lt;p&gt;Comme la dernière fois, pour le moment, on a une implémentation assez générique que l'on compte en éléments. Si on considère que ces éléments sont en fait des octets, il y a beaucoup de place perdue, ne serait-ce que par l'utilisation d'un octet complet pour différencier les littéraux des références.&lt;/p&gt;
&lt;p&gt;De même, on peut se poser la question de l'utilisation d'un octet complet pour la position et la longueur dans les références, alors que les plus grandes valeurs absolues utilisées dans cet exemple sont 34. On pourrait limiter ces valeurs à 4 bits chacun pour coder les deux valeurs sur un seul octet.&lt;/p&gt;
&lt;p&gt;J'ai fait l'essai... et ce n'est pas brillant. La compression est alors assez mauvaise, passant alors à un résultat compressé de 225 octets.&lt;/p&gt;
&lt;p&gt;Par contre, en utilisant une valeur maximale de 32, alors on retrouve le taux de compression précédente.&lt;/p&gt;
&lt;p&gt;Mais plus que la valeur maximale, il est intéressant de s'intéresser à la répartition des valeurs utilisées. &lt;/p&gt;
&lt;p&gt;Grâce à un petit programme d'analyse, voici ce que j'obtiens pour cet exemple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Distribution des longueurs de référence:
  Valeur | Occurrences | Histogramme
  -------|-------------|------------
       4 |           9 | #########
       5 |           6 | ######
       6 |           1 | #
       7 |           2 | ##
       8 |           2 | ##
      10 |           2 | ##
      17 |           1 | #
      34 |           2 | ##
  Statistiques: Min=4, Max=34, Moyenne=8.28, Médiane=5.0

Distribution des positions de référence (valeurs absolues):
  Valeur | Occurrences | Histogramme
  -------|-------------|------------
       4 |           1 | #
       5 |           1 | #
       7 |           1 | #
       8 |           1 | #
      10 |           1 | #
      15 |           1 | #
      16 |           4 | ####
      17 |           7 | #######
      18 |           4 | ####
      19 |           2 | ##
      34 |           2 | ##
  Statistiques: Min=4, Max=34, Moyenne=16.40, Médiane=17.0

Distribution combinée (longueurs + positions):
  Valeur | Occurrences | Histogramme
  -------|-------------|------------
       4 |          10 | ##########
       5 |           7 | #######
       6 |           1 | #
       7 |           3 | ###
       8 |           3 | ###
      10 |           3 | ###
      15 |           1 | #
      16 |           4 | ####
      17 |           8 | ########
      18 |           4 | ####
      19 |           2 | ##
      34 |           4 | ####
  Statistiques: Min=4, Max=34, Moyenne=12.34, Médiane=10.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On peut remarquer que même si l'amplitude des valeurs est grande (de 4 à 34), la moitié des valeurs utilisées sont plutôt petites (entre 4 et 10), et la moyenne n'est pas très élevée non plus. Est-ce que ça ne vaudrait pas le coup d'utiliser un codage variable pour ces valeurs, afin de privilégier les petites valeurs ?&lt;/p&gt;
&lt;p&gt;C'est sur cette piste que part l'algorithme ZX0, que nous verrons dans un prochain article.&lt;/p&gt;
&lt;p&gt;À noter que une piste est possible en calculant une représentation des valeurs adaptée à leurs distributions. Pour cela, on peut utiliser un codage de Huffman, et c'est la piste utilisée par l'algorithme DEFLATE (utilisé dans les fichiers ZIP et PNG entre autres).&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Avec cette méthode de compression par références dans un dictionnaire construit, il est possible de compresser des flux de données avec beaucoup plus de variations qu'avec la méthode RLE. LZ est en fait la base de beaucoup d'algorithmes de compression sans pertes. Le temps de compression est « élevé » car il est nécessaire de chercher des motifs dans des plages de données (la recherche peut d'ailleurs être paramétrée selon ce que l'on veut). La décompression est en revanche assez rapide, il n'y a pas de calculs ou d'opérations complexes à faire.&lt;/p&gt;
&lt;h3&gt;Supplément&lt;/h3&gt;
&lt;p&gt;Le code que j'ai utilisé lors de l'écriture pour vérifier les exemples est &lt;a href="https://www.triceraprog.fr/files/202507/20250728-lz.py"&gt;disponible ici&lt;/a&gt;.&lt;/p&gt;</content><category term="Algorithmes"></category><category term="Compression"></category><category term="LZ"></category></entry><entry><title>Briques Stellaires, jeu pour PHC-25</title><link href="https://www.triceraprog.fr/briques-stellaires-jeu-pour-phc-25.html" rel="alternate"></link><published>2025-10-12T00:00:00+02:00</published><updated>2025-10-12T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-10-12:/briques-stellaires-jeu-pour-phc-25.html</id><summary type="html">&lt;p&gt;Avec la publication de la version 0.9 de &lt;a href="https://mokona78.itch.io/le-casseur-de-briques"&gt;Briques Stellaires&lt;/a&gt;, ma contribution à la Game Jam « Retro Programmers United for Obscure Systems » session PHC-25 est l'occasion de revenir sur cette session et ma proposition.&lt;/p&gt;
&lt;p&gt;Vu les caractéristiques modestes mais sympathiques du PHC-25, j'ai eu envie de faire un jeu plutôt action. Exercice toujours délicat pour ces machines peu utilisées dont les émulateurs sont très très perfectibles, pour ne pas dire à côté de la plaque. Mais ayant eu un accès temporaire à la machine, je ne me suis dit que... allez pourquoi pas.&lt;/p&gt;
&lt;p&gt;J'étais parti sur un twist du classique casse-brique. Au final, le temps passant toujours à sa proverbiale vitesse, le jeu est... un casse-brique tout ce qu'il y a de plus standard.&lt;/p&gt;
&lt;p&gt;Mais voyons un peu les détails potentiellement intéressants du développement.&lt;/p&gt;
&lt;h2&gt;L'environnement de développement&lt;/h2&gt;
&lt;p&gt;Je suis parti pour cette contribution sur un développement en assembleur Z80 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Avec la publication de la version 0.9 de &lt;a href="https://mokona78.itch.io/le-casseur-de-briques"&gt;Briques Stellaires&lt;/a&gt;, ma contribution à la Game Jam « Retro Programmers United for Obscure Systems » session PHC-25 est l'occasion de revenir sur cette session et ma proposition.&lt;/p&gt;
&lt;p&gt;Vu les caractéristiques modestes mais sympathiques du PHC-25, j'ai eu envie de faire un jeu plutôt action. Exercice toujours délicat pour ces machines peu utilisées dont les émulateurs sont très très perfectibles, pour ne pas dire à côté de la plaque. Mais ayant eu un accès temporaire à la machine, je ne me suis dit que... allez pourquoi pas.&lt;/p&gt;
&lt;p&gt;J'étais parti sur un twist du classique casse-brique. Au final, le temps passant toujours à sa proverbiale vitesse, le jeu est... un casse-brique tout ce qu'il y a de plus standard.&lt;/p&gt;
&lt;p&gt;Mais voyons un peu les détails potentiellement intéressants du développement.&lt;/p&gt;
&lt;h2&gt;L'environnement de développement&lt;/h2&gt;
&lt;p&gt;Je suis parti pour cette contribution sur un développement en assembleur Z80. Je le regretterai plus d'une fois, quand il m'a fallu mettre au point la routine de rebond. Mais comme je savais que cela serait potentiellement compliqué avec des regressions très probables, j'ai cherché dès le début un environnement me permettant de faire des tests unitaires.&lt;/p&gt;
&lt;p&gt;J'avais déjà mis en place des tests unitaires pour le &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-7.html"&gt;jeu sur VG5000&lt;/a&gt;, cependant, ils devaient être lancés en même temps que l'exécutable principal. Puis c'était un bricolage rapide qui manquait de fonctionnalités.&lt;/p&gt;
&lt;p&gt;Je suis donc parti sur un environnement déjà fait : &lt;a href="https://github.com/maziac/DeZog"&gt;DeZog&lt;/a&gt;. C'est un environnement intégré à Visual Code, initialement fait et spécialisé pour le ZX Spectrum, mais qui peut être utilisé comme environnement Z80 générique. DeZog supporte l'exécution de tests unitaires, avec de nombreuses assertions, le tout pouvant tourner dans un émulateur interne.&lt;/p&gt;
&lt;p&gt;DeZog implémente aussi un lien de debuggage avec différents émulateurs, dont MAME. Parfait pour la mise au point.&lt;/p&gt;
&lt;h2&gt;Les choix pour le PHC-25&lt;/h2&gt;
&lt;p&gt;Il y a plusieurs modes graphiques sur le PHC-25, qui utilise comme VDP un clone du MC6847 avec le maximum de RAM vidéo supportée. On peut considérer qu'il y a deux grandes classes de modes graphiques : des modes alpha-numérique/semi-graphique, et des modes bitmap, avec des variations dans les contraintes.&lt;/p&gt;
&lt;p&gt;Pour le jeu, j'ai choisi un mode alpha-numérique/semi-graphique qui permet d'avoir une résolution en « gros pixels » de 68x48. C'est suffisant pour un casse-brique.&lt;/p&gt;
&lt;p&gt;Pas de son ni de joystick, car le PHC-25 a besoin d'une extension pour cela. Et puis... le temps, toujours le temps.&lt;/p&gt;
&lt;h2&gt;Liste d'affichage&lt;/h2&gt;
&lt;p&gt;Sur le PHC-25, le MC6847 utilise pour RAM vidéo une mémoire directement accessible par le bus du Z80. Et lorsqu'il y a arbitrage, c'est le Z80 qui gagne. Ainsi, des accès à la mémoire vidéo pendant le rafraîchissement de l'écran provoquent des parasites bien visibles.&lt;/p&gt;
&lt;p&gt;Il faut donc absolument éviter d'accéder à la mémoire vidéo pendant le rafraîchissement. C'est d'ailleurs ce que fait la ROM du PHC-25 où les commandes graphiques sont appliquées progressivement pendant l'interruption (INT), branchée sur VBLANK.&lt;/p&gt;
&lt;p&gt;Et c'est aussi ce que je fais dans Briques Stellaires. Après avoir passé le Z80 en mode d'interruption IM2 (il n'y a pas de possibilité prévue par le système pour s'accrocher à l'interruption en IM1), je déroule des listes d'affichages au moment de l'interruption. Ces listes d'affichages sont elles-mêmes construites pendant le reste du temps, par des accès en RAM normale exclusivement.&lt;/p&gt;
&lt;p&gt;Ces listes d'affichages sont de type : afficher une brique, effacer une brique, effacer et afficher la balle,...&lt;/p&gt;
&lt;p&gt;Le traitement de l'affichage du contour de jeu ainsi que des pages de titre et de score est un peu différent : je prépare l'affichage dans un buffer auxiliaire de la taille de l'écran, puis je copie ce buffer en RAM vidéo pendant le VBLANK, petit à petit.&lt;/p&gt;
&lt;p&gt;L'affichage de la raquette est similaire : il est fait dans le buffer auxiliaire, puis la ligne correspondante est copiée en RAM vidéo pendant le VBLANK systématiquement. C'est un choix que j'ai fait assez tôt car je ne savais pas trop à quelle vitesse la raquette allait bouger et je voulais un système simple, avec un temps fixe pendant la VBLANK.&lt;/p&gt;
&lt;h2&gt;La physique&lt;/h2&gt;
&lt;p&gt;Voilà qui m'a pris plus de temps que prévu. Je savais que cela allait être délicat, avec des rebonds particuliers et des vitesses non entières. En effet, les coordonnées de la balle sont en virgule fixe, 8 bits pour la partie entière, 8 bits pour la partie fractionnaire. Là encore, c'est un choix que j'ai fait assez tôt, car je ne savais pas quelle vitesse de balle allait être intéressante. Et avec la résolution de l'écran, des vitesses entières allaient donner des mouvements bien trop rapides.&lt;/p&gt;
&lt;p&gt;Pour les collisions, je trace une ligne entre la position précédente et la position actuelle de la balle, point par point, en testant les collisions avec les briques, la raquette et les bords. La ligne ne fait rarement plus de deux pixels, mais là encore, cela permet de gérer différentes vitesses, donc des vitesses supérieures à 1 par axe.&lt;/p&gt;
&lt;p&gt;Par contre, j'ai simplifié : une collision arrête immédiatement la trajectoire. Je ne cherche pas à compléter le mouvement restant après le rebond. Aux vitesses utilisées au final par le jeu, la différence est imperceptible.&lt;/p&gt;
&lt;h2&gt;La gestion de variables&lt;/h2&gt;
&lt;p&gt;Puisque le jeu est sur cassette, il est toujours intéressant de minimiser la taille des données encodées. Pour gagner de la place, j'ai implémenté avec le système de STRUCT et de macros de sasmjsplus qui permet de « déclarer » des variables près du code, mais qui sont toutes regroupées à la fin du code lors de l'assemblage.&lt;/p&gt;
&lt;p&gt;Au démarrage du programme, je fixe toute la zone à zéro. Un peu à la manière d'une section &lt;code&gt;BSS&lt;/code&gt; dans un programme C.&lt;/p&gt;
&lt;p&gt;J'avais envisagé d'utiliser un système de compression, surtout pour les niveaux. Mais le manque de temps et finalement la taille relativement modeste du programme (moins de 3ko) m'ont fait abandonner cette idée.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Briques Stellaires est un casse-brique très rudimentaire. Et autant que je puisse m'en souvenir, c'est la première fois que je programme un casse-brique. Je me suis perdu dans la gestion de collisions et malgré les tests unitaires qui m'ont gardé sur les rails, j'y ai passé beaucoup de temps. Un peu avant la date limite de la jam, j'ai coupé dans toutes mes idées un peu originales pour me concentrer sur l'essentiel : un jeu auquel on peut jouer.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran de jeu de Briques Stellaires" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202510/Briques-Stellaires-0.9-750.jpeg"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="PHC-25"></category><category term="Jeu"></category><category term="RPUfOS"></category></entry><entry><title>Compression de données, compter les répétitions</title><link href="https://www.triceraprog.fr/compression-de-donnees-compter-les-repetitions.html" rel="alternate"></link><published>2025-07-28T00:00:00+02:00</published><updated>2025-07-28T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-07-28:/compression-de-donnees-compter-les-repetitions.html</id><summary type="html">&lt;p&gt;Dès le début de l'informatique, même si je ne saurais pas dater exactement quand, il a été question de stocker ou transmettre des données de manière efficace. Comment stocker ou transmettre un maximum de données avec un minimum d'espace ou de bande passante ? La compression de données répond à cette problématique avec des algorithmes qui repèrent l'information redondante pour la représenter de manière plus concise, ou bien qui éliminent des données jugées'(selon certains critères) moins utiles que d'autres.&lt;/p&gt;
&lt;p&gt;Dans ce premier article, nous allons voir ce que j'imagine être la plus simple des méthodes et qui vient souvent à l'esprit en premier lorsque l'on découvre le sujet : la compression RLE (Run Length Encoding).&lt;/p&gt;
&lt;h2&gt;Le flux d'entrée&lt;/h2&gt;
&lt;p&gt;Imaginons une image en niveaux de gris que l'on pourrait représenter de cette manière :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;................
....#######.....
..##@@@@@@@##...
.##@OOOOOOO@##..
.#@OoooooooO@#..
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
.#@OoooooooO@#..
.##@OOOOOOO@##..
..##@@@@@@@##...
....#######.....
................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les niveaux de gris sont représentés par des caractères …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dès le début de l'informatique, même si je ne saurais pas dater exactement quand, il a été question de stocker ou transmettre des données de manière efficace. Comment stocker ou transmettre un maximum de données avec un minimum d'espace ou de bande passante ? La compression de données répond à cette problématique avec des algorithmes qui repèrent l'information redondante pour la représenter de manière plus concise, ou bien qui éliminent des données jugées'(selon certains critères) moins utiles que d'autres.&lt;/p&gt;
&lt;p&gt;Dans ce premier article, nous allons voir ce que j'imagine être la plus simple des méthodes et qui vient souvent à l'esprit en premier lorsque l'on découvre le sujet : la compression RLE (Run Length Encoding).&lt;/p&gt;
&lt;h2&gt;Le flux d'entrée&lt;/h2&gt;
&lt;p&gt;Imaginons une image en niveaux de gris que l'on pourrait représenter de cette manière :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;................
....#######.....
..##@@@@@@@##...
.##@OOOOOOO@##..
.#@OoooooooO@#..
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
#@OoooooooooO@#.
.#@OoooooooO@#..
.##@OOOOOOO@##..
..##@@@@@@@##...
....#######.....
................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les niveaux de gris sont représentés par des caractères, et chaque caractère représente un pixel de l'image. L'image est de 16 lignes et 16 colonnes, soit 256 éléments. Ne nous occupons pas pour le moment de comment coder ces éléments. Ce sont juste des éléments.&lt;/p&gt;
&lt;h2&gt;L'idée générale&lt;/h2&gt;
&lt;p&gt;L'idée de la compression RLE vient de la constatation rapide qu'il existe des suites de données identiques dans les données, et que l'on peut même facilement énoncer. Par exemple, sur la première ligne, on peut dire qu'il y a 16 fois la valeur &lt;code&gt;.&lt;/code&gt;. Sur la deuxième ligne, on peut dire qu'il y a 4 fois la valeur &lt;code&gt;.&lt;/code&gt; puis 7 fois la valeur &lt;code&gt;#&lt;/code&gt; puis 5 fois la valeur &lt;code&gt;.&lt;/code&gt;. Et ainsi de suite.&lt;/p&gt;
&lt;p&gt;C'est le principe de la compression RLE : on va remplacer les suites d'éléments identiques par deux éléments : le nombre de répétitions et la valeur répétée. Par exemple, la première ligne devient &lt;code&gt;(16, '.')&lt;/code&gt;, la deuxième ligne devient &lt;code&gt;(4, '.'), (7, '#'), (5, '.')&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Voilà ce que cela donne pour l'image complète, si on met toutes les lignes bout à bout (sans les sauts de ligne) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(20,.), (7,#), (7,.), (2,#), (7,@), (2,#), (4,.), (2,#), (1,@), (7,O), (1,@), (2,#), (3,.), (1,#), (1,@), (1,O), (7,o), (1,O), (1,@), (1,#), (2,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (1,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (1,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (1,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (1,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (1,.), (1,#), (1,@), (1,O), (9,o), (1,O), (1,@), (1,#), (2,.), (1,#), (1,@), (1,O), (7,o), (1,O), (1,@), (1,#), (3,.), (2,#), (1,@), (7,O), (1,@), (2,#), (4,.), (2,#), (7,@), (2,#), (7,.), (7,#), (21,.)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui donne 89 couples de valeurs, soit 178 éléments au total. Contre 256 éléments dans l'image d'origine. On a donc bien réduit le nombre d'éléments nécessaires pour représenter l'image.&lt;/p&gt;
&lt;p&gt;Mais attention, ce qui permet la réduction, ce sont les suites de même valeur.&lt;/p&gt;
&lt;p&gt;Si les données sont constituées de valeurs souvent changeantes, la compression ne va pas bien fonctionner, voire donner plus d´éléments en sortie. Par exemple, si l'image n’était constituée que de valeurs différentes de leurs précédentes, on devrait à chaque fois écrire &lt;code&gt;(1, élément)&lt;/code&gt;, et donc au final doubler le nombre d'éléments nécessaires. Pas très efficace.&lt;/p&gt;
&lt;h2&gt;Codage du flux compressé&lt;/h2&gt;
&lt;p&gt;Jusqu'à maintenant, on n'a parlé que d'éléments. Cependant, ces éléments doivent être codés d'une manière ou d'une autre pour être stockés sur la machine. Par exemple, on peut considérer assez facilement que le flux d'entrée est codé en caractères sur 8 bits. C'est trop pour 4 valeurs différentes (2 bits sont suffisants), mais on peut imaginer avoir d'autres valeurs sur les 256 possibles dans d'autres images.&lt;/p&gt;
&lt;p&gt;On va donc garder cette représentation en 8 bits pour les éléments valeurs. Même en sortie.&lt;/p&gt;
&lt;p&gt;Pour le nombre de répétitions, il faut faire un choix sur le plus grand nombre de répétitions possibles. Ces choix vont dépendre de la nature des données. Pour un premier choix, on va faire simple : 256 répétition maximum. Une image de 16x16 éléments monochrome serait donc codée par deux valeurs en 8 bits : (0, valeur). En effet, comme une répétition de 0 n'a pas de sens, on se sert du 0 pour coder 256.&lt;/p&gt;
&lt;p&gt;Deux octets au lieu de 256, c'est pas mal. Mais on peut aussi imaginer que les images monochromes ne sont pas représentatives.&lt;/p&gt;
&lt;p&gt;En prenant un octet pour les répétitions et un octet pour la valeur, le codage et le décodage sont très simples et la taille pour l'image exemple est de 178 octets, soit 178 octets pour 256 éléments.&lt;/p&gt;
&lt;h2&gt;Peut-on faire mieux ?&lt;/h2&gt;
&lt;p&gt;Oui. Il y a plusieurs manières différentes de coder un flux compressé RLE. La méthode indiquée précédemment est la plus simple. Mais on peut en imaginer d'autres.&lt;/p&gt;
&lt;p&gt;Par exemple, on peut réserver une plage de nombres dans l'indication des répétitions pour indiquer un nombre d'octets à suivre qui seront recopiés tels quels (parce qu'ils ne présentaient pas de répétition en entrée).&lt;/p&gt;
&lt;p&gt;Par exemple, sur un morceau en entrée comme :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;....#.#.#.....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On code les valeurs&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(r4, &amp;#39;.&amp;#39;), (c5, &amp;#39;#.#.#&amp;#39;), (r3, &amp;#39;.&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Où &lt;code&gt;r&lt;/code&gt; signifie "répétition" et &lt;code&gt;c&lt;/code&gt; signifie "copie".&lt;/p&gt;
&lt;p&gt;D'un point de vue codage, on peut choisir que les valeurs &lt;code&gt;0&lt;/code&gt; à &lt;code&gt;127&lt;/code&gt; représentent des répétitions, et les valeurs &lt;code&gt;128&lt;/code&gt; à &lt;code&gt;255&lt;/code&gt; représentent des copies.&lt;/p&gt;
&lt;p&gt;Voilà ce que cela donne pour l'image complète avec cette méthode :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(20,.), (7,#), (7,.), (2,#), (7,@), (2,#), (4,.), (2,#), (129,@), (7,O), (129,@), (2,#), (3,.), (131,#@O), (7,o), (131,O@#), (2,.), (131,#@O), (9,o), (135,O@#.#@O), (9,o), (135,O@#.#@O), (9,o), (135,O@#.#@O), (9,o), (135,O@#.#@O), (9,o), (135,O@#.#@O), (9,o), (131,O@#), (2,.), (131,#@O), (7,o), (131,O@#), (3,.), (2,#), (129,@), (7,O), (129,@), (2,#), (4,.), (2,#), (7,@), (2,#), (7,.), (7,#), (21,.)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;47 éléments au lieu de 89. Des éléments de taille variable cependant. Ici la taille en octets est de 136 plutôt que 178. Ce qui est un nouveau gain (au prix d'une toute petite complexité supplémentaire à traiter à la décompression)&lt;/p&gt;
&lt;h2&gt;Peut-on faire encore mieux ?&lt;/h2&gt;
&lt;p&gt;Vous pouvez trouver d'autres manières de coder un flux compressé RLE. En fonction de la plateforme, de la nature des données, de la taille des éléments, etc, il est possible de trouver des ajustements et des variations qui permettent de gagner de la place.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;La compression RLE est une méthode simple à comprendre et à implémenter. Le temps de compression et de décompression sont très rapides car les calculs sont très simples.&lt;/p&gt;
&lt;p&gt;Elle peut donner de bons résultats sur des données avec beaucoup de plages de même valeur. C'est aussi une méthode non destructive : une fois décompressées, les données sont identiques à l'original avant compression.&lt;/p&gt;
&lt;p&gt;Dans un prochain article, nous verrons une autre méthode de compression classique et qui fonctionne bien sur des répétitions de motifs.&lt;/p&gt;
&lt;h3&gt;Supplément&lt;/h3&gt;
&lt;p&gt;Le code que j'ai utilisé lors de l'écriture pour vérifier les exemples est &lt;a href="https://www.triceraprog.fr/files/202507/20250728-rle.py"&gt;disponible ici&lt;/a&gt;.&lt;/p&gt;</content><category term="Algorithmes"></category><category term="Compression"></category><category term="RLE"></category></entry><entry><title>PHC-25, et Z80 en IM 2</title><link href="https://www.triceraprog.fr/phc-25-et-z80-en-im-2.html" rel="alternate"></link><published>2025-06-09T00:00:00+02:00</published><updated>2025-06-09T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-06-09:/phc-25-et-z80-en-im-2.html</id><summary type="html">&lt;p&gt;Ça y est, la nouvelle saison des Retro Programmers United for Obscure System a démarré. Et cette fois, c'est le &lt;a href="http://www.phc25.com/"&gt;PHC-25&lt;/a&gt; qui est à l'honneur. Un ordinateur de Sanyo à base de Z80 (d'un clone plus précisément) et d'un MC6845 (... un clone aussi) et plutôt bien fourni en mémoire vive pour cette classe de machines : 16 ko de RAM et 6 ko pour la VRAM, accessible directement par le Z80 (avec des contraintes de timing si on veut éviter des parasites graphiques).&lt;/p&gt;
&lt;p&gt;Bien entendu, comme toutes les machines concernées par cette game jam, le PHC-25 est un ordinateur qui n'a pas une grande logithèque, et pas non plus beaucoup d'activité ni de documentation. C'est le principe.&lt;/p&gt;
&lt;p&gt;Pour cette Jam, je suis parti sur l'idée que le programme sera en assembleur. Certains vont certainement encore faire des miracles en BASIC, mais ce n'est pas ma tasse de thé, même si je …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ça y est, la nouvelle saison des Retro Programmers United for Obscure System a démarré. Et cette fois, c'est le &lt;a href="http://www.phc25.com/"&gt;PHC-25&lt;/a&gt; qui est à l'honneur. Un ordinateur de Sanyo à base de Z80 (d'un clone plus précisément) et d'un MC6845 (... un clone aussi) et plutôt bien fourni en mémoire vive pour cette classe de machines : 16 ko de RAM et 6 ko pour la VRAM, accessible directement par le Z80 (avec des contraintes de timing si on veut éviter des parasites graphiques).&lt;/p&gt;
&lt;p&gt;Bien entendu, comme toutes les machines concernées par cette game jam, le PHC-25 est un ordinateur qui n'a pas une grande logithèque, et pas non plus beaucoup d'activité ni de documentation. C'est le principe.&lt;/p&gt;
&lt;p&gt;Pour cette Jam, je suis parti sur l'idée que le programme sera en assembleur. Certains vont certainement encore faire des miracles en BASIC, mais ce n'est pas ma tasse de thé, même si je l'ai enté par le passé. Avec la communauté des participants, nous nous sommes donc penchés sur la compréhension de la machine. Pas facile là encore car nous ne sommes pas nombreux à avoir un PHC-25, il faut donc continuellement passer par les bonnes âmes qui peuvent lancer nos tests.&lt;/p&gt;
&lt;p&gt;Après quelques jours, j'ai commencé à mettre mes notes, un programme d'exemple et une manière de packager un programme assembleur sur &lt;a href="https://gitlab.com/mokona/phc25_tools/-/tree/main?ref_type=heads"&gt;gitlab&lt;/a&gt;. C'est principalement le résultat d'un travail de recherche collectif.&lt;/p&gt;
&lt;p&gt;J'ai pu aussi corriger deux petits trucs dans MAME, qui reste loin d'être parfait pour le PHC-25, mais qui est un tout petit peu mieux qu'il y a deux semaines. La machine reste assez simple et peu exotique par rapport à d'autres que l'on a traitées auparavant.&lt;/p&gt;
&lt;h1&gt;IM 2&lt;/h1&gt;
&lt;p&gt;Lors de nos discussions et analyse, il est apparu que la ROM du PHC-25 lançait une ISR (Interrupt Service Routine) à chaque synchronisation verticale. C'est classique. Pendant cette ISR, la ROM fait les modifications en VRAM en fonction des modifications d'affichages demandées par le BASIC, cela pour éviter les parasites graphiques. Il y a aussi une lecture du clavier, la gestion du son,...&lt;/p&gt;
&lt;p&gt;Mais aucune possibilité de reroutage. Là où l'on trouve dans d'autres machines un « hook » sur lequel on peut attacher son propre code, ici, il n'y a rien. &lt;/p&gt;
&lt;p&gt;La proposition a été faite de passer le Z80 en IM 2, afin de gérer entièrement l'interruption. Cela fonctionne, et ce que je vais expliquer ici. À noter que l'IM 2 est une fonctionnalité du Z80 et que la grande partie de ce qui suit est valable pour d'autres machines similaires à base de Z80.&lt;/p&gt;
&lt;h2&gt;Interrupt Mode ?&lt;/h2&gt;
&lt;p&gt;Le Z80 peut fonctionner selon trois modes d'interruption. Le mode 0 est le mode par défaut. C'est un mode reliquat du 8080. Dans ce mode, lorsque l'interruption est reçue, le Z80 va lire l'instruction suivante qui va lui être présentée depuis un mécanisme externe. Généralement, c'est une instruction &lt;code&gt;RST&lt;/code&gt; qui est utilisée, afin de brancher à l'une des routines &lt;em&gt;RESTART&lt;/em&gt; du Z80.&lt;/p&gt;
&lt;p&gt;Mais la plupart, si ce n'est toutes, des machines familiales à base de Z80 utilisent le mode 1, qui est beaucoup plus simple. Dans ce mode, lorsque l'interruption est reçue, le Z80 branche tout simplement à l'adresse fixe 0x0038, à partir de laquelle on place l'ISR. C'est ce que fait le PHC-25. Mais comme son ISR n'offre pas de moyen d'extension, on est vite limité si on veut prendre les choses en main.&lt;/p&gt;
&lt;p&gt;Le mode 2, ou IM 2, est un mode qui est normalement fait pour être utilisé avec un contrôleur d'interruption externe. Dans ce mode, l'interruption est suivie d'une valeur paire sur 8 bits. Cette valeur est utilisée comme index dans une table d'adresses d'ISRs. Le Z80 va lire l'adresse de l'ISR à partir de cette table, puis il va brancher à cette adresse.&lt;/p&gt;
&lt;p&gt;Cependant, le PHC-25 n'a pas de contrôleur d'interruption externe. Ainsi, la valeur reçue peut être un peu n'importe quoi (et même pas forcément paire). L'astuce consiste donc à utiliser une table dont toutes les entrées pointent vers la même adresse. Comme l'index peut-être paire ou impaire, cela implique une contrainte supplémentaire : l'adresse de l'ISR doit être composée de deux octets identiques ($FEFE par exemple). Autre petit piège, comme la valeur 255 peut-être reçue, la table doit contenir 257 octets, et non pas 256 uniquement.&lt;/p&gt;
&lt;h2&gt;En pratique&lt;/h2&gt;
&lt;p&gt;Voici le code commenté pour mettre en place l'IM 2 sur le PHC-25 :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Code pour l&amp;#39;assembleur SjASMPlus&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;$c009&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Adresse de départ du programme.&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; On commence à $C009, car c&amp;#39;est l&amp;#39;adresse de départ&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; avec le chargeur BASIC utilisé. Mais vous pouvez&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; adapter.&lt;/span&gt;

&lt;span class="nl"&gt;start:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;install_im2&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Le programme démarre par l&amp;#39;installation de l&amp;#39;IM 2&lt;/span&gt;

&lt;span class="nl"&gt;infinite_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;halt&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Attente de l&amp;#39;interruption&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;infinite_loop&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Puis boucle&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Installation de l&amp;#39;IM 2&lt;/span&gt;
&lt;span class="nl"&gt;install_im2:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;di&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; On commence par désactiver les interruptions&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Comme on va modifier la configuration,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; on ne veut pas qu&amp;#39;elles se déclenchent pendant ce temps&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Déplace la pile&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Peut-être optionnel, mais comme ça, on sait où elle est&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; On ne pourra pas retourner dans la ROM, mais de toute façon&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; elle ne fonctionnerait pas en IM2.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; sauve l&amp;#39;adresse de retour de la routine&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$fffe&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; place la pile à $FFFE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Pousse l&amp;#39;adresse de retour sur la pile&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="c1"&gt;; À présent, le RET peut retourner à l&amp;#39;endroit de l&amp;#39;appel&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Remplit la table des vecteurs d&amp;#39;interruption&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$fe00&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La table démarre en $FE00&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;l&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;de&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Idiome de remplissage de mémoire&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; De longueur 257 octets&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$fd&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Contenant l&amp;#39;adresse $fdfd&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ldir&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;; Remplissage de mémoire&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; On place un saut vers l&amp;#39;ISR dans le vecteur d&amp;#39;interruption&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$fdfd&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; L&amp;#39;adresse du vecteur&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$c3&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Instruction de saut (JP) vers xxxx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;isr&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; L&amp;#39;adresse de l&amp;#39;ISR&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;d&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Met l&amp;#39;adresse de l&amp;#39;ISR après l&amp;#39;instruction JP&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Place la table des vecteurs d&amp;#39;interruption ($FExx)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$fe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Met l&amp;#39;adresse haute à $FE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;im&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Commute en Mode d&amp;#39;Interruption 2&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; All set&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ei&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;; Réactive les interruptions&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;char:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Routine de service d&amp;#39;interruption&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Appelée au début de la synchronisation verticale&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Affiche un caractère en haut à gauche de l&amp;#39;écran&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; (en mode SCREEN 1)&lt;/span&gt;
&lt;span class="nl"&gt;isr:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;char&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;$6000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ei&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;reti&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="PHC-25"></category><category term="Z80"></category><category term="Programmation"></category></entry><entry><title>Récréation Famicom</title><link href="https://www.triceraprog.fr/recreation-famicom.html" rel="alternate"></link><published>2025-05-16T00:00:00+02:00</published><updated>2025-05-16T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-05-16:/recreation-famicom.html</id><content type="html">&lt;p&gt;Et puisque ces temps-ci, je m'intéresse à la Famicom, en ayant commencé par le &lt;a href="https://www.triceraprog.fr/family-basic-le-basic-sur-famicom.html"&gt;Family Basic&lt;/a&gt;  , j'ai voulu faire une petite image 3D de la console.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un recréation da la Famicom" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202505/famicom-retake-750.jpeg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Famicom"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>Family BASIC, le BASIC sur Famicom</title><link href="https://www.triceraprog.fr/family-basic-le-basic-sur-famicom.html" rel="alternate"></link><published>2025-05-10T00:00:00+02:00</published><updated>2025-05-10T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-05-10:/family-basic-le-basic-sur-famicom.html</id><summary type="html">&lt;p&gt;L'hiver dernier, j'ai découvert le Family Basic, ou Famibe, un BASIC pour la Famicom (le petit nom de la Family Computer de Nintendo, dont la version occidentale donnera la Nintendo Entertainment System, ou NES).&lt;/p&gt;
&lt;p&gt;Le Family Basic, qui vient dans une boite bien visible sur une étagère, comprend une cartouche, un clavier et un manuel. Le clavier est un vrai clavier et est assez agréable à utiliser. Il se branche sur le port d'extension en façade de la console, là où se branchent les périphériques d'entrées supplémentaires, les deux manettes étant connectées à la console « en dur ».&lt;/p&gt;
&lt;p&gt;La cartouche est plus haute que les cartouches Famicom classiques, presque la taille d'une cartouche NES. Dedans, il y a de la rom PRG (le programme), de la rom CHR (les données graphiques) et de la RAM (la mémoire vive) supplémentaire. Cette RAM peut d'ailleurs être alimentée par piles lorsque la console est …&lt;/p&gt;</summary><content type="html">&lt;p&gt;L'hiver dernier, j'ai découvert le Family Basic, ou Famibe, un BASIC pour la Famicom (le petit nom de la Family Computer de Nintendo, dont la version occidentale donnera la Nintendo Entertainment System, ou NES).&lt;/p&gt;
&lt;p&gt;Le Family Basic, qui vient dans une boite bien visible sur une étagère, comprend une cartouche, un clavier et un manuel. Le clavier est un vrai clavier et est assez agréable à utiliser. Il se branche sur le port d'extension en façade de la console, là où se branchent les périphériques d'entrées supplémentaires, les deux manettes étant connectées à la console « en dur ».&lt;/p&gt;
&lt;p&gt;La cartouche est plus haute que les cartouches Famicom classiques, presque la taille d'une cartouche NES. Dedans, il y a de la rom PRG (le programme), de la rom CHR (les données graphiques) et de la RAM (la mémoire vive) supplémentaire. Cette RAM peut d'ailleurs être alimentée par piles lorsque la console est éteinte, ce qui permet de garder des programmes en mémoire.&lt;/p&gt;
&lt;p&gt;Quant au manuel, en japonais, il est assez fourni et explique comment utiliser le BASIC, comment utiliser les particularités de celui-ci et contient des listings de programmes à taper, avec des explications.&lt;/p&gt;
&lt;p&gt;Ce BASIC est plutôt intéressant, et même si la mémoire vive est très limitées (2ko sur les version 1 et 2 de la cartouche, 4ko sur la version 3), il est possible de faire des choses intéressantes.&lt;/p&gt;
&lt;p&gt;Il y a eu plusieurs versions du Family Basic. La première, sortie en 1984, semble ne pas avoir été très fiable et a pu être échangée contre une version 2 (il semble exister une version 2.0 et une version 2.1). Ces deux versions ont une cartouche de couleur noire. La version 3, dans une cartouche rouge et sortie en 1985, est beaucoup plus intéressante : plus de commandes et plus de mémoire vive.&lt;/p&gt;
&lt;p&gt;J'ai résumé quelques-unes de mes expériences dans une vidéos que vous pouvez voir ci-dessous.&lt;/p&gt;
&lt;p&gt;Un article en anglais, qui donne plus d'informations que ce présent petit article est disponible sur le site &lt;a href="https://nerdlypleasures.blogspot.com/2021/03/family-basic-putting-computer-into.html"&gt;Nerdly Pleasures&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-top: 56.25%;"&gt;&lt;iframe title="Programmer sur Famicom en BASIC avec le Family Basic" width="100%" height="100%" src="https://videos.triceraprog.fr/videos/embed/ak4kmKHm7aXhtLLqjzXYtD" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"&gt;&lt;/iframe&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="Famicom"></category><category term="BASIC"></category><category term="Programmation"></category></entry><entry><title>Instance Peertube pour Triceraprog</title><link href="https://www.triceraprog.fr/instance-peertube-pour-triceraprog.html" rel="alternate"></link><published>2025-01-12T00:00:00+01:00</published><updated>2025-01-12T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2025-01-12:/instance-peertube-pour-triceraprog.html</id><content type="html">&lt;p&gt;Un projet que j'avais depuis un moment maintenant était de mettre en place une instance Peertube pour
ce site. J'ai profité d'un changement de version majeur de Peertube pour réactiver ce projet et c'est
maintenant chose faite.&lt;/p&gt;
&lt;p&gt;J'ai ai donc mis les deux vidéos sur le BASIC et celle sur le LOGO.&lt;/p&gt;
&lt;div style="position: relative; padding-top: 56.25%;"&gt;&lt;iframe title="Le BASIC, ou la programmation pour tous des années 80" width="100%" height="100%" src="https://videos.triceraprog.fr/videos/embed/ca50a322-cefe-4f2e-9dcf-59a13c6aa086" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;div style="position: relative; padding-top: 56.25%;"&gt;&lt;iframe title="Le (presque) tout premier BASIC." width="100%" height="100%" src="https://videos.triceraprog.fr/videos/embed/2d74ba5c-e017-46e0-8bca-709217d33587" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;div style="position: relative; padding-top: 56.25%;"&gt;&lt;iframe title="Le LOGO, un langage derrière une tortue." width="100%" height="100%" src="https://videos.triceraprog.fr/videos/embed/946ac940-7542-4004-a2c1-ee08a65c8231" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" style="position: absolute; inset: 0px;"&gt;&lt;/iframe&gt;&lt;/div&gt;</content><category term="Divers"></category><category term="Vidéo"></category><category term="Peertube"></category><category term="Triceraprog"></category></entry><entry><title>Environnement de développement pour Picthorix</title><link href="https://www.triceraprog.fr/environnement-de-developpement-pour-picthorix.html" rel="alternate"></link><published>2024-11-22T00:00:00+01:00</published><updated>2024-11-22T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-11-22:/environnement-de-developpement-pour-picthorix.html</id><summary type="html">&lt;p&gt;Forth est naturellement un langage qui est souvent utilisé dans un environnement interactif qui est à la fois un interpréteur et un compilateur. Il est aussi parfois accompagné d'un éditeur qui permet d'enregistrer des pages de code, afin de les sauvegarder, de les recharger et de les exécuter.&lt;/p&gt;
&lt;p&gt;Le Hector HRX a bien tout ça, et cela était probablement très agréable dans les conditions d'époque. Enfin, peut-être pas lorsque l'on n'avait que le lecteur de cassette intégré. En effet, le système puissant des écrans charge et sauve les pages automatiquement au besoin. Pratique lorsque la mémoire de masse est à accès direct, comme une disquette. Mais avec une cassette, il faut souvent avancer, rembobiner avec de bonnes chances d'écraser des données.&lt;/p&gt;
&lt;p&gt;Pour le développement de &lt;a href="https://www.triceraprog.fr/un-jeu-en-forth-pour-hector-hrx-picthorix.html"&gt;Picthorix&lt;/a&gt;, j'ai souvent utilisé le mode interactif pour bien comprendre le fonctionnement de certains mots, pour tester des idées, pour vérifier le fonctionnement de certaines …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Forth est naturellement un langage qui est souvent utilisé dans un environnement interactif qui est à la fois un interpréteur et un compilateur. Il est aussi parfois accompagné d'un éditeur qui permet d'enregistrer des pages de code, afin de les sauvegarder, de les recharger et de les exécuter.&lt;/p&gt;
&lt;p&gt;Le Hector HRX a bien tout ça, et cela était probablement très agréable dans les conditions d'époque. Enfin, peut-être pas lorsque l'on n'avait que le lecteur de cassette intégré. En effet, le système puissant des écrans charge et sauve les pages automatiquement au besoin. Pratique lorsque la mémoire de masse est à accès direct, comme une disquette. Mais avec une cassette, il faut souvent avancer, rembobiner avec de bonnes chances d'écraser des données.&lt;/p&gt;
&lt;p&gt;Pour le développement de &lt;a href="https://www.triceraprog.fr/un-jeu-en-forth-pour-hector-hrx-picthorix.html"&gt;Picthorix&lt;/a&gt;, j'ai souvent utilisé le mode interactif pour bien comprendre le fonctionnement de certains mots, pour tester des idées, pour vérifier le fonctionnement de certaines parties de mon code. Mais hors de question d'utiliser en continu le mode natif, j'aurais perdu trop de temps en manipulations et en erreurs.&lt;/p&gt;
&lt;p&gt;Donc, comme souvent, j'ai réfléchi à un petit environnement de développement à base d'éditeur et d'émulateur sur PC.&lt;/p&gt;
&lt;h1&gt;Formatage des écrans&lt;/h1&gt;
&lt;p&gt;Le Hector HRX peut avoir en mémoire 10 écrans simultanés. Chaque écran contient 798 caractères. Chaque caractère est donc précieux. Mais formatter son code pour le rendre lisible et ajouter des commentaire est très précieux aussi, surtout dans un langage que l'on ne maîtrise pas.&lt;/p&gt;
&lt;p&gt;J'ai donc fait le choix d'avoir en source un fichier texte de forme libre et d'avoir une moulinette qui compacte le code pour mettre le maximum de code dans un écran. Il existe aussi le mot Forth &lt;code&gt;--&amp;gt;&lt;/code&gt; qui permet de lancer l'exécution de l'écran suivant numériquement, la moulinette peut donc ajouter ce mot de transition à la fin de chaque écran, sauf le dernier.&lt;/p&gt;
&lt;p&gt;En pratique, il y a quelques pièges dans lesquels je suis tomber. Le premier est que la définition d'un mot ne peut pas commencer sur un écran et continuer dans le suivant. Il aurait fallu avoir un peu d'analyse du code Forth pour faire ce découpage correctement. C'est un piège que j'ai contourné de manière tout à fait manuelle : je place les &lt;code&gt;--&amp;gt;&lt;/code&gt; à la main dans le code source pour séparer les screens. Pas le plus agréable, je me suis souvent retrouvé avec des screens trop grands qui ne chargeaient pas correctement, mais pas assez par rapport au temps de développement que cela m'aurait pris.&lt;/p&gt;
&lt;p&gt;Second piège, que j'ai mis un moment à comprendre. Parfois, mes affichages de chaînes de caractères étaient décalées, comme si des espaces étaient ajoutées en début de chaîne. J'ai mis un moment à comprendre que c'était parce que la mot de début de chaîne &lt;code&gt;."&lt;/code&gt; se trouvait en fin de ligne, mais pas en dernière caractère, et que le premier mot affiché se trouvait à la ligne suivante. Comme les écrans ont une largeur fixe, des espaces étaient ajoutés mécaniquement en début de chaîne.&lt;/p&gt;
&lt;p&gt;J'ai corrigé ça rapidement en revenant à la ligne lors de la détection d'un mot &lt;code&gt;."&lt;/code&gt;. Cela fait perdre de l'espace, mais pas trop. Ça passe...&lt;/p&gt;
&lt;p&gt;Dernier piège... un développement un peu fait rapidement. La moulinette n'est pas très solide et se plante parfois lorsque la ligne source est « trop » longue. Je n'ai pas analysé pourquoi. J'ai contourné le problème en coupant les lignes trop longues dans le source lorsque le bug apparaissait. Celui-ci provoque un saut au prochain screen pour une raison qui m'échappe, mais qui serait probablement simple à comprendre avec du temps pour le débugger. Je n'ai pas pris ce temps.&lt;/p&gt;
&lt;h1&gt;L'éditeur&lt;/h1&gt;
&lt;p&gt;Le code source est édité dans Visual Code, mais techniquement, il n'y a rien de spécial. Je ne l'ai pas spécifiquement customisé, à part une petite colorisation syntaxique.&lt;/p&gt;
&lt;h1&gt;L'émulateur&lt;/h1&gt;
&lt;p&gt;Comme d'habitude, j'utilise MAME pour son scripting Lua qui a un accès au debugger. J'ai fais évoluer le script déjà utilisé dans des précédents projets (&lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-visual-studio-code.html"&gt;description initiale ici&lt;/a&gt;). Il a fallu bien entendu adapter les points d'arrêt pour l'automatisation et injecter les écrans préalablement converti en format binaire en mémoire.&lt;/p&gt;
&lt;p&gt;L'injection des écrans directement en mémoire est un peu fragile. En effet, Forth ajuste des variables lorsque l'on créé et on manipule des écrans. J'ai tenter de forcer ces variables à des valeurs connues en fonction des écrans injectés, mais sans vraiment de succès. Je me retrouvais avec un environnement extrêmement instable. J'ai cependant repéré qu'en évitant d'utiliser le premier écran, le système se comportait bien. Tant pis pour la perte d'un écran.&lt;/p&gt;
&lt;p&gt;Une fois les écrans injectés, je lance la compilation en passant l'émulateur en mode rapide, et j'obtiens ainsi un compilateur. La nature du Forth fait qu'à la fin du processus, j'ai une image du jeu compilé en mémoire à un emplacement tout à fait déterminé.&lt;/p&gt;
&lt;p&gt;À partir de là, soit je peux lancer le jeu pour les tests, soit tester certains mots. Je peux aussi  sauvegarder la mémoire pour la recharger plus tard.&lt;/p&gt;
&lt;p&gt;Comme au bout d'un moment, j'ai rempli tous les screens, j'ai eu besoin d'une deuxième série d'écran à compiler à la suite. Pour scripter cela, le dernier écran de la première série termine en écrivant à un endroit précis de la mémoire et très éloigné de l'espace utilisé. Le script Lua détecte cette écriture et injecte la nouvelle série d'écran, puis lance une nouvelle compilation.&lt;/p&gt;
&lt;p&gt;Cela aurait pu être étendu à plus de séries d'écrans, il reste encore beaucoup de place en mémoire avec le jeu au complet. Cependant, comme il s'agit de le mettre sur cassette à la fin, il faut aussi veiller à ce que le temps de chargement soit de durée acceptable.&lt;/p&gt;
&lt;h1&gt;Toujours automatiser !&lt;/h1&gt;
&lt;p&gt;C'est mon conseil récurrent, et je le répète à nouveau. La dernière étape pour créer un jeu distribuable est donc de dumper la mémoire contenant tous les mots compilés qui forment le jeu. À partir du debuggeur, il faut donc spécifier une plage mémoire à sauvegarder et une adresse du mot de démarrage. Pour cela, en fin de compilation de la dernière série de screen, j'affichais les informations (taille, adresse de début) à l'écran. Restait à utiliser ces informations dans le debugger pour sauvegarder la mémoire.&lt;/p&gt;
&lt;p&gt;Le jour où je voulais publier le jeu, impossible d'avoir un dump qui fonctionne. J'ai passé la soirée à analyser un bug. Forcément, un vendredi soir, la fatigue de fin de semaine n'aide pas. Je suis allé me coucher sans trouver. Le lendemain, je relance et je trouve immédiatement (une bonne nuit de sommeil, ça aide). La taille que j'avais recopié à la main pour le dump n'était pas la bonne, de quatre octets...&lt;/p&gt;
&lt;p&gt;J'ai donc ajouté au script Lua le dump automatique, en allant chercher l'information sur la taille laissée par la fin de la compilation en mémoire.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Chaque operation manuelle répétée est une occasion de perdre son temps...&lt;/p&gt;
&lt;p&gt;À part ça, pas grand chose de neuf. Les outils sont disponibles dans les &lt;a href="https://gitlab.com/mokona/picthorix"&gt;sources du jeu&lt;/a&gt;. Cependant, à la date d'écriture de cet article, avoir un Hector HRX qui fonctionne bien sur MAME nécessite quelques modifications que je n'ai pas encore proposé pour intégration. Mais cela sera fait quand j'aurais nettoyé les changements et vérifié que je n'ai pas cassé d'autres machines.&lt;/p&gt;</content><category term="Projets"></category><category term="Hector"></category><category term="Forth"></category><category term="Jeu"></category><category term="RPUfOS"></category></entry><entry><title>Un jeu en Forth pour Hector HRX : Picthorix</title><link href="https://www.triceraprog.fr/un-jeu-en-forth-pour-hector-hrx-picthorix.html" rel="alternate"></link><published>2024-11-18T00:00:00+01:00</published><updated>2024-11-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-11-18:/un-jeu-en-forth-pour-hector-hrx-picthorix.html</id><summary type="html">&lt;p&gt;À nouvelle édition de &lt;a href="https://itch.io/jam/rpufos-hector-hr"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, nouvelle machine et une nouvelle participation.&lt;/p&gt;
&lt;p&gt;La gamme de machine couverte par cette édition est la gamme Hector HR et suivants : 2HR, 2HR+, HRX, MX40 et MX80. Pour des informations sur cette gamme de machines, je vous invite à consulter &lt;a href="http://hectorvictor.free.fr/index.php"&gt;cette page&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Hector HRX&lt;/h2&gt;
&lt;p&gt;Ces machines forment une gamme de machines vaguement compatibles les unes avec les autres. Des petites différences de matériel, et surtout de ROM, font que les programmes ne sont pas forcément compatibles entre les différentes machines. D'après ce que j'ai compris, pour rien n'arranger, c'était une machine ouverte à la bidouille et aux modifications hardware. Le parc de machines devait donc être assez hétérogène.&lt;/p&gt;
&lt;p&gt;De la gamme, j'ai donc choisi une machine : le HRX. Pour deux raisons. La première est parce que j'en avais une sous la main (mais en demande de réparation), et j'aime bien …&lt;/p&gt;</summary><content type="html">&lt;p&gt;À nouvelle édition de &lt;a href="https://itch.io/jam/rpufos-hector-hr"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, nouvelle machine et une nouvelle participation.&lt;/p&gt;
&lt;p&gt;La gamme de machine couverte par cette édition est la gamme Hector HR et suivants : 2HR, 2HR+, HRX, MX40 et MX80. Pour des informations sur cette gamme de machines, je vous invite à consulter &lt;a href="http://hectorvictor.free.fr/index.php"&gt;cette page&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Hector HRX&lt;/h2&gt;
&lt;p&gt;Ces machines forment une gamme de machines vaguement compatibles les unes avec les autres. Des petites différences de matériel, et surtout de ROM, font que les programmes ne sont pas forcément compatibles entre les différentes machines. D'après ce que j'ai compris, pour rien n'arranger, c'était une machine ouverte à la bidouille et aux modifications hardware. Le parc de machines devait donc être assez hétérogène.&lt;/p&gt;
&lt;p&gt;De la gamme, j'ai donc choisi une machine : le HRX. Pour deux raisons. La première est parce que j'en avais une sous la main (mais en demande de réparation), et j'aime bien pouvoir voir la machine pour imaginer le jeu qui va avec (et pour tester... quand la machine fonctionne). La seconde car c'est une machine qui a un Forth résident. Et si je connais un peu le Forth pour avoir joué avec et lu à son propos, je n'avais jamais développé un programme complet en Forth. Or, c'est dans ces situations que l'on découvre vraiment un langage.&lt;/p&gt;
&lt;h2&gt;La découverte&lt;/h2&gt;
&lt;p&gt;La première étape, comment toujours, est de découvrir la machine. Il y a pas mal de documentation disponible sur les différentes machines, surtout sous forme de magazines spécialisés à petits tirages (j'imagine), un peu de document de reverse engineering, des plans des certaines des machines (dont le HRX) et le code source de MAME. Il existe même un manuel Forth, sous forme de didacticiel, pour le HRX. Ce manuel m'a été très utile pour me remettre dans l'esprit Forth et faire le tour des capacités de la machine.&lt;/p&gt;
&lt;p&gt;Une fois lu le manuel et fait quelques exercices et tests, j'ai démarré... non pas le jeu, mais une relecture du manual, en notant tous les mots Forth et leur fonctionnement, afin de les classer par catégorie, les expliquer et les rendre accessible sous forme de référence en ligne, indexé. Cela m'a pris pas mal de temps, mais j'étais certain d'avoir parcouru tous les mots, de les avoir presque tous compris, et surtout, de pouvoir les retrouver rapidement.&lt;/p&gt;
&lt;p&gt;Le résultat est disponible sur &lt;a href="https://mokona.puupuu.org/pampuk-forth/"&gt;cette page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce n'est pas tout à fait complet et j'y trouve encore quelques petites erreurs en m'y référant, mais c'est déjà très utilisable. Le code source de la page &lt;a href="https://gitlab.com/mokona/hector_hrx_forth_book"&gt;est disponible&lt;/a&gt; si vous voulez le compléter.&lt;/p&gt;
&lt;h2&gt;L'environnement de développement&lt;/h2&gt;
&lt;p&gt;Le Forth du HRX est fourni avec un système de « screen », qui est classique pour le Forth. Les « screens » permettent d'éditer et d'enregistrer des données, généralement des commandes et des mots, pour les réutiliser à volonté. Le système offre du paging automatique mais avec un système sur cassette, c'est pratiquement inutilisable.&lt;/p&gt;
&lt;p&gt;De plus, l'éditeur est un éditeur de ligne, pas très agréable, même si ça dépanne. Il existe un éditeur pleine page que l'on peut charger depuis une disquette. Ça peut être intéressant pour retrouver les sensations sur la machine, mais pour un développement, je trouvais ça un peu lourd.&lt;/p&gt;
&lt;p&gt;J'ai donc, comme souvent, créé mon petit environnement en utilisant MAME et un script d'automatisation. Je ferai un article à ce sujet par la suite. Sans détail, cela m'a permis de programmer depuis Visual Code et de lancer une compilation en me servant de la machine émulée.&lt;/p&gt;
&lt;h2&gt;Le jeu&lt;/h2&gt;
&lt;p&gt;Lorsque je n'ai pas une machine fonctionnelle sous la main, je préfère chercher des idées de jeux qui ne vont pas pousser les performances ou les exotismes de la machine. Particulièrement dans le cas de ces machines avec peu d'activité, où les émulateurs ne sont pas toujours très fidèles.&lt;/p&gt;
&lt;p&gt;Mon fils m'a proposé alors l'idée d'un Picross, aussi connu sous le nom de Nonogram ou encore Logimage... et plein d'autres noms. L'idée est de remplir une grille en suivant des indications sur les groupes de « pixels » par lignes et par colonnes. Bonne idée, je suis parti là-dessus.&lt;/p&gt;
&lt;p&gt;Du à ma méconnaissance du Forth, ça a été assez laborieux. J'ai pas mal appris au passage et j'écrirais certaines choses probablement différemment si je devais recommencer. Je n'ai pas utilisé les capacités de la machines au niveau graphique, qui peut aller bien plus loin que ça, avec de l'adressage au pixel sans color clash.&lt;/p&gt;
&lt;p&gt;Au passage, j'ai aussi appris à créer des grilles de Picross. Pour cela, j'ai utilisé un &lt;a href="http://www.landofcrispy.com/nonogrammer/nonogram.html?mode=build"&gt;programme un ligne&lt;/a&gt; qui permet de savoir si la grille est résolvable ou pas. C'est pratique, car il ne suffit pas de faire une grille avec un dessin sympa. Il faut à cette grille une solution unique, ce qui n'est pas toujours le cas sur une grille quelconque.&lt;/p&gt;
&lt;p&gt;Au final, j'ai créé 9 grilles, dont deux vraiment comme une initiation et cinq comme références aux cinq jeux précédents avec lesquels j'ai participé aux précédentes éditions de RPUfOS. &lt;/p&gt;
&lt;p&gt;Pour télécharger le jeu, c'est &lt;a href="https://mokona78.itch.io/picthorix"&gt;sur la page itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Le code source &lt;a href="https://gitlab.com/mokona/picthorix"&gt;est disponible&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://youtu.be/-Ur-7aHOM2o"&gt;Vidéo de Retro Vynz&lt;/a&gt; contenant une revue du jeu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/0HOi2E-uPAg"&gt;Vidéo de Olipix&lt;/a&gt; une présentation et revue du jeu ainsi qu'un petit passage où j'interviens (en disant globalement la même chose que dans cet article)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Picthorix" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202411/20241120-Picthorix-Screenshot-750.jpeg"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Hector"></category><category term="Forth"></category><category term="Jeu"></category><category term="RPUfOS"></category></entry><entry><title>Yeno SC-3000 et condensateurs</title><link href="https://www.triceraprog.fr/yeno-sc-3000-et-condensateurs.html" rel="alternate"></link><published>2024-09-14T00:00:00+02:00</published><updated>2024-09-14T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-09-14:/yeno-sc-3000-et-condensateurs.html</id><content type="html">&lt;p&gt;Suite à une panne sur un Yeno SC-3000 récemment, j'ai du changer un condensateur. En travail préparatoire, j'ai fait une photo annotée de la carte mère.Là voici, si ça peut aider.&lt;/p&gt;
&lt;p&gt;L'image est cliquable pour l'agrandir.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/202409/SC3000-CarteMere-1024px.png"&gt;&lt;img alt="Platine principale" src="https://www.triceraprog.fr/images/202409/SC3000-CarteMere-750px.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="SC-3000"></category><category term="Schéma"></category><category term="Photo"></category></entry><entry><title>Suite de tests pour VG5000µ</title><link href="https://www.triceraprog.fr/suite-de-tests-pour-vg5000m.html" rel="alternate"></link><published>2024-09-06T00:00:00+02:00</published><updated>2024-09-06T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-09-06:/suite-de-tests-pour-vg5000m.html</id><content type="html">&lt;p&gt;Il y a quelques années, j'avais commencé une suite de tests pour le VG5000µ sous la forme d'un programme en mélange de C et assembleur.
L'idée était double : écrire une référence pour s'inspirer dans la programmation du VG5000µ (et particulièrement de l'EF9345), ainsi que
tester la fidélité des émulateurs.&lt;/p&gt;
&lt;p&gt;Je me suis servi de cette base de code pour la première raison et mes besoins personnels. J'ai aussi pu corriger une paire de bugs dans
MAME grâce à la seconde utilisation.&lt;/p&gt;
&lt;p&gt;Cependant, cette base de code traîne depuis un moment sur mon disque et je n'y passe pas beaucoup de temps. Alors autant que ça serve
à d'autres, et je mets donc aujourd'hui cette base à disposition.&lt;/p&gt;
&lt;p&gt;Je ne sais plus trop dans quel état il est. Ça doit globalement fonctionner. J'imagine.&lt;/p&gt;
&lt;p&gt;En tout cas, c'est &lt;a href="https://gitlab.com/mokona/vg5000-tests"&gt;dispo sous licence CC0&lt;/a&gt;, donc faites-en ce que vous voulez.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="C"></category><category term="Z80"></category></entry><entry><title>Un peu d'Atari ST</title><link href="https://www.triceraprog.fr/un-peu-datari-st.html" rel="alternate"></link><published>2024-08-31T00:00:00+02:00</published><updated>2024-08-31T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-08-31:/un-peu-datari-st.html</id><summary type="html">&lt;p&gt;Ce site est, en tout cas a été jusqu'à maintenant, très machines 8 bits. Du fait des participations aux &lt;a href="tag/rpufos.html"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, mais aussi aux machines sur lesquelles je m'amuse le plus. L'avantage des machines 8 bits, c'est qu'elles la plupart du temps assez simple à comprendre, à programmer, avec des designs techniques parfois originaux mais qui restent abordables.&lt;/p&gt;
&lt;p&gt;Cependant, il y a peu, Zisquier &lt;a href="https://www.asmtariste.fr/"&gt;a lancé un site&lt;/a&gt; pour aborder le 68000 à travers la programmation en assembleur sur Atari ST. Je m'étais lancé dans l'idée d'essayer d'&lt;a href="https://www.triceraprog.fr/apprendre-lassembleur-mais-comment.html"&gt;enseigner l'assembleur de manière ludique&lt;/a&gt;, mais comme on dit, « life happens » et je n'ai pas poursuit sur la lancée.&lt;/p&gt;
&lt;p&gt;Comme j'étais en pause d'été, que l'Atari ST (STE en réalité) fait partie de mon historique de machines personnelles, et que j'avais quitté cette machine sans en avoir fait le tour je pense, même si j'y avais fait un …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ce site est, en tout cas a été jusqu'à maintenant, très machines 8 bits. Du fait des participations aux &lt;a href="tag/rpufos.html"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, mais aussi aux machines sur lesquelles je m'amuse le plus. L'avantage des machines 8 bits, c'est qu'elles la plupart du temps assez simple à comprendre, à programmer, avec des designs techniques parfois originaux mais qui restent abordables.&lt;/p&gt;
&lt;p&gt;Cependant, il y a peu, Zisquier &lt;a href="https://www.asmtariste.fr/"&gt;a lancé un site&lt;/a&gt; pour aborder le 68000 à travers la programmation en assembleur sur Atari ST. Je m'étais lancé dans l'idée d'essayer d'&lt;a href="https://www.triceraprog.fr/apprendre-lassembleur-mais-comment.html"&gt;enseigner l'assembleur de manière ludique&lt;/a&gt;, mais comme on dit, « life happens » et je n'ai pas poursuit sur la lancée.&lt;/p&gt;
&lt;p&gt;Comme j'étais en pause d'été, que l'Atari ST (STE en réalité) fait partie de mon historique de machines personnelles, et que j'avais quitté cette machine sans en avoir fait le tour je pense, même si j'y avais fait un peu d'assembleur, je me suis dit que c'était l'occasion de la redécouvrir. Par la programmation bien entendu.&lt;/p&gt;
&lt;p&gt;Le ton de Zisquier est direct, il va à l'essentiel, progressivement. Il y a des tests à la fin des leçons qui apportent un petit côté ludique. C'est fun et j'aime bien. Et petit à petit, me voici actuellement avec un sprite qui se déplace à l'écran au-dessus d'un décors.&lt;/p&gt;
&lt;p&gt;Le code est un peu moche, j'y vais un peu à tâtons et je ne sais pas toujours quels sont les meilleurs façon d'utiliser les instructions 68000. Mais il y a un Discord associé avec des personnes qui sont aidantes sur le sujet.&lt;/p&gt;
&lt;p&gt;Le sprite est en CC-BY 3.0 par « Withthelove », &lt;a href="https://opengameart.org/content/tiny-16-expanded-character-sprites"&gt;trouvé sur OpenGameArt.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le tileset est en CC0 par « Kenney », c'est &lt;a href="https://kenney.nl/assets/tiny-town"&gt;Tiny Town&lt;/a&gt; remanié au niveau de la palette de couleurs et du layout pour correspondre à l'Atari ST et à mon besoin.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Sprite et Tilemap sur Atari ST" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202408/20240831-SpriteEtTilemap-AtariST.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Atari ST"></category><category term="ASM"></category></entry><entry><title>Le Forth sur Hector HRX</title><link href="https://www.triceraprog.fr/le-forth-sur-hector-hrx.html" rel="alternate"></link><published>2024-08-15T00:00:00+02:00</published><updated>2024-08-15T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-08-15:/le-forth-sur-hector-hrx.html</id><summary type="html">&lt;p&gt;Avec la nouvelle session de Retro Programmers United for Obscure Systems,
il est temps de découvrir la ligne des Hector HR. Que ce soit l'Hector 2HR, le 2HR+,
le HRX et probablement le MX.&lt;/p&gt;
&lt;p&gt;Pour en savoir plus sur ces ordinateurs, il existe &lt;a href="http://hectorvictor.free.fr/index.php?page=y=XhGx5OoEsI"&gt;une page&lt;/a&gt; dédiée à ces machines.&lt;/p&gt;
&lt;p&gt;Après avoir cherché un peu dans les resources Hector, je me suis dirigé pour ma contribution à cette
session vers le « Hector HRX » et son Forth. En effet, le HRX est un de ces rares ordinateurs 8 bits
qui venait avec un Forth en ROM, au lieu du plus classique BASIC.&lt;/p&gt;
&lt;p&gt;Il existe un livre sur le Forth pour Hector HRX, « la pratique du Forth avec Hector », qui est plutôt
agréable à lire afin de découvrir la machine à travers ce langage, et pourquoi pas, découvrir le Forth
au passage.&lt;/p&gt;
&lt;p&gt;L'ennui avec le livre, c'est qu'il présente les mots en contexte …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Avec la nouvelle session de Retro Programmers United for Obscure Systems,
il est temps de découvrir la ligne des Hector HR. Que ce soit l'Hector 2HR, le 2HR+,
le HRX et probablement le MX.&lt;/p&gt;
&lt;p&gt;Pour en savoir plus sur ces ordinateurs, il existe &lt;a href="http://hectorvictor.free.fr/index.php?page=y=XhGx5OoEsI"&gt;une page&lt;/a&gt; dédiée à ces machines.&lt;/p&gt;
&lt;p&gt;Après avoir cherché un peu dans les resources Hector, je me suis dirigé pour ma contribution à cette
session vers le « Hector HRX » et son Forth. En effet, le HRX est un de ces rares ordinateurs 8 bits
qui venait avec un Forth en ROM, au lieu du plus classique BASIC.&lt;/p&gt;
&lt;p&gt;Il existe un livre sur le Forth pour Hector HRX, « la pratique du Forth avec Hector », qui est plutôt
agréable à lire afin de découvrir la machine à travers ce langage, et pourquoi pas, découvrir le Forth
au passage.&lt;/p&gt;
&lt;p&gt;L'ennui avec le livre, c'est qu'il présente les mots en contexte, mais qu'il n'y a pas de référence
regroupement les mots par catégorie, ou par usage. Il faut donc se souvenir du passage où le mot
est présenté, et le retrouver parmi la prose pédagogique.&lt;/p&gt;
&lt;p&gt;Je n'étais pas non plus certain que tous les mots soient présentés par le livre (après en avoir fait la liste,
il en manque bien quelques uns, mais c'est en fait très complet).&lt;/p&gt;
&lt;p&gt;Pour moi, il manquait donc une référence, et c'est ce que je me suis appliqué à faire. Cette référence
n'est pas un apprentissage du Forth, la lecture du livre ou d'une autre ressource est nécessaire. Par
contre, elle présente une liste catégorisée des mots ainsi que les grands principes du Forth et son
implémentation sur Hector HRX.&lt;/p&gt;
&lt;p&gt;Éspérant donc que cette référence pourra vous être utile comme elle l'est pour moi, je l'ai &lt;a href="https://mokona.puupuu.org/pampuk-forth"&gt;publiée à
cette adresse&lt;/a&gt;.&lt;/p&gt;</content><category term="Langages"></category><category term="Forth"></category><category term="Programmation"></category><category term="Hector"></category></entry><entry><title>J'MSX 24 et un micro jeu</title><link href="https://www.triceraprog.fr/jmsx-24-et-un-micro-jeu.html" rel="alternate"></link><published>2024-07-02T00:00:00+02:00</published><updated>2024-07-02T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-07-02:/jmsx-24-et-un-micro-jeu.html</id><summary type="html">&lt;h2&gt;Le salon&lt;/h2&gt;
&lt;p&gt;Les 23 et 23 mai 2024 ont eu lieu à Paris deux journées autour du MSX. La rencontre se passait à ISART, une école de jeux vidéo, et était
co-organisée par l'&lt;a href="https://www.mo5.com/"&gt;association MO5&lt;/a&gt; et le &lt;a href="https://msxvillage.fr/"&gt;MSX Village&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Deux journées vraiment sympas avec quelques conférences, dont certaines faites par le concepteur du MSX en personne, Kazuhiko Nishi, qui
avait fait le déplacement. Son but est de présenter ses projets de MSX0 et MSX3, sur lesquels je ne m'étendrai pas ici.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Conférence de Kazuhiko Nishi" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202407/20240623-conference-nishi-san-msx.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Pour moi, cela a été l'occasion de rencontrer des gens passionnés par le MSX. N'étant moi-même pas très connaisseur de la machine, en tout
cas pas autant qu'eux, j'ai pu apprendre plein de choses. Outre une exposition autour des jeux Konami, avec plein de MSX jouables en libre
service, il y avait une petite exposition d'illustrations faites dans des modes de rendus MSX, ainsi qu'une présentation de diverses …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Le salon&lt;/h2&gt;
&lt;p&gt;Les 23 et 23 mai 2024 ont eu lieu à Paris deux journées autour du MSX. La rencontre se passait à ISART, une école de jeux vidéo, et était
co-organisée par l'&lt;a href="https://www.mo5.com/"&gt;association MO5&lt;/a&gt; et le &lt;a href="https://msxvillage.fr/"&gt;MSX Village&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Deux journées vraiment sympas avec quelques conférences, dont certaines faites par le concepteur du MSX en personne, Kazuhiko Nishi, qui
avait fait le déplacement. Son but est de présenter ses projets de MSX0 et MSX3, sur lesquels je ne m'étendrai pas ici.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Conférence de Kazuhiko Nishi" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202407/20240623-conference-nishi-san-msx.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Pour moi, cela a été l'occasion de rencontrer des gens passionnés par le MSX. N'étant moi-même pas très connaisseur de la machine, en tout
cas pas autant qu'eux, j'ai pu apprendre plein de choses. Outre une exposition autour des jeux Konami, avec plein de MSX jouables en libre
service, il y avait une petite exposition d'illustrations faites dans des modes de rendus MSX, ainsi qu'une présentation de diverses
extensions modernes et françaises pour les machines du standard.&lt;/p&gt;
&lt;h2&gt;La game jam&lt;/h2&gt;
&lt;p&gt;Pendant le week-end, une game jam a été proposées aux étudiants de l'école qui nous accueillait. Quelques étudiants se sont prêtés au jeu.
Le but était bien évidemment de créer un jeu pour MSX, fonctionnel sur une machine réelle, et donc de comprendre ses contraintes.
L'organisateur les avait briefé auparavant, pour ne pas partir de zéro le jour J.&lt;/p&gt;
&lt;p&gt;Le thème ? « l'amour éternel ». Il y avait de bonnes idées autour du thème, mais je ne sais pas si les jeux ont été terminés.&lt;/p&gt;
&lt;p&gt;De mon côté, j'étais titillé par l'idée de participer. Mais je ne voulais pas non plus y passer le week-end. J'ai donc fait rapidement
un petit truc le dimanche matin, probablement en 2 ou 3 heures tout en déambulant dans le salon. Le résultat n'est pas tout à fait un
jeu : on ne peut pas gagner. Mais on peut perdre, et c'est déjà ça. On pourrait ajouter au jeu un score à maximiser...&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d'écran de mon micro jeu" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202407/20240624-jeu-jam-msx.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Dans ce jeu, il faut attraper des logos MSX qui apparaissent sur le terrain. Lorsqu'on en attrape un, cela laisse sur place un petit
visage souriant, propageant ainsi l'amour éternel du MSX. Ces visages gênent les déplacements, et il devient donc de plus en plus difficile
d'attraper les logos. Le jeu est en mode 1 et est jouable sur un MSX1. J'ai bien entendu utilisé la librairie &lt;a href="https://github.com/aoineko-fr/MSXgl"&gt;MSXgl&lt;/a&gt;
que nous utilisons aussi pour le projet &lt;a href="https://github.com/Asso-MO5/room5"&gt;Room 5&lt;/a&gt; pendant les lives twitch de l'association MO5. Jeu qui d'ailleurs
était jouable sur place et sur vrai matériel.&lt;/p&gt;
&lt;p&gt;Bref, deux journées qui font plaisir.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Room 5 en présentation à la J'MSX 24" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202407/room5-msx-reel.jpg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="MSX"></category><category term="Salon"></category><category term="Game Jam"></category><category term="Jeu"></category></entry><entry><title>Récréation 3D, Matra Alice</title><link href="https://www.triceraprog.fr/recreation-3d-matra-alice.html" rel="alternate"></link><published>2024-06-08T00:00:00+02:00</published><updated>2024-06-08T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-06-08:/recreation-3d-matra-alice.html</id><content type="html">&lt;p&gt;Suite à des discussions semi-sérieuses sur la possibilité de transporter un Matra Alice pour l'utiliser à la plage, je me suis amusé
à imaginer (et à modéliser) une extension « batterie + écran » pour le Matra Alice.&lt;/p&gt;
&lt;p&gt;Ce n'est qu'une vue d'artiste, aucune étude de faisabilité n'a été faite. Mécaniquement, je n'ai aucune idée de si ça tiendrait, je
ne sais pas si ça serait pratique... c'est pour le fun !&lt;/p&gt;
&lt;p&gt;Dans cette hypothétique extension qui se clipserait à l'arrière de la machine, on peut imaginer des batteries pour fournir les 5V
nécessaires (si on laisse tomber le port série), des connecteurs pour amener le signal vidéo à un écran plat. Et pourquoi pas
une extension RAM ?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un concept de Matra Alice portable" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202406/20240607-MatraAlicePortable-Rendu.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;On m'a signalé que la chaîne YouTube « The Taylor and Amy Show » avait adapté un écran plat à un TRS-80 MC-10, si vous voulez voir ça,
c'est &lt;a href="https://www.youtube.com/watch?v=4zbNa-9jG1I&amp;amp;t=509s"&gt;par ici&lt;/a&gt;.&lt;/p&gt;</content><category term="Divers"></category><category term="Matra Alice"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>Tuiles des plus très-curieuses</title><link href="https://www.triceraprog.fr/tuiles-des-plus-tres-curieuses.html" rel="alternate"></link><published>2024-05-07T00:00:00+02:00</published><updated>2024-05-07T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-05-07:/tuiles-des-plus-tres-curieuses.html</id><summary type="html">&lt;p&gt;Et voici la cinquième session de &lt;a href="https://itch.io/jam/rpuos-matra-alice"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, organisée par &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; qui se termine !&lt;/p&gt;
&lt;p&gt;Et j'y ai participé.&lt;/p&gt;
&lt;h2&gt;La machine&lt;/h2&gt;
&lt;p&gt;Tout d'abord, la machine. Le principe de cette game jam est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque.
Avec le Matra Alice, la question se posait. En effet, la première machine de la gamme, le Matra Alice 4k, est la même machine que le Tandy MC-10,
qui a lui une ludothèque un peu plus fournie.&lt;/p&gt;
&lt;p&gt;L'idée était donc de se concentrer plutôt sur les deux autres machines de la gamme commerciale : le Matra Alice 32 et le Matra Alice 90.
Ces machines, qui offrent une compatibilité au niveau BASIC avec la première, sont néanmoins différentes, en particulier à cause d'un
processeur graphique différent. Dans ces deux machines, il s'agit de l'EF9345. Le même qui équipe le VG5000µ, avec la …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Et voici la cinquième session de &lt;a href="https://itch.io/jam/rpuos-matra-alice"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, organisée par &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; qui se termine !&lt;/p&gt;
&lt;p&gt;Et j'y ai participé.&lt;/p&gt;
&lt;h2&gt;La machine&lt;/h2&gt;
&lt;p&gt;Tout d'abord, la machine. Le principe de cette game jam est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque.
Avec le Matra Alice, la question se posait. En effet, la première machine de la gamme, le Matra Alice 4k, est la même machine que le Tandy MC-10,
qui a lui une ludothèque un peu plus fournie.&lt;/p&gt;
&lt;p&gt;L'idée était donc de se concentrer plutôt sur les deux autres machines de la gamme commerciale : le Matra Alice 32 et le Matra Alice 90.
Ces machines, qui offrent une compatibilité au niveau BASIC avec la première, sont néanmoins différentes, en particulier à cause d'un
processeur graphique différent. Dans ces deux machines, il s'agit de l'EF9345. Le même qui équipe le VG5000µ, avec la même taille de
mémoire vidéo associée, 8k.&lt;/p&gt;
&lt;p&gt;Autant dire que niveau graphique, j'étais en terrain connu.&lt;/p&gt;
&lt;p&gt;Niveau processeur par contre, c'est une découverte. Le 6803 est un microcontrôleur  8 bits, de la famille des 6800. Mais je ne connaissais pas vraiment.
En tout cas, je n'en avais aucune pratique. Il a de la RAM embarquée sur la page 0. Il a aussi un chronomètre (timer), normalement utilisée
pour les communications (séries et cassette).&lt;/p&gt;
&lt;h2&gt;Le développement&lt;/h2&gt;
&lt;p&gt;Avant de parler du jeu, un mot sur le développement. Comme je venais de recevoir &lt;a href="https://forum.system-cfg.com/viewtopic.php?f=10&amp;amp;t=14759"&gt;l'extension « Multiports » &lt;/a&gt;, je voulais que le jeu puisse être sur cartouche. Autre avantage, pas de temps de chargement si l'émulateur gère bien cette extension.&lt;/p&gt;
&lt;p&gt;Vous le savez si vous avez lu d'autres articles sur ce blog, j'aime bien avoir une chaîne de développement avec le maximum d'automatismes, pour
me concentrer sur le développement du jeu et faire le moins d'opérations manuelles possibles.&lt;/p&gt;
&lt;p&gt;Mon choix habituel va vers MAME. Et MAME a un support pour l'Alice... mais pas pour l'extension. Mon premier développement a donc été d'ajouter
à MAME le support de l'extension, en tout cas le support cartouche et l'ajout de RAM. Le changement a été accepté, mais j'ai quelques modifications
qui m'ont été demandées et que je dois toujours terminer.&lt;/p&gt;
&lt;p&gt;Utilisant mes scripts d'automatisation habituels, j'avais en tout cas de quoi lancer l'émulateur automatiquement après une compilation.&lt;/p&gt;
&lt;p&gt;Cependant pour compiler... il faut un compilateur. Il n'y a pas beaucoup de choix pour le 6803 pour un compilateur C, et légèrement plus, mais pas
trop, pour un assembleur. Dans un premier temps, j'ai fais quelques tests avec un premier assembleur... mais avec le jeu que je voulais faire,
je me suis dit que j'y gagnerais en productivité avec un compilateur C.&lt;/p&gt;
&lt;p&gt;Après quelques recherches et essais, j'ai choisi &lt;a href="https://github.com/EtchedPixels/CC6303"&gt;CC6303&lt;/a&gt;. Le message « The assembler and linker should be reasonably reliable and complete. » m'a fait un peu peur, mais j'ai quand même tenté. J'ai fais des tests, et ça semblait générer du code correct.&lt;/p&gt;
&lt;p&gt;Sur toute la durée du développement, j'ai eu deux fois des problèmes de génération de code. Je ne les ai pas analysés plus que ça, car c'était
(bien entendu) vers la fin.&lt;/p&gt;
&lt;p&gt;J'ai contribué à une paire de modifications au passage. Au moins, la game jam aura permis modestement d'améliorer les outils de développement pour cette machine.&lt;/p&gt;
&lt;h2&gt;Le jeu&lt;/h2&gt;
&lt;p&gt;Comme d'habitude, je suis parti sur une idée bien trop ambitieuse, et avec le premiers mois consacré à la découverte de la machine et aux modifications
de MAME, j'ai dû revoir mes plans. En fait, même avec la totalité du temps, je n'aurais pas pu faire ce que je voulais...&lt;/p&gt;
&lt;p&gt;Je suis donc parti sur une idée de jeu que je voulais aussi faire : un Match-3. C'est un type de jeu auquel je joue beaucoup. C'est aussi un type
de jeu qui a beaucoup de variations : est-ce que les tuiles tombent, est-ce qu'elles montent, est-ce qu'elles sont renouvelées, quel scoring,
quels bonus, des challenges, etc.&lt;/p&gt;
&lt;p&gt;Pour démarrer, j'ai fait un prototype avec un terrain de 10 par 10, toujours rempli de tuiles. Lorsque 3 tuiles identiques ou plus sont alignées,
elles disparaissent. Les tuiles du dessus tombent, et des nouvelles tuiles apparaissent en haut. Les tuiles étaient représentées par des chiffres.
Le but pour moi était de 1/ trouver l'algorithme de recherche des tuiles alignées, 2/ vérifier que la machine était assez puissante pour ce type
de jeu.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Prototype du jeu" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202405/20240319-Match-3-Dev.png"&gt;&lt;/p&gt;
&lt;p&gt;Une fois le prototype fonctionnel, j'ai commencé à ajouter des graphismes. J'ai utilisé &lt;a href="https://orama-interactive.itch.io/pixelorama"&gt;Pixelorama&lt;/a&gt; pour dessiner les tuiles, avec un thème « Alice au Pays des Merveilles ». Comme je l'ai fait auparavant, j'exporte manuellement les images en PNG (j'aimerais bien un export automatique, mais cela ne semble pas possible pour le moment, ou alors je n'ai pas trouvé). Ces imagines PNG sont ensuite converties en données dans un format que je peux inclure dans le code.&lt;/p&gt;
&lt;p&gt;De temps en temps, je lançais un test sur la machine réelle. C'est ainsi que je me suis aperçu que mon extension a un problème avec son extension RAM.
Comme je n'avais pas le temps de m'en occupé, j'ai coupé la RAM supplémentaire (c'est une option de l'extension). Le jeu n'a pas besoin de beaucoup de mémoire, le code et les données graphiques étant présents dans la ROM.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Les tuiles" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202405/AliceMatch-16.png"&gt;&lt;/p&gt;
&lt;p&gt;Une fois le jeu fonctionnel, je voulais ajouter un principe de challenges pour avoir une sorte de mode « histoire ». Je voulais aussi
ajouter un mode « infini », mais je n'aurai pas assez de place pour ça. Je voulais aussi ajouter un petit personnage qui réagit aux actions du joueur.&lt;/p&gt;
&lt;p&gt;Dessiner un personnage avec les contraintes de couleur et mes (bas) talents de dessinateur a été un peu compliqué, mais je suis assez content du résultat.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le personnage animé" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202405/Alice-Personnage.png"&gt;&lt;/p&gt;
&lt;p&gt;Problème : la place sur la cartouche. Une cartouche d'extension Multiports a une taille totale de 64k. En mode cartouche, cette taille est
divisée en 8 banques de 8k. Cela signifie qu'à un moment donné, il n'y a que 8ko accessible. Le Multiports a un système simpliste de changement
de banque : il suffit d'écrire sur une plage de donnée précise le numéro de la banque voulue. C'est suffisant, mais sans support du compilateur,
c'est un peu acrobatique.&lt;/p&gt;
&lt;p&gt;Je n'avais pas le temps de pousser un système d'appels de code entre les banques, j'ai donc séparé le jeu en deux grandes parties. Dans la première
partie, et donc la première banque, je mets tout ce qui est graphiques. C'est une astuce sur les jeux cassettes que je reprends ici : un premier
programme se charge et redéfini les caractères. Ensuite, il lance le jeu.&lt;/p&gt;
&lt;p&gt;La première banque contient aussi l'écran de titre.&lt;/p&gt;
&lt;p&gt;Le cœur du jeu est dans la deuxième banque. Pour passer d'une banque à l'autre, j'ai un petit bout de code que je place en RAM pour faire le changement.
Chaque programme est compilé comme un logiciel indépendant.&lt;/p&gt;
&lt;h2&gt;Mais... et le titre ?&lt;/h2&gt;
&lt;p&gt;Le titre est une référence à la traduction française de « Alice's Adventures in Wonderland » qui est trouvable sur le &lt;a href="https://www.gutenberg.org/cache/epub/55456/pg55456-images.html"&gt;projet Gutenberg&lt;/a&gt;. Le chapitre deux commence par ce passage : « “De plus très-curieux en plus très-curieux!” s’écria Alice ».&lt;/p&gt;
&lt;p&gt;Dans mon jeu, Alice se retrouve dans un monde étrange avec des tuiles à aligner. On ne peut pas dire que ça va très loin d'un point de vue
histoire et justification... mais ça suffira.&lt;/p&gt;
&lt;p&gt;Oh, et j'ai aussi dessiné une jaquette pour la cartouche et la manuel. À base de dessin sur tablette et de beaucoup de temps de retouche avec The Gimp,
puis de composition avec Blender pour ajouter les tuiles.&lt;/p&gt;
&lt;h2&gt;Quelques liens&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Le code source &lt;a href="https://gitlab.com/mokona/alicematch3"&gt;est disponible&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://youtu.be/wVtyKYwheAI"&gt;Vidéo de Retro Vynz&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="embed-yt text-center" data-video-id="wVtyKYwheAI" style="width: 560; height:315"&gt;
    &lt;div class="embed-yt-play"&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/BX98AdSIHWA"&gt;Vidéo de Olipix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="embed-yt text-center" data-video-id="BX98AdSIHWA" style="width: 560; height:315"&gt;
    &lt;div class="embed-yt-play"&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Le jeu est disponible sur &lt;a href="https://mokona78.itch.io/tuiles-des-plus-trs-curieuses"&gt;itch.io&lt;/a&gt;. J'ai rapidement ajouté une version cassette,
car tout le monde n'a pas un Multiports (pas encore disponible sur la page, elle sera dans la version 1.1 que j'ajouterai bientôt).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tuiles des plus très-curieuses" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202405/TuilesCurieuses-Version1.0-750.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="RPUfOS"></category><category term="Matra Alice"></category></entry><entry><title>Notes sur le Motorola 6809</title><link href="https://www.triceraprog.fr/notes-sur-le-motorola-6809.html" rel="alternate"></link><published>2024-02-23T00:00:00+01:00</published><updated>2024-02-23T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-02-23:/notes-sur-le-motorola-6809.html</id><summary type="html">&lt;p&gt;Je place ici quelques notes sur le Motorola 6809, pour me remettre rapidement dans le bain lorsque je change de processeur.&lt;/p&gt;
&lt;h1&gt;Registres&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;2 accumulateurs 8 bits A et B, qui peuvent se joindre en un seul accumulateur 16 bits D&lt;/li&gt;
&lt;li&gt;1 registre d'index X 16 bits&lt;/li&gt;
&lt;li&gt;1 registre SP (Stack Pointer)&lt;/li&gt;
&lt;li&gt;1 registre PC (Program Counter)&lt;/li&gt;
&lt;li&gt;1 registre d'état : 11HINZVC&lt;ul&gt;
&lt;li&gt;5, H : half carry&lt;/li&gt;
&lt;li&gt;4, I : interrupt&lt;/li&gt;
&lt;li&gt;3, N : negative&lt;/li&gt;
&lt;li&gt;2, Z : zero&lt;/li&gt;
&lt;li&gt;1, V : overflow&lt;/li&gt;
&lt;li&gt;0, C : carry&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Interruptions&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;NMI (Non Maskable Interrupt)&lt;/li&gt;
&lt;li&gt;IRQ1 (Interrupt Request) : pour les périphériques externes&lt;/li&gt;
&lt;li&gt;IRQ2 (Interrupt Request) : pour le timer et l'interface série&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;IRQ1 a la priorité sur IRQ2.&lt;/p&gt;
&lt;p&gt;Vecteurs d’interruptions :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MSB&lt;/th&gt;
&lt;th&gt;LSB&lt;/th&gt;
&lt;th&gt;Interruption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FFFE&lt;/td&gt;
&lt;td&gt;FFFF&lt;/td&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFFC&lt;/td&gt;
&lt;td&gt;FFFD&lt;/td&gt;
&lt;td&gt;NMI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFFA&lt;/td&gt;
&lt;td&gt;FFFB&lt;/td&gt;
&lt;td&gt;Software interrupt (SWI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF8&lt;/td&gt;
&lt;td&gt;FFF9&lt;/td&gt;
&lt;td&gt;IRQ1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF6&lt;/td&gt;
&lt;td&gt;FFF7&lt;/td&gt;
&lt;td&gt;ICF (Input Capture)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF4&lt;/td&gt;
&lt;td&gt;FFF5&lt;/td&gt;
&lt;td&gt;OCF (Output Compare)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF2&lt;/td&gt;
&lt;td&gt;FFF3&lt;/td&gt;
&lt;td&gt;TOF (Timer Overflow)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF0&lt;/td&gt;
&lt;td&gt;FFF1&lt;/td&gt;
&lt;td&gt;SCI (RDRF + ORFE + TDRE)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;Ensemble des Instructions …&lt;/h1&gt;</summary><content type="html">&lt;p&gt;Je place ici quelques notes sur le Motorola 6809, pour me remettre rapidement dans le bain lorsque je change de processeur.&lt;/p&gt;
&lt;h1&gt;Registres&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;2 accumulateurs 8 bits A et B, qui peuvent se joindre en un seul accumulateur 16 bits D&lt;/li&gt;
&lt;li&gt;1 registre d'index X 16 bits&lt;/li&gt;
&lt;li&gt;1 registre SP (Stack Pointer)&lt;/li&gt;
&lt;li&gt;1 registre PC (Program Counter)&lt;/li&gt;
&lt;li&gt;1 registre d'état : 11HINZVC&lt;ul&gt;
&lt;li&gt;5, H : half carry&lt;/li&gt;
&lt;li&gt;4, I : interrupt&lt;/li&gt;
&lt;li&gt;3, N : negative&lt;/li&gt;
&lt;li&gt;2, Z : zero&lt;/li&gt;
&lt;li&gt;1, V : overflow&lt;/li&gt;
&lt;li&gt;0, C : carry&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Interruptions&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;NMI (Non Maskable Interrupt)&lt;/li&gt;
&lt;li&gt;IRQ1 (Interrupt Request) : pour les périphériques externes&lt;/li&gt;
&lt;li&gt;IRQ2 (Interrupt Request) : pour le timer et l'interface série&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;IRQ1 a la priorité sur IRQ2.&lt;/p&gt;
&lt;p&gt;Vecteurs d’interruptions :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MSB&lt;/th&gt;
&lt;th&gt;LSB&lt;/th&gt;
&lt;th&gt;Interruption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FFFE&lt;/td&gt;
&lt;td&gt;FFFF&lt;/td&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFFC&lt;/td&gt;
&lt;td&gt;FFFD&lt;/td&gt;
&lt;td&gt;NMI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFFA&lt;/td&gt;
&lt;td&gt;FFFB&lt;/td&gt;
&lt;td&gt;Software interrupt (SWI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF8&lt;/td&gt;
&lt;td&gt;FFF9&lt;/td&gt;
&lt;td&gt;IRQ1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF6&lt;/td&gt;
&lt;td&gt;FFF7&lt;/td&gt;
&lt;td&gt;ICF (Input Capture)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF4&lt;/td&gt;
&lt;td&gt;FFF5&lt;/td&gt;
&lt;td&gt;OCF (Output Compare)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF2&lt;/td&gt;
&lt;td&gt;FFF3&lt;/td&gt;
&lt;td&gt;TOF (Timer Overflow)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFF0&lt;/td&gt;
&lt;td&gt;FFF1&lt;/td&gt;
&lt;td&gt;SCI (RDRF + ORFE + TDRE)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;Ensemble des Instructions&lt;/h1&gt;
&lt;h2&gt;Mode d'adressage&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Implied/Inherent : aucune donnée n'est nécessaire&lt;/li&gt;
&lt;li&gt;Immediate : la donnée est dans l'instruction (1 ou 2 octets)&lt;/li&gt;
&lt;li&gt;Direct : la donnée est dans l'octet suivant (1 octet, le poids fort est fixé à $00)&lt;/li&gt;
&lt;li&gt;Extended : la donnée est dans les deux octets suivants (adresse 16 bits)&lt;/li&gt;
&lt;li&gt;Indexed : la donnée est dans la mémoire, à l'adresse donnée par le registre d'index (opérande de 8 bits ajoutée à X)&lt;/li&gt;
&lt;li&gt;Relative : la donnée est dans l'octet suivant, signée (pour les branchements)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Instructions&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Opérations à pointeur&lt;/th&gt;
&lt;th&gt;Mnemonic&lt;/th&gt;
&lt;th&gt;Imm&lt;/th&gt;
&lt;th&gt;Dir&lt;/th&gt;
&lt;th&gt;Ind&lt;/th&gt;
&lt;th&gt;Ext&lt;/th&gt;
&lt;th&gt;Inh&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;HINZVC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compare Index Reg&lt;/td&gt;
&lt;td&gt;CPX&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X - M : M + 1&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrement Index Reg&lt;/td&gt;
&lt;td&gt;DEX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X - 1-&amp;gt; X&lt;/td&gt;
&lt;td&gt;...!..&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrement SP&lt;/td&gt;
&lt;td&gt;DES&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;SP - 1-&amp;gt; SP&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increment Index Reg&lt;/td&gt;
&lt;td&gt;INX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X + 1-&amp;gt; X&lt;/td&gt;
&lt;td&gt;...!..&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increment SP&lt;/td&gt;
&lt;td&gt;INS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;SP + 1-&amp;gt; SP&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load Index Reg&lt;/td&gt;
&lt;td&gt;LDX&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M -&amp;gt; Xh, M+1 -&amp;gt; Xl&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load SP&lt;/td&gt;
&lt;td&gt;LDS&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M -&amp;gt; SPh, M+1 -&amp;gt; SPl&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store Index Reg&lt;/td&gt;
&lt;td&gt;STX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Xh -&amp;gt; M, Xl -&amp;gt; M+1&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store SP&lt;/td&gt;
&lt;td&gt;STS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;SPh -&amp;gt; M, SPl -&amp;gt; M+1&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index to Stack&lt;/td&gt;
&lt;td&gt;TXS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X - 1 -&amp;gt; SP&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack to Index&lt;/td&gt;
&lt;td&gt;TSX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;SP + 1 -&amp;gt; X&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add B with X&lt;/td&gt;
&lt;td&gt;ABX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B + X -&amp;gt; B&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Push X&lt;/td&gt;
&lt;td&gt;PSHX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Xl-&amp;gt;(SP),SP-1&amp;gt;SP,Xh...&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull X&lt;/td&gt;
&lt;td&gt;PULX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;(SP)+1-&amp;gt;SP,Xh-&amp;gt;Xh,...&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operations Acc. &amp;amp; Mémoire&lt;/th&gt;
&lt;th&gt;Mnemonic&lt;/th&gt;
&lt;th&gt;Imm&lt;/th&gt;
&lt;th&gt;Dir&lt;/th&gt;
&lt;th&gt;Ind&lt;/th&gt;
&lt;th&gt;Ext&lt;/th&gt;
&lt;th&gt;Inh&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;HINZVC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Add Accumulators&lt;/td&gt;
&lt;td&gt;ABA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A + B -&amp;gt; A&lt;/td&gt;
&lt;td&gt;!.!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add B to X&lt;/td&gt;
&lt;td&gt;ABX&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;00:B + X -&amp;gt; X&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add A with Carry&lt;/td&gt;
&lt;td&gt;ADCA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A + M + C -&amp;gt; A&lt;/td&gt;
&lt;td&gt;!.!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add B with Carry&lt;/td&gt;
&lt;td&gt;ADCB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B + M + C -&amp;gt; B&lt;/td&gt;
&lt;td&gt;!.!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add with A&lt;/td&gt;
&lt;td&gt;ADDA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A + M -&amp;gt; A&lt;/td&gt;
&lt;td&gt;!.!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add with B&lt;/td&gt;
&lt;td&gt;ADDB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B + M -&amp;gt; B&lt;/td&gt;
&lt;td&gt;!.!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add Double&lt;/td&gt;
&lt;td&gt;ADDD&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;D + M:M+1 -&amp;gt; D&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;And with A&lt;/td&gt;
&lt;td&gt;ANDA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A &amp;amp; M -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;And with B&lt;/td&gt;
&lt;td&gt;ANDB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B &amp;amp; M -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Left Arithmetic M&lt;/td&gt;
&lt;td&gt;ASL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B7 dans C, C dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Left Arithmetic A&lt;/td&gt;
&lt;td&gt;ASLA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B7 dans C, C dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Left Arithmetic B&lt;/td&gt;
&lt;td&gt;ASLB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B7 dans C, C dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Left Arithmetic D&lt;/td&gt;
&lt;td&gt;ASLD&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B15 dans C, C dans B0 ?&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Arithmetic M&lt;/td&gt;
&lt;td&gt;ASR&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B0 dans C, B7 dans B7&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Arithmetic A&lt;/td&gt;
&lt;td&gt;ASRA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B0 dans C, B7 dans B7&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Arithmetic B&lt;/td&gt;
&lt;td&gt;ASRB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B0 dans C, B7 dans B7&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bit Test A&lt;/td&gt;
&lt;td&gt;BITA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A &amp;amp; M, A non modifié&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bit Test B&lt;/td&gt;
&lt;td&gt;BITB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B &amp;amp; M, B non modifié&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare A/B with M&lt;/td&gt;
&lt;td&gt;CBA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A &amp;amp; B, A/B non modifié&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear Memory&lt;/td&gt;
&lt;td&gt;CLR&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;00 -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..0100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear A&lt;/td&gt;
&lt;td&gt;CLRA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;0 -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..0100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear B&lt;/td&gt;
&lt;td&gt;CLRB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;0 -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..0100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare with A&lt;/td&gt;
&lt;td&gt;CMPA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A - M&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare with B&lt;/td&gt;
&lt;td&gt;CMPB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B - M&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1's Complement M&lt;/td&gt;
&lt;td&gt;COM&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;~M -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1's Complement A&lt;/td&gt;
&lt;td&gt;COMA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;~A -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1's Complement B&lt;/td&gt;
&lt;td&gt;COMB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;~B -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decimal Adj. A&lt;/td&gt;
&lt;td&gt;DAA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Ajustement BCD&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrement M&lt;/td&gt;
&lt;td&gt;DEC&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M - 1 -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrement A&lt;/td&gt;
&lt;td&gt;DECA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A - 1 -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrement B&lt;/td&gt;
&lt;td&gt;DECB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B - 1 -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exclusive OR with A&lt;/td&gt;
&lt;td&gt;EORA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A ^ M -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exclusive OR with B&lt;/td&gt;
&lt;td&gt;EORB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B ^ M -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increment M&lt;/td&gt;
&lt;td&gt;INC&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M + 1 -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increment A&lt;/td&gt;
&lt;td&gt;INCA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A + 1 -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increment B&lt;/td&gt;
&lt;td&gt;INCB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B + 1 -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!!.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load to A&lt;/td&gt;
&lt;td&gt;LDAA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load to B&lt;/td&gt;
&lt;td&gt;LDAB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load to D&lt;/td&gt;
&lt;td&gt;LDD&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M:M+1 -&amp;gt; D&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical Shift Left M&lt;/td&gt;
&lt;td&gt;LSL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B7 dans C, 0 dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical Shift Left A&lt;/td&gt;
&lt;td&gt;LSLA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B7 dans C, 0 dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical Shift Left B&lt;/td&gt;
&lt;td&gt;LSLB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B7 dans C, 0 dans B0&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical Shift Left D&lt;/td&gt;
&lt;td&gt;LSLD&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B15 dans C, 0 dans B0 ?&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Logical M&lt;/td&gt;
&lt;td&gt;LSR&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B0 dans C, 0 dans B7&lt;/td&gt;
&lt;td&gt;..0!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Logical A&lt;/td&gt;
&lt;td&gt;LSRA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B0 dans C, 0 dans B7&lt;/td&gt;
&lt;td&gt;..0!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Logical B&lt;/td&gt;
&lt;td&gt;LSRB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B0 dans C, 0 dans B7&lt;/td&gt;
&lt;td&gt;..0!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shift Right Logical D&lt;/td&gt;
&lt;td&gt;LSRD&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B0 dans C, 0 dans B15 ?&lt;/td&gt;
&lt;td&gt;..0!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiply&lt;/td&gt;
&lt;td&gt;MUL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A * B -&amp;gt; D&lt;/td&gt;
&lt;td&gt;.....!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2's Complement M&lt;/td&gt;
&lt;td&gt;NEG&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-M -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2's Complement A&lt;/td&gt;
&lt;td&gt;NEGA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;-A -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2's Complement B&lt;/td&gt;
&lt;td&gt;NEGB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;-B -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No Operation&lt;/td&gt;
&lt;td&gt;NOP&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical OR with A&lt;/td&gt;
&lt;td&gt;ORAA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;M -&amp;gt; A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logical OR with B&lt;/td&gt;
&lt;td&gt;ORAB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;M -&amp;gt; B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Push A&lt;/td&gt;
&lt;td&gt;PSHA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A -&amp;gt; (SP), SP - 1 -&amp;gt; SP&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Push B&lt;/td&gt;
&lt;td&gt;PSHB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B -&amp;gt; (SP), SP - 1 -&amp;gt; SP&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull A&lt;/td&gt;
&lt;td&gt;PULA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;SP + 1 -&amp;gt; SP, (SP) -&amp;gt; A&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull B&lt;/td&gt;
&lt;td&gt;PULB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;SP + 1 -&amp;gt; SP, (SP) -&amp;gt; B&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Left M&lt;/td&gt;
&lt;td&gt;ROL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C dans B0, B7 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Left A&lt;/td&gt;
&lt;td&gt;ROLA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;C dans B0, B7 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Left B&lt;/td&gt;
&lt;td&gt;ROLB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;C dans B0, B7 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Right M&lt;/td&gt;
&lt;td&gt;ROR&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C dans B7, B0 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Right A&lt;/td&gt;
&lt;td&gt;RORA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;C dans B7, B0 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate Right B&lt;/td&gt;
&lt;td&gt;RORB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;C dans B7, B0 dans C&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract A with B&lt;/td&gt;
&lt;td&gt;SBA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A - B -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract with Carry with A&lt;/td&gt;
&lt;td&gt;SBCA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A - M - C -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract with Carry with B&lt;/td&gt;
&lt;td&gt;SBCB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B - M - C -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store A&lt;/td&gt;
&lt;td&gt;STAA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store B&lt;/td&gt;
&lt;td&gt;STAB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B -&amp;gt; M&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store D&lt;/td&gt;
&lt;td&gt;STD&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;D -&amp;gt; M:M+1&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract from A&lt;/td&gt;
&lt;td&gt;SUBA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;A - M -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract from B&lt;/td&gt;
&lt;td&gt;SUBB&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B - M -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract Double&lt;/td&gt;
&lt;td&gt;SUBD&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;D - M:M+1 -&amp;gt; D&lt;/td&gt;
&lt;td&gt;..!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer A to B&lt;/td&gt;
&lt;td&gt;TAB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A -&amp;gt; B&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer B to A&lt;/td&gt;
&lt;td&gt;TBA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B -&amp;gt; A&lt;/td&gt;
&lt;td&gt;..!!0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Zero or Minus M&lt;/td&gt;
&lt;td&gt;TST&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;M, M non modifié&lt;/td&gt;
&lt;td&gt;..!!00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Zero or Minus A&lt;/td&gt;
&lt;td&gt;TSTA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A, A non modifié&lt;/td&gt;
&lt;td&gt;..!!00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Zero or Minus B&lt;/td&gt;
&lt;td&gt;TSTB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;B, B non modifié&lt;/td&gt;
&lt;td&gt;..!!00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sauts et Branches&lt;/th&gt;
&lt;th&gt;Mnemonic&lt;/th&gt;
&lt;th&gt;Dir&lt;/th&gt;
&lt;th&gt;Rel&lt;/th&gt;
&lt;th&gt;Ind&lt;/th&gt;
&lt;th&gt;Ext&lt;/th&gt;
&lt;th&gt;Inh&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;HINZVC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Branch Always&lt;/td&gt;
&lt;td&gt;BRA&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch Never&lt;/td&gt;
&lt;td&gt;BRN&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Carry Clear&lt;/td&gt;
&lt;td&gt;BCC&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Carry Set&lt;/td&gt;
&lt;td&gt;BCS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C = 1&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Equal&lt;/td&gt;
&lt;td&gt;BEQ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Z = 1&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Greater or Equal&lt;/td&gt;
&lt;td&gt;BGE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;N ^ V = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Greater&lt;/td&gt;
&lt;td&gt;BGT&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;(N ^ V)&lt;/td&gt;
&lt;td&gt;Z = 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Higher&lt;/td&gt;
&lt;td&gt;BHI&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C + Z = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Higher or Same&lt;/td&gt;
&lt;td&gt;BHS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;C = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Less or Equal&lt;/td&gt;
&lt;td&gt;BLE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;(N ^ V)&lt;/td&gt;
&lt;td&gt;Z = 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Less than 0&lt;/td&gt;
&lt;td&gt;BLT&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;N ^ V = 1&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Minus&lt;/td&gt;
&lt;td&gt;BMI&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;N = 1&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Not Equal&lt;/td&gt;
&lt;td&gt;BNE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Z = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Overflow Clear&lt;/td&gt;
&lt;td&gt;BVC&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;V = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Overflow Set&lt;/td&gt;
&lt;td&gt;BVS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;V = 1&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch on Plus&lt;/td&gt;
&lt;td&gt;BPL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;N = 0&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch to Subroutine&lt;/td&gt;
&lt;td&gt;BSR&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jump&lt;/td&gt;
&lt;td&gt;JMP&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jump to Subroutine&lt;/td&gt;
&lt;td&gt;JSR&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return from Interrupt&lt;/td&gt;
&lt;td&gt;RTI&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;!!!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return from Subroutine&lt;/td&gt;
&lt;td&gt;RTS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software Interrupt&lt;/td&gt;
&lt;td&gt;SWI&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;!1!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wait for Interrupt&lt;/td&gt;
&lt;td&gt;WAI&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manipulation des drapeaux&lt;/th&gt;
&lt;th&gt;Mnemonic&lt;/th&gt;
&lt;th&gt;Inh&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;HINZVC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clear Carry&lt;/td&gt;
&lt;td&gt;CLC&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;0 -&amp;gt; C&lt;/td&gt;
&lt;td&gt;.....0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear Interrupt&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;0 -&amp;gt; I&lt;/td&gt;
&lt;td&gt;.0....&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear Overflow&lt;/td&gt;
&lt;td&gt;CLV&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;0 -&amp;gt; V&lt;/td&gt;
&lt;td&gt;....0.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set Carry&lt;/td&gt;
&lt;td&gt;SEC&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;1 -&amp;gt; C&lt;/td&gt;
&lt;td&gt;.....1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set Interrupt&lt;/td&gt;
&lt;td&gt;SEI&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;1 -&amp;gt; I&lt;/td&gt;
&lt;td&gt;.1....&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set Overflow&lt;/td&gt;
&lt;td&gt;SEV&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;1 -&amp;gt; V&lt;/td&gt;
&lt;td&gt;....1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accumulator to CCR&lt;/td&gt;
&lt;td&gt;TAP&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;A -&amp;gt; CCR&lt;/td&gt;
&lt;td&gt;!!!!!!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CCR to Accumulator&lt;/td&gt;
&lt;td&gt;TPA&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;CCR -&amp;gt; A&lt;/td&gt;
&lt;td&gt;......&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;Ports&lt;/h1&gt;
&lt;h2&gt;Port 1&lt;/h2&gt;
&lt;p&gt;P10-P17 : entrées/sorties, 8 bits. Toutes les lignes sont configurables en entrée ou en sortie indépendamment.&lt;/p&gt;
&lt;h2&gt;Port 2&lt;/h2&gt;
&lt;p&gt;P20-P24 : entrées/sorties, 5 bits.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;P20 et P21 déterminent le mode de fonctionnement du processeur (lors du reset)&lt;/li&gt;
&lt;li&gt;Si P21 est configuré en sortie, il est lié à la fonction de comparison du timer&lt;/li&gt;
&lt;li&gt;Peut être utilisé comme port série&lt;/li&gt;
&lt;li&gt;Les lignes sont configurables en entrée ou en sortie indépendamment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Port 3&lt;/h2&gt;
&lt;p&gt;P30-P37 : entrées/sorties, 8 bits. Adresses et données multiplexées. A0 à A7 et D0 à D7.&lt;/p&gt;
&lt;h2&gt;Port 4&lt;/h2&gt;
&lt;p&gt;P40-P47 : adressage de la mémoire externe, A8 à A15.&lt;/p&gt;
&lt;h1&gt;Mémoire interne&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;128 octets de RAM interne&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Timer programmable&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Compteur ($09:$0A) : lecture seule. Une écriture dans $09 reset le compteur à $FFF8, à éviter.&lt;/li&gt;
&lt;li&gt;Comparateur ($0B:$0C) : 16 bits, lecture/écriture. Lorsqu'il est égal au compteur, OCF est mis à 1.&lt;/li&gt;
&lt;li&gt;Capture d'entrée ($0D:$0E) : lecture seule. Enregistre la valeur du compteur lorsqu'une transition est détectée, tel que définie par IEG.&lt;/li&gt;
&lt;li&gt;Contrôle du Timer ($08) : lecture, écriture sur bits 0-4. Les bits de poids fort représentent l'état.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Machines"></category><category term="Motorola"></category><category term="6809"></category></entry><entry><title>Sous le capot de l'Alice 32/90, un EF9345</title><link href="https://www.triceraprog.fr/sous-le-capot-de-lalice-3290-un-ef9345.html" rel="alternate"></link><published>2024-01-04T00:00:00+01:00</published><updated>2024-01-04T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2024-01-04:/sous-le-capot-de-lalice-3290-un-ef9345.html</id><summary type="html">&lt;p&gt;La machine de la nouvelle session du « Retro Programmers United for Obscure Systems » est connue. C'est le Matra Alice. Et plus exactement les version 32 et 90, afin de s'échapper de la trop grande proximité entre le Alice premier du nom et le Tandy MC-10 (une telle proximité que ce sont les mêmes machines).&lt;/p&gt;
&lt;p&gt;Les versions 32 et 90 étant très similaires niveau hardware, je les nommerais conjointement Alice 32/90.&lt;/p&gt;
&lt;p&gt;Pour cet article, ce qui va m'intéresser est que l'Alice 32/90 utilise un EF9345, comme le VG5000. Et l'EF9345 étant aussi utilisé dans le VG5000µ, c'est une puce que je connais bien. Cependant, l'Alice 32/90 l'utilise différemment. Je dirais même qu'il l'utilise mieux.&lt;/p&gt;
&lt;p&gt;L'autre axe de cet article est que je veux utiliser l'EF9345 depuis le BASIC. La machine tournant avec un 6803, les I/O sont mappées en mémoire. Et il est donc possible d'accéder aux …&lt;/p&gt;</summary><content type="html">&lt;p&gt;La machine de la nouvelle session du « Retro Programmers United for Obscure Systems » est connue. C'est le Matra Alice. Et plus exactement les version 32 et 90, afin de s'échapper de la trop grande proximité entre le Alice premier du nom et le Tandy MC-10 (une telle proximité que ce sont les mêmes machines).&lt;/p&gt;
&lt;p&gt;Les versions 32 et 90 étant très similaires niveau hardware, je les nommerais conjointement Alice 32/90.&lt;/p&gt;
&lt;p&gt;Pour cet article, ce qui va m'intéresser est que l'Alice 32/90 utilise un EF9345, comme le VG5000. Et l'EF9345 étant aussi utilisé dans le VG5000µ, c'est une puce que je connais bien. Cependant, l'Alice 32/90 l'utilise différemment. Je dirais même qu'il l'utilise mieux.&lt;/p&gt;
&lt;p&gt;L'autre axe de cet article est que je veux utiliser l'EF9345 depuis le BASIC. La machine tournant avec un 6803, les I/O sont mappées en mémoire. Et il est donc possible d'accéder aux registres de l'EF9345 depuis le BASIC avec des PEEKs et POKEs. Pas besoin de passer par
l'assembleur. Par contre, pas de mystère, c'est lent !&lt;/p&gt;
&lt;h2&gt;Le mode graphique en BASIC sur l'Alice&lt;/h2&gt;
&lt;p&gt;Première chose amusante, l'Alice 32/90 démarre dans un mode 32 colonnes qui n'existe pas pour l'EF9345. Je pense que ce mode par défaut, qui utilise en fait le mode 40 colonnes de l'EF9345, est là pour être compatible avec le Alice 4k au niveau BASIC. Pour assurer cette compatibilité, des caractères utilisateurs sont chargés dans la RAM vidéo au démarrage pour représenter les différentes combinaison d'un bloc de 2x2 « gros pixels » pour chaque caractère.&lt;/p&gt;
&lt;p&gt;L'Alice 32/90 peut cependant utiliser l'EF9345 en vrai mode 40 colonnes, et même en mode 80 colonnes. Pour cela passer d'un mode à l'autre, il faut utiliser les commandes CLS32, CLS40 et CLS80. Je vais me concentrer sur le mode 40 colonnes.&lt;/p&gt;
&lt;p&gt;Celui-ci est initialisé dans le mode « 40 CHAR LONG ». C'est un mode qui prend trois pages de 1Ko en mémoire vidéo. La première page contient les caractères, la deuxième les attributs et la troisième les couleurs. Ça fait beaucoup sur les 8ko de RAM vidéo de la machine, et le VG5000µ avait fait le choix d'utilise le mode « 40 CHAR SHORT » qui ne prend que 2ko. Cependant, on y gagner en simplicité et flexibilité au niveau des attributs.&lt;/p&gt;
&lt;p&gt;Autre choix de l'Alice : le système ne conserve pas de miroir en RAM de l'affichage. Là encore, bon choix pour l'utilisation de la RAM principale. En contrepartie cela signifie que les opérations non prévues par le BASIC devront se faire en s'adressant directement à l'EF9345.&lt;/p&gt;
&lt;p&gt;Plus techniquement, le mode est initialisé avec les registres suivants :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TGS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaire&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;00010000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;312&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lignes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entrelacées&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;synchro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;composite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;synchro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entrante&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaire&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;00101000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couleur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;marge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;noire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curseur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;complet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clignotant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curseur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;désactivé&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;simple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hauteur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x67&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaire&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;01100111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bulk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;haut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;conceal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;désactivé&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;activé&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaire&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;00010011&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;0 située en Z = 3, page G&amp;#39;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;située&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;située&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x08&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaire&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;00001000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;première&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ligne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bulk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;origine Z = 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Les registres de l'EF9345&lt;/h2&gt;
&lt;p&gt;Depuis le processeur, l'EF9345 est accessible via 8 registres. Ces registres sont accessibles en lecture et écriture, et sont tous des registres de 8 bits. Ils sont accessibles via les adresses suivantes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;- R0 = $BF20 ; 48928 (commande)
- R1 = $BF21 ; 48929 (paramètre principal)
- R2 = $BF22 ; 48930 (paramètre)
- R3 = $BF23 ; 48931 (paramètre)
- R4 = $BF24 ; 48932 (pointeur auxiliaire haut)
- R5 = $BF25 ; 48933 (pointeur auxiliaire bas)
- R6 = $BF26 ; 48934 (pointeur principal haut)
- R7 = $BF27 ; 48935 (pointeur principal bas)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Une adresse supplémentaire est située en $BF28 (48936). Il s'agit en fait de R0 mais avec le flag d'exécution (bit 7 du numéro de registre) mis à 1. Cela permet de demander à l'EF9345 d'exécuter la commande indiquée dans R0.&lt;/p&gt;
&lt;p&gt;Techniquement, n'importe quel registre peut être utilisé pour exécuter une commande en mettant le bit 7 à 1. Cela permet d'ailleurs quelques optimisations. Je n'ai pas vérifié si les adresses au delà de $BF28 étaient mappées. Si ce n'est pas le cas, on n'utilisera pas, voire jamais, R0 directement en écriture directement, mais toujours via le « faux registre » R8.&lt;/p&gt;
&lt;p&gt;Note additionnel : le livre "les astuces d'Alice 32 et 90" indique qu'il est en effet possible d'utiliser tous les registres en mode « exécution ».&lt;/p&gt;
&lt;h2&gt;Un premier affichage&lt;/h2&gt;
&lt;p&gt;Voici un programme qui place tous les registres directs correctement pour afficher un « A » à l'écran sur la ligne 0 (ligne de service), colonne 10. Notez que cela fonctionnera parfaitement en mode CLS32. Vous pouvez vous amuser à écrire où vous voulez dans l'espace de 40 colonnes par 25 lignes pour constater que le mode 32 colonnes est en fait le mode 40.&lt;/p&gt;
&lt;p&gt;Attention, dans cette configuration de l'EF9345, la deuxième ligne affichée est la ligne... numéro 8.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM AFFICHE UN CARACTERE&lt;/span&gt;
&lt;span class="nl"&gt;110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;COMMANDE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;INUTILE&lt;/span&gt;
&lt;span class="nl"&gt;120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;65&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;130&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48930&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;140&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48931&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;150&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48932&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;NA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;160&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48933&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;NA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;170&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48934&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;MP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LIGNE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48935&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;10&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;MP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;COL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;190&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Une démonstration plus complète&lt;/h2&gt;
&lt;p&gt;Voici un programme de démonstration plus complet, mais pas entièrement, puisqu'il y a plein de choses à faire avec l'EF9345 qui ne sont pas démontrées ici.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt; : je n'ai pas du tout testé sur vrai matériel. L'EF9345 étant sensible aux synchronisations (on ne peut pas lui parler n'importe quand), je ne sais pas à quel point le BASIC est capable de gérer cela. Il est possible que ce programme ne fonctionne pas bien sur vrai matériel. Je suis preneur de retours (et j'essaierai moi même un de ces jours).&lt;/p&gt;
&lt;p&gt;Voici quelques commentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;En ligne 100, on initialise les registres nécessaires pour afficher une chaîne de caractère utilisant les mêmes attributs.&lt;/li&gt;
&lt;li&gt;En ligne 200, on initialise les registres restants pour afficher un caractère et passer à la colonne suivante (attention, il n'y a pas de détection de fin de ligne).&lt;/li&gt;
&lt;li&gt;En ligne 300, on initialise tous les registres pour afficher un caractère avec des attributs différents. Dans les commentaires &lt;code&gt;KRF&lt;/code&gt; est le nom de la commande d'affichage d'un caractère en mode « 40 CHAR LONG ».&lt;/li&gt;
&lt;li&gt;En ligne 400, une routine se charge de monter en mémoire vidéo les données pour un caractère utilisateur.&lt;/li&gt;
&lt;li&gt;En ligne 10000, c'est le début du test et j'affichage "BONJOUR". C'est un PRINT en bien plus compliqué et bien plus lent...&lt;/li&gt;
&lt;li&gt;En ligne 10100, j'affiche les 128 caractères alphanumériques en ROM de l'EF9345.&lt;/li&gt;
&lt;li&gt;En ligne 10200, j'affiche une autre plage de 32 caractères, graphiques, en ROM de l'EF9345.&lt;/li&gt;
&lt;li&gt;En ligne 10300, j'affiche les 128 caractères semi-graphiques en ROM de l'EF9345. Dans ces trois affichages, c'est la variable B qui indique le type de caractères à utiliser.&lt;/li&gt;
&lt;li&gt;En ligne 10400, j'affiche un caractère graphique plein pour montrer les 16 teintes disponibles pour les caractères.&lt;/li&gt;
&lt;li&gt;En ligne 11000, je tente de lire les registres indirects de l'EF9345. Cela ne fonctionne pas tout à fait bien. Possible que ce soit un problème de synchro (d'où la petite boucle, même si 1/ ce n'est pas comme cela qu'on synchronise l'EF9345 2/ la lenteur du BASIC me fait penser que quoique l'on fasse, il y a toujours un risque de tomber au mauvais moment).&lt;/li&gt;
&lt;li&gt;En ligne 12300, je modifie le registre indirect ROR afin de faire un scrolling vertical. Comme la mémoire « sous » l'écran n'est pas préparée, cela affiche un peu n'importe quoi. C'est surtout une démonstration de l'utilisation de registre indirect en écriture.&lt;/li&gt;
&lt;li&gt;En ligne 13000, je charge un caractère utilisateur (le bonhomme du manuel du VG5000µ) puis j'affichage un des « sets » de caractères redéfinis. Particularité : c'est un ensemble de 100 caractères allant de 0 à 3, puis de 32 à 127... L'adresse de destination &lt;code&gt;A=192&lt;/code&gt; est aussi assez compliquée à calculer (en tout cas, ça ne s'invente pas, et le datasheet demande une grande attention, je ferai peut-être un article séparé là-dessus). Dans les caractères affichés, vous verrez les blocs redéfinis pour la compatibilité avec l'Alice 4k.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour la manière dont fonctionne la mémoire de l'EF9345, en attendant un article, vous pouvez tentez de comprendre avec le code du fichier &lt;code&gt;ef9345_memory.py&lt;/code&gt; dans mon &lt;a href="https://github.com/Triceraprog/vg5000_tools"&gt;dépôt GitHub&lt;/a&gt; dédié aux outils d'étude pour le VG5000µ.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CLS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;10000&lt;/span&gt;

&lt;span class="nl"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PREPARATION AFFICHAGE CARACTERE&lt;/span&gt;
&lt;span class="nl"&gt;110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48930&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;
&lt;span class="nl"&gt;120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48931&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;130&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48934&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;
&lt;span class="nl"&gt;140&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48935&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;
&lt;span class="nl"&gt;150&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM AFFICHE UN CARACTERE AVEC INCREMENTATION&lt;/span&gt;
&lt;span class="nl"&gt;210&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;220&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;INCR&lt;/span&gt;
&lt;span class="nl"&gt;230&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM AFFICHE UN SEUL CARACTERE COMPLET&lt;/span&gt;
&lt;span class="nl"&gt;310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48930&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;
&lt;span class="nl"&gt;330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48931&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48934&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;
&lt;span class="nl"&gt;350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48935&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;
&lt;span class="nl"&gt;360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KRF&lt;/span&gt;
&lt;span class="nl"&gt;370&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM CHARGEMENT D&amp;#39;UN CARACTERE REDÉFINI&lt;/span&gt;
&lt;span class="nl"&gt;410&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;10&lt;/span&gt;
&lt;span class="nl"&gt;420&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;READ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;430&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48932&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kr"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;440&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48933&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;255&lt;/span&gt;
&lt;span class="nl"&gt;450&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;460&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;OCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;AUX_PTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;470&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;
&lt;span class="nl"&gt;480&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;490&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;10000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PROGRAMME DE TEST&lt;/span&gt;
&lt;span class="nl"&gt;10010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;COORDONNEE&lt;/span&gt;
&lt;span class="nl"&gt;10020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ATTRIBUTS&lt;/span&gt;
&lt;span class="nl"&gt;10030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BONJOUR&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;10040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;100&lt;/span&gt;
&lt;span class="nl"&gt;10050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;MID$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nl"&gt;10070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;200&lt;/span&gt;
&lt;span class="nl"&gt;10080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;

&lt;span class="nl"&gt;10100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM AFFICHAGE DE CARACTERES&lt;/span&gt;
&lt;span class="nl"&gt;10110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;
&lt;span class="nl"&gt;10120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;
&lt;span class="nl"&gt;10130&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;39&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10140&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10150&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;10160&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;

&lt;span class="nl"&gt;10200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;12&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;
&lt;span class="nl"&gt;10210&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;31&lt;/span&gt;
&lt;span class="nl"&gt;10220&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;10230&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10240&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;

&lt;span class="nl"&gt;10300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;13&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;
&lt;span class="nl"&gt;10310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;
&lt;span class="nl"&gt;10320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;39&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;10340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;

&lt;span class="nl"&gt;10400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM COULEURS&lt;/span&gt;
&lt;span class="nl"&gt;10410&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;17&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;
&lt;span class="nl"&gt;10420&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;16&lt;/span&gt;
&lt;span class="nl"&gt;10430&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;10440&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10450&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;10460&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;18&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;33&lt;/span&gt;
&lt;span class="nl"&gt;10470&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;16&lt;/span&gt;
&lt;span class="nl"&gt;10480&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;10490&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;10500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;

&lt;span class="nl"&gt;11000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM LECTURE DES REGISTRES INDIRECTS&lt;/span&gt;
&lt;span class="nl"&gt;11010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;TGS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;11020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;T&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;11030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TGS=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;T:&lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;11040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;MAT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;11050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;11060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;MAT=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;M:&lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;11070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PAT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;11080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;11090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PAT=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;P:&lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;11110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;11120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;11130&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DOR=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;D:&lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;11140&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;11150&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LECTURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;11160&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ROR=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="vg"&gt;R&lt;/span&gt;

&lt;span class="nl"&gt;12300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM CHANGE ROR POUR SCROLLING&lt;/span&gt;
&lt;span class="nl"&gt;12310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;31&lt;/span&gt;
&lt;span class="nl"&gt;12320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;I:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ECRITURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;12330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ECRITURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;12340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;J&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;J&lt;/span&gt;
&lt;span class="nl"&gt;12350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;12360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48929&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ECRITURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R1&lt;/span&gt;
&lt;span class="nl"&gt;12370&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;48936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;IND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ECRITURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;13000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM CARACTERES REDÉFINIS&lt;/span&gt;
&lt;span class="nl"&gt;13010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;93&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;93&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;99&lt;/span&gt;
&lt;span class="nl"&gt;13020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;192&lt;/span&gt;
&lt;span class="nl"&gt;13030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;400&lt;/span&gt;

&lt;span class="nl"&gt;13100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;16&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;112&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;GP11&lt;/span&gt;
&lt;span class="nl"&gt;13110&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;
&lt;span class="nl"&gt;13120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;39&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;13125&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;
&lt;span class="nl"&gt;13130&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;300&lt;/span&gt;
&lt;span class="nl"&gt;13140&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;X&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;13150&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;

&lt;span class="nl"&gt;14000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;14000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="Matra Alice"></category><category term="EF9345"></category></entry><entry><title>Dans la prison hantée sur AgonLight</title><link href="https://www.triceraprog.fr/dans-la-prison-hantee-sur-agonlight.html" rel="alternate"></link><published>2023-12-21T00:00:00+01:00</published><updated>2023-12-21T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-12-21:/dans-la-prison-hantee-sur-agonlight.html</id><summary type="html">&lt;p&gt;Comme présenté dans un article précédent, j'ai participé à la game jam &lt;a href="https://itch.io/jam/rpuos-camputers-lynx/entries"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, organisée par &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt;. Le principe est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque (moins de 100 titres).&lt;/p&gt;
&lt;p&gt;Après avoir terminé ma contribution sur le Lynx, je me suis dit qu'un portage pour l'AgonLight serait intéressant et plutôt facile. Les capacités graphiques sont bien supérieures, et le processeur est un Z80, supporté par la même toolchain que j’avais utilisée pour le Lynx (z88dk).&lt;/p&gt;
&lt;p&gt;Un petit mois plus tard, c'est chose faite. Le jeu est &lt;a href="https://mokona78.itch.io/dans-la-prison-hante"&gt;disponible sur itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J'en ai profité pour ajouter une version en anglais et une version en esperanto. Puisque tout est développé depuis les mêmes sources, ces versions sont aussi disponibles sur le Lynx. &lt;/p&gt;
&lt;p&gt;Au passage, la taille de l'exécutable a été un tout petit peu réduite. Pas assez pour entrer …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Comme présenté dans un article précédent, j'ai participé à la game jam &lt;a href="https://itch.io/jam/rpuos-camputers-lynx/entries"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt;, organisée par &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt;. Le principe est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque (moins de 100 titres).&lt;/p&gt;
&lt;p&gt;Après avoir terminé ma contribution sur le Lynx, je me suis dit qu'un portage pour l'AgonLight serait intéressant et plutôt facile. Les capacités graphiques sont bien supérieures, et le processeur est un Z80, supporté par la même toolchain que j’avais utilisée pour le Lynx (z88dk).&lt;/p&gt;
&lt;p&gt;Un petit mois plus tard, c'est chose faite. Le jeu est &lt;a href="https://mokona78.itch.io/dans-la-prison-hante"&gt;disponible sur itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J'en ai profité pour ajouter une version en anglais et une version en esperanto. Puisque tout est développé depuis les mêmes sources, ces versions sont aussi disponibles sur le Lynx. &lt;/p&gt;
&lt;p&gt;Au passage, la taille de l'exécutable a été un tout petit peu réduite. Pas assez pour entrer sur la version Lynx 48k malheureusement. Et en projetant le gain potentiel en travaillant la compression des données, j'ai assez peu d'espoir d'y arriver. Cela pourrait probablement être possible en reprogrammant le jeu en assembleur, mais j'ai déjà passé assez de temps sur ce projet et j'ai envie de passer à autre chose. De plus, je perdrai la possibilité d'un portage facile sur une machine avec un autre processeur.&lt;/p&gt;
&lt;p&gt;J'ai aussi publié &lt;a href="https://github.com/Mokona/in-the-haunted-prison"&gt;les sources du jeu sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;À bientôt pour de nouvelles aventures !&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dans la prison hantée sur AgonLight2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202312/20231221-RunningOnAgonLight2-750.jpg"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="RPUfOS"></category><category term="AgonLight"></category></entry><entry><title>VG5000µ, Schémas de principe mis à jour en v1.5</title><link href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v15.html" rel="alternate"></link><published>2023-11-21T00:00:00+01:00</published><updated>2023-11-21T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-11-21:/vg5000m-schemas-de-principe-mis-a-jour-en-v15.html</id><content type="html">&lt;p&gt;Et voici une nouvelle mise à jour du schéma de principe.&lt;/p&gt;
&lt;p&gt;Il y a une seule modification par rapport à la version 1.4, qui est l'ajout du mode international lorsque la diode &lt;code&gt;6602&lt;/code&gt; relie le signal &lt;code&gt;NMI/&lt;/code&gt; au &lt;code&gt;Y3/&lt;/code&gt; de &lt;code&gt;7807&lt;/code&gt;. Avec cette diode présente, le VG5000µ passe en anglais.&lt;/p&gt;
&lt;p&gt;Merci à &lt;em&gt;Etno&lt;/em&gt; pour cette information.&lt;/p&gt;
&lt;p&gt;Ce qui donne, mis à jour.&lt;/p&gt;
&lt;h4&gt;La platine principale&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 21 novembre 2023)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/202311/VG5000-Schema-v1.5.png"&gt;&lt;img alt="Platine principale" src="https://www.triceraprog.fr/images/202311/VG5000-Schema-v1.5-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;La platine K7/Son&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2.png"&gt;&lt;img alt="Platine K7/Son" src="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Rappel des versions précédentes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe.html"&gt;première version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour.html"&gt;version 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v14.html"&gt;version 1.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Schéma"></category></entry><entry><title>Un an de Retro Programmers United for Obscure Systems</title><link href="https://www.triceraprog.fr/un-an-de-retro-programmers-united-for-obscure-systems.html" rel="alternate"></link><published>2023-11-20T00:00:00+01:00</published><updated>2023-11-20T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-11-20:/un-an-de-retro-programmers-united-for-obscure-systems.html</id><summary type="html">&lt;p&gt;Un peu plus d'un an en fait, puisque &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; lance ce groupe en juin 2022. L'idée, je le rappelle, est d'offrir à des machines qui en leur temps n'ont pas eu une grande ludothèque quelques titres supplémentaires, dans un format game jam de trois mois (souvent étendus à quatre).&lt;/p&gt;
&lt;p&gt;Dans cet article, je vais revenir rapidement sur les 4 jeux que j'ai développés à cette occasion, avec quelques commentaires.&lt;/p&gt;
&lt;h2&gt;VG5000µ : La Maison dans la colline&lt;/h2&gt;
&lt;p&gt;La première machine choisie a été le VG5000µ, une machine que, vous le savez si vous suivez ce blog, j'étudie depuis un moment. Pour un premier développement réel (autre que des tests), je voulais un affichage rapide, mais sans aller dans un jeu rapide. L'idée du jeu d'aventure graphique avec support de texte est arrivée rapidement.&lt;/p&gt;
&lt;p&gt;J'ai commencé ici une &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;série d'articles&lt;/a&gt; sur le développement du jeu.&lt;/p&gt;
&lt;p&gt;Le jeu est développé avec &lt;a href="https://z88dk.org/"&gt;z88dk&lt;/a&gt;, en C …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Un peu plus d'un an en fait, puisque &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; lance ce groupe en juin 2022. L'idée, je le rappelle, est d'offrir à des machines qui en leur temps n'ont pas eu une grande ludothèque quelques titres supplémentaires, dans un format game jam de trois mois (souvent étendus à quatre).&lt;/p&gt;
&lt;p&gt;Dans cet article, je vais revenir rapidement sur les 4 jeux que j'ai développés à cette occasion, avec quelques commentaires.&lt;/p&gt;
&lt;h2&gt;VG5000µ : La Maison dans la colline&lt;/h2&gt;
&lt;p&gt;La première machine choisie a été le VG5000µ, une machine que, vous le savez si vous suivez ce blog, j'étudie depuis un moment. Pour un premier développement réel (autre que des tests), je voulais un affichage rapide, mais sans aller dans un jeu rapide. L'idée du jeu d'aventure graphique avec support de texte est arrivée rapidement.&lt;/p&gt;
&lt;p&gt;J'ai commencé ici une &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;série d'articles&lt;/a&gt; sur le développement du jeu.&lt;/p&gt;
&lt;p&gt;Le jeu est développé avec &lt;a href="https://z88dk.org/"&gt;z88dk&lt;/a&gt;, en C avec un peu d'assembleur pour l'affichage. J'ai aussi réalisé tous les graphismes (et ça se voit ?) avec &lt;a href="https://orama-interactive.itch.io/pixelorama"&gt;Pixelorama&lt;/a&gt;. Pour les outils de données, c'est du Python avec un fichier de description du jeu, qui sort les données binaires injectées dans l'exécutable.&lt;/p&gt;
&lt;p&gt;Le jeu est disponible sur &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Olipix fait une revue du jeu &lt;a href="https://www.youtube.com/watch?v=nFzPpzOrcEU&amp;amp;t=1347s"&gt;dans cette vidéo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="La maison dans la colline" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202311/RPUfOS-Maison.png"&gt;&lt;/p&gt;
&lt;h2&gt;EXL100 : Plouf... in space&lt;/h2&gt;
&lt;p&gt;La deuxième machine choisie a été l'EXL100, une machine que je ne connaissais pas du tout. Et une machine plutôt exotique. Un processeur que je ne connais pas, l'essentiel de la mémoire utilisable non adressable par le processeur... et un synthétiseur vocal plutôt difficile à utiliser.&lt;/p&gt;
&lt;p&gt;J'avais quelques idées pour utiliser la machine, mais j'ai rapidement compris que le temps de me familiariser avec et de faire des tests, je n'aurais pas le temps de faire un jeu. J'ai donc changé d'avis et suis partie sur un jeu programmé en BASIC, qui permet facilement d'utiliser toute la mémoire. Et pour le type de jeu, un touché-coulé, mais avec un twist : les bateaux sont en mouvement. Je n'étais pas très certain que le gameplay donne quelque chose, mais au final et après quelques ajustements, ça fonctionne plutôt bien.&lt;/p&gt;
&lt;p&gt;Sur la fin, les calculs en BASIC commençaient à être un peu lents, et j'ai donc ajouté un peu d'assembleur dans le peu de mémoire adressable par le processeur. J'ai utilisé l'assembleur &lt;a href="http://john.ccac.rwth-aachen.de:8000/as/"&gt;ASL&lt;/a&gt; qui est un des rares supportant le TMS7020. J'y associe un petit script en Python pour générer les DATA pour le BASIC. C'était assez manuel, je n'aime pas trop ça, mais comme souvent : manque de temps pour des choix assez tardifs.&lt;/p&gt;
&lt;p&gt;Puis les bateaux sont devenus des vaisseaux parce que... parce que.&lt;/p&gt;
&lt;p&gt;Je voulais aussi redéfinir quelques caractères pour un affichage plus sympa, mais je n'ai pas eu le temps. Peut-être un jour si je ressors l'idée ?&lt;/p&gt;
&lt;p&gt;Le jeu est disponible sur &lt;a href="https://mokona78.itch.io/plouf-in-space"&gt;itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Olipix fait une revue du jeu &lt;a href="https://www.youtube.com/watch?v=QxLnOV9Y8fA"&gt;dans cette vidéo&lt;/a&gt;, dans laquelle nous avons aussi discuté du développement du jeu.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Plouf... in space" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202311/RPUfOS-Plouf.png"&gt;&lt;/p&gt;
&lt;h2&gt;Aquarius : Le jardin des œufs&lt;/h2&gt;
&lt;p&gt;La troisième machine a été l'Aquarius. Retour à du Z80 qui m'est familier. Et une machine simple. Dépouillée même. L'avantage pour le graphisme, c'est qu'il faut faire avec les caractères de la machine. Heureusement, un éditeur dédié à la machine est &lt;a href="https://aquarius.mattpilz.com/draw/"&gt;disponible en ligne&lt;/a&gt;, ce qui a bien simplifié les choses.&lt;/p&gt;
&lt;p&gt;Comme la fin de la game jam était autour de Pâques, j'ai voulu faire thématique avec une chasse au œufs. Dans la lignée des anciens jeux avec des plateformes qui n'ont pas vraiment de sens, j'ai designé un jardin étrange, avec quelques éléments de game design classiques.&lt;/p&gt;
&lt;p&gt;Dans tous ces jeux, je pars d'un principe : les joueurs de retro n'ont souvent pas vraiment de temps à passer sur ces machines, particulièrement celles qui ne sortent jamais. Je vise donc des jeux courts, quelque chose qui puisse se découvrir et se terminer en une vingtaine de minutes. Quitte à se qu'il se termine en moins de 5 minutes lorsque l'on connaît la solution.&lt;/p&gt;
&lt;p&gt;Puisque le jeu se termine rapidement, j'ai ajouté un compteur de mouvements, avec d'y associer une sorte de time attack... mais sans temps.&lt;/p&gt;
&lt;p&gt;Le jeu est entièrement en assembleur, utilisant &lt;a href="https://z00m128.github.io/sjasmplus/documentation.html"&gt;sjasmplus&lt;/a&gt;, un assembleur que j'avais essayé auparavant et que je voulais creuser un peu plus. C'était l'occasion. Un jeu tout en assembleur, ça prend un peu plus de temps à développer, par contre, question mémoire, ça permettait de faire petit. Et encore, il y a de la marge d'optimisation.&lt;/p&gt;
&lt;p&gt;Le jeu est disponible sur &lt;a href="https://mokona78.itch.io/le-jardin-des-oeufs"&gt;itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Olipix fait une revue du jeu &lt;a href="https://youtu.be/K7NlEP6SVcw?si=Rjaa_zgFN2Lx2v97&amp;amp;t=1800"&gt;dans cette vidéo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le jardin des œufs" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202311/RPUfOS-Jardin.png"&gt;&lt;/p&gt;
&lt;h2&gt;Camputers Lynx : Dans la prison hantée&lt;/h2&gt;
&lt;p&gt;Une nouvelle session, et une nouvelle machine sortie de nulle part. J'avais connaissance de la machine, mais je ne m'étais jamais penché dessus et... quel étonnement. Cette machine a été conçue avec des choix originaux. C'est du Z80, bon point pour moi. La partie vidéo est aussi très intéressante avec des pixels indépendants en couleur les uns des autres. Une rareté pour l'époque. Bien entendu, je me dis qu'il faudra absolument utiliser cette particularité.&lt;/p&gt;
&lt;p&gt;J'ai passé un bon moment sur la machine sur des tests variés. Les limitations d'accès à la RAM, avec un mapping vraiment pas simple, et des émulateurs pas très aboutis m'ont fait désespérer une paire de fois. J'ai souvent mis le projet sur le côté.&lt;/p&gt;
&lt;p&gt;Pour le jeu, je voulais aller du côté de Temple of Apshaï, un jeu qui m'avait marqué étant petit. Comme d'habitude, dans une formule courte. Vu tout le temps passés à faire des tests et à procrastiner, j'ai aussi fait le choix d'utiliser un set de sprites désigné par &lt;a href="https://kenney.nl/"&gt;Kenney&lt;/a&gt;. Sur base d'un set noir et blanc, j'ai ajouté un peu de couleurs, puisque je voulais utiliser les capacités de la machine en la matière.&lt;/p&gt;
&lt;p&gt;Initialement, j'étais parti sur la réutilisation du format et des scripts de la Maison dans la Colline. Cependant, j'avais un peu luté avec le côté semi-manuel de la méthode. J'ai donc décidé d'utiliser &lt;a href="https://www.mapeditor.org/"&gt;Tiled&lt;/a&gt; pour la conception des niveaux, et un script Python pour générer les données. Tiled est vraiment sympa à utiliser et je pense que je le réutiliserai dans le futur pour des projets similaires.&lt;/p&gt;
&lt;p&gt;Pour le code, j'ai utilisé &lt;a href="https://z88dk.org/"&gt;z88dk&lt;/a&gt; avec un peu d'assembleur pour l'affichage, mais beaucoup moins que pour le VG5000µ. Je voulais réutiliser le principe d'affichage rapide, mais les émulateurs Lynx ne supportent pas (encore ?) la redirection du vecteur d'interruption pour la VSYNC. J'ai rapidement fait une croix dessus. N'ayant pas accès à cette machine, je devais absolument faire avec les émulateurs.&lt;/p&gt;
&lt;p&gt;Aussi, rapidement, j'ai compris que le jeu n'entrerais pas en mémoire de la version 48k, mais uniquement sur la version 96k (cela semble beaucoup, mais de cette mémoire, 32ko sont réservés pour la vidéo).&lt;/p&gt;
&lt;p&gt;Le jeu est disponible sur &lt;a href="https://mokona78.itch.io/dans-la-prison-hante"&gt;itch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Retro VynZ a fait une partie filmée &lt;a href="https://www.youtube.com/watch?v=WOuM0tr9eTg"&gt;sur sa chaîne YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Olipix présente le jeu, suivi d'un petit échange &lt;a href="https://youtu.be/QKNcR9iI_K0"&gt;sur sa chaîne YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dans la prison hantée" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202311/RPUfOS-Prison.png"&gt;&lt;/p&gt;
&lt;h2&gt;Et la suite ?&lt;/h2&gt;
&lt;p&gt;J'ai passé de bons moments sur ces projets. Découvrir ces machines est un plaisir (même si elles sont parfois un peu énervantes), cela profite un peu (un tout petit peu) à leur visibilité, à leur redécouverte. Et si ça n'amuse que nous, c'est déjà ça.&lt;/p&gt;
&lt;p&gt;Je ne connais pas encore la prochaine machine, je ne sais donc pas vers où je vais aller, mais j'ai en tête deux défis : utiliser un peu plus de couleurs et, pour la première fois, ajouter du son !&lt;/p&gt;
&lt;p&gt;À bientôt pour de nouvelles aventures !&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="RPUfOS"></category></entry><entry><title>La palette de couleur de l'Agon Light</title><link href="https://www.triceraprog.fr/la-palette-de-couleur-de-lagon-light.html" rel="alternate"></link><published>2023-06-10T00:00:00+02:00</published><updated>2023-06-10T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-06-10:/la-palette-de-couleur-de-lagon-light.html</id><summary type="html">&lt;p&gt;Ces derniers temps, je m'amuse avec un &lt;a href="https://github.com/TheByteAttic/AgonLight"&gt;AgonLight&lt;/a&gt; (ou plus exactement un AgonLight2, qui est la &lt;a href="https://www.olimex.com/Products/Retro-Computers/AgonLight2/open-source-hardware"&gt;version Olimex&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Cette machine est assez récente et possède une petite communauté. Sa documentation est par contre très éparse pour le moment. Du plus, la partie graphique de la machine se reposant sur &lt;a href="http://www.fabglib.org/"&gt;FabGL&lt;/a&gt;, une partie des informations intéressantes sont en fait à déduire de cette bibliothèque. Mais d'autres se déduisent de l'implémentation pour la machine du BBC Basic.&lt;/p&gt;
&lt;p&gt;Je vais me servir de ce blog pour prendre quelques notes. Cette semaine, j'ai tourné en rond autour de la gestion de la palette et des modes graphiques disponibles.&lt;/p&gt;
&lt;h2&gt;Modes graphiques&lt;/h2&gt;
&lt;p&gt;Les modes graphiques, à cette date (MOS 1.03), sont :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Résolution (Pixels)&lt;/th&gt;
&lt;th&gt;Fréquence (Hz)&lt;/th&gt;
&lt;th&gt;Nb. de couleurs&lt;/th&gt;
&lt;th&gt;Palette?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1024x768&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;512x384&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;320x200&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;Non&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;640x480&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Palette de couleurs&lt;/h2&gt;
&lt;p&gt;Dans les …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ces derniers temps, je m'amuse avec un &lt;a href="https://github.com/TheByteAttic/AgonLight"&gt;AgonLight&lt;/a&gt; (ou plus exactement un AgonLight2, qui est la &lt;a href="https://www.olimex.com/Products/Retro-Computers/AgonLight2/open-source-hardware"&gt;version Olimex&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Cette machine est assez récente et possède une petite communauté. Sa documentation est par contre très éparse pour le moment. Du plus, la partie graphique de la machine se reposant sur &lt;a href="http://www.fabglib.org/"&gt;FabGL&lt;/a&gt;, une partie des informations intéressantes sont en fait à déduire de cette bibliothèque. Mais d'autres se déduisent de l'implémentation pour la machine du BBC Basic.&lt;/p&gt;
&lt;p&gt;Je vais me servir de ce blog pour prendre quelques notes. Cette semaine, j'ai tourné en rond autour de la gestion de la palette et des modes graphiques disponibles.&lt;/p&gt;
&lt;h2&gt;Modes graphiques&lt;/h2&gt;
&lt;p&gt;Les modes graphiques, à cette date (MOS 1.03), sont :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Résolution (Pixels)&lt;/th&gt;
&lt;th&gt;Fréquence (Hz)&lt;/th&gt;
&lt;th&gt;Nb. de couleurs&lt;/th&gt;
&lt;th&gt;Palette?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1024x768&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;512x384&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;320x200&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;Non&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;640x480&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Oui&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Palette de couleurs&lt;/h2&gt;
&lt;p&gt;Dans les modes en palette, les couleurs se choisissent parmi l'espace de couleur complet RGB222. Les 4 niveaux pour chaque composante sont 0x00, 0x55, 0xAA et 0xFF. Ce qui donne :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Palette RGB222 de l'AgonLight" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202306/AgonLight-Palette.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention, la palette est réinitialisée lors d'un changement de mode&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;R,G,B ?&lt;/h2&gt;
&lt;p&gt;Une chose étonnante, c'est qu'il est possible de spécifier les palettes, et il est obligatoire de spécifier les pixels des surfaces, en RGB888, alors que l'espace de couleur est RGB222. Le VDP (ou plutôt FabGL), va chercher à trouver les couleurs en fonction. Ce n'est pas hyper pratique au premier abord, et c'est un bon gâchis d'espace.&lt;/p&gt;
&lt;p&gt;Mieux vaut ne spécifier que des couleurs faisant partie de la palette.&lt;/p&gt;</content><category term="Machines"></category><category term="AgonLight"></category></entry><entry><title>La Maison dans la colline, partie 7</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-7.html" rel="alternate"></link><published>2023-05-10T00:00:00+02:00</published><updated>2023-05-10T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-05-10:/la-maison-dans-la-colline-partie-7.html</id><summary type="html">&lt;p&gt;Dans ce septième article de la série sur le jeu « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; », il va être question de tests anti-regression.&lt;/p&gt;
&lt;h2&gt;Regressions&lt;/h2&gt;
&lt;p&gt;Mais qu'est-ce qu'une regression ? C'est un fonctionnement qui donnait toute satisfaction et qui, suite à un changement dans le système, se met à ne plus fonctionner comme attendu. Autrement dit, une apparition de bug !&lt;/p&gt;
&lt;p&gt;Les bugs n'arrivent jamais de nulle part, il y a toujours une raison. Mais plus un programme est grand, plus il se complexifie et plus le risque de programmer des morceaux qui entrent en conflit apparaît. C'est à peu près inéluctable et le développement d'un logiciel est, normalement, accompagné d'un certain nombre de règles pour éviter au mieux et surtout repérer au plus vite les défauts qui apparaissent.&lt;/p&gt;
&lt;p&gt;La vitesse de détection est importante, car il une regression peut ne pas être immédiatement flagrante. Il est possible que quelque chose casse sur une …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans ce septième article de la série sur le jeu « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; », il va être question de tests anti-regression.&lt;/p&gt;
&lt;h2&gt;Regressions&lt;/h2&gt;
&lt;p&gt;Mais qu'est-ce qu'une regression ? C'est un fonctionnement qui donnait toute satisfaction et qui, suite à un changement dans le système, se met à ne plus fonctionner comme attendu. Autrement dit, une apparition de bug !&lt;/p&gt;
&lt;p&gt;Les bugs n'arrivent jamais de nulle part, il y a toujours une raison. Mais plus un programme est grand, plus il se complexifie et plus le risque de programmer des morceaux qui entrent en conflit apparaît. C'est à peu près inéluctable et le développement d'un logiciel est, normalement, accompagné d'un certain nombre de règles pour éviter au mieux et surtout repérer au plus vite les défauts qui apparaissent.&lt;/p&gt;
&lt;p&gt;La vitesse de détection est importante, car il une regression peut ne pas être immédiatement flagrante. Il est possible que quelque chose casse sur une partie « éloignée » de ce sur quoi on travaille sur le moment. Il est aussi possible que le défaut soit subtile ; présent, mais pas évident. Tout à l'air de bien fonctionner en apparence, mais pas dans les détails. Et si on continue à développer avec ce défaut présent, il se peut très bien que l'on amplifie le problème, ajoutant du bug à du bug.&lt;/p&gt;
&lt;p&gt;La vitesse est aussi importante pour une question de contexte. Lorsque l'on a en tête une partie en train d'être travaillée, il est plus simple de corriger ce qui vient d'être modifié que lorsque l'on s'en rend compte plus tard, lorsqu'on est passé à autre chose.&lt;/p&gt;
&lt;p&gt;Dans le contexte de « La maison dans la colline », je suis tout seul et, comme je l'ai déjà dit auparavant, j'essaie de maximiser mon temps libre passé sur le projet. Ainsi, une session à essayer de trouver et corriger la raison d'un bug introduit deux sessions avant ne m'enchante pas du tout.&lt;/p&gt;
&lt;p&gt;J'ai donc mis en place deux systèmes pour m'aider à détecter rapidement les bugs&lt;/p&gt;
&lt;h2&gt;Tests unitaires&lt;/h2&gt;
&lt;p&gt;Le premier système est un système simpliste de tests unitaires. Le principe est de mettre le système dans un certain état, de faire une opération, puis de vérifier que le système est dans l'état attendu.&lt;/p&gt;
&lt;p&gt;J'ai mis en place ce système après avoir débuté le projet et lorsque celui-ci commençait à devenir un peu complexe. Malheureusement ou heureusement, j'avais pris quelques raccourcis qui rendaient certains tests un compliqués. Cela m'a pris un peu de temps pour nettoyer ça ; au passage, j'en suis sorti avec quelques nettoyages bienvenue dans le code.&lt;/p&gt;
&lt;p&gt;Je n'ai pas non plus beaucoup de tests. Majoritairement, je fais des tests sur la gestion de l'inventaire, qui m'a causé quelques soucis et qui a été ce qui m'a décidé à mettre des tests unitaires. Je fais aussi quelques tests sur mon micro-allocateur de mémoire dynamique (celui de z88dk ne me convenant pas).&lt;/p&gt;
&lt;p&gt;Lorsque je lance le programme avec une option de compilation, les tests sont exécutés dans une page spéciale, au démarrage du jeu. Je peux ainsi m'assurer que les tests passent et que donc le fonctionnement de mon système d'inventaire et d'allocation sont toujours d'aplomb.&lt;/p&gt;
&lt;p&gt;Voilà à quoi ressemble le test des objets, une fois que j'ai mis en place un environnement de tests avec des objets dans des pièces :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_count_in_room&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_count_in_room&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;254&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_count_in_room&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà une capture d'écran lors d'une regression :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Liste terminée des fonctions du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202305/20220820-MDLC-FailingTests.png"&gt;&lt;/p&gt;
&lt;h2&gt;Mode automatique&lt;/h2&gt;
&lt;p&gt;L'autre système que j'ai mis en place est un mode de jeu automatique. Au bout d'un moment, et alors que le nombre d'actions et de pièce commençait à grandir, il me fallait régulièrement jouer toute une première partie du jeu. Je vérifiais les mouvements, les portes et changements de pièce, la prise d'objet dans l'inventaire, l'utilisation d'un objet.&lt;/p&gt;
&lt;p&gt;Ça a rapidement été long, pas très amusant et source d'erreurs : est-ce que je fais bien les mêmes étapes ? Est-ce que j'ai encore envie de le faire parce que ça m'ennuie ? Est-ce que quelque chose ne va pas casse pile la fois où j'aurai la flemme de conduire les tests ?&lt;/p&gt;
&lt;p&gt;Solution : automatiser le test.&lt;/p&gt;
&lt;p&gt;Lorsque je compile le jeu avec le mode automatique inclue, je déroule un petit script qui va exécuter les actions à ma place. C'est assez simpliste, je n'ai pas de retour d'erreur automatisé. Mais au moins, si je vois quelque chose d'étrange, ou bien si le personnage se retrouve bloqué sur une étape, je peux le voir rapidement. Et je peux alors conduire un test manuel pour comprendre dans les détails ce qu'il se passe.&lt;/p&gt;
&lt;p&gt;Il n'y a pas beaucoup d'étapes dans ce test automatique, car c'est un peu fastidieux à maintenir. J'ai hésité un moment à rendre le système plus malin, avec une création de script depuis les données du jeu. Par exemple en trouvant le chemin pour aller d'un point A à un point B automatiquement. Mais je ne suis pas allé jusque là, j'ai trouvé un compromis avec un système qui « tente » d'aller vers une position, mais de manière simpliste, que je dois aider manuellement parfois.&lt;/p&gt;
&lt;p&gt;Mais que de temps gagné au final !&lt;/p&gt;
&lt;p&gt;Voici à quoi ressemble le début du script, qui est stocké dans un tableau de caractères dans le code source :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Wait page 4 (test page)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="c1"&gt;// Wait frames&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Press &amp;#39; &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Press &amp;#39; &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Press &amp;#39;A&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// Go to Kitchen&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEY_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEY_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEY_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEY_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;G&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;R&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="c1"&gt;// Go to Room 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;J'ai déjà évoqué mon goût pour les outils et les automatisation dans les articles précédents. L'automatisation des tests est un outil de plus pour se simplifier la vie. Cela demande un peu d'effort en amont, mais force parfois à mieux réfléchir son code pour le rendre flexible, ce qui est bénéfique lors de la mise au point du jeu, et permet un gros gain de temps sur la durée du projet, pour peu que l'on trouve le bon équilibre entre le temps passé à créer les outils et le gain de temps espéré grâce à eux.&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>La Maison dans la colline, partie 6</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-6.html" rel="alternate"></link><published>2023-05-04T00:00:00+02:00</published><updated>2023-05-04T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-05-04:/la-maison-dans-la-colline-partie-6.html</id><summary type="html">&lt;p&gt;Dans ce sixième article de la série sur le jeu « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; », il va être question des structures du jeu, de portage et de « binarisation ».&lt;/p&gt;
&lt;h2&gt;Les structures&lt;/h2&gt;
&lt;p&gt;« &lt;strong&gt;La maison dans la colline&lt;/strong&gt; » est un jeu programmé en grande partie en C. L'idée derrière est de pouvoir porter assez facilement sur une autre machine qui n'aurait potentiellement pas le même processeur, c'est aussi une manière de faciliter les itérations. Le jeu manipulant des objets, des pièces pour circuler, un personnage, il est intéressant de pouvoir se reposer sur des structures de données et de les manipuler, de les faire évoluer, sans avoir à adapter un code assembleur en parallèle (même s'il existe des assembleurs qui peuvent faciliter ces opérations).&lt;/p&gt;
&lt;h3&gt;Les pièces&lt;/h3&gt;
&lt;p&gt;La première structure que je présente est celle des &lt;strong&gt;pièces&lt;/strong&gt; de la maison et des &lt;strong&gt;portes&lt;/strong&gt; qui les relient. Ces données sont fixes et pourraient se situer …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans ce sixième article de la série sur le jeu « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; », il va être question des structures du jeu, de portage et de « binarisation ».&lt;/p&gt;
&lt;h2&gt;Les structures&lt;/h2&gt;
&lt;p&gt;« &lt;strong&gt;La maison dans la colline&lt;/strong&gt; » est un jeu programmé en grande partie en C. L'idée derrière est de pouvoir porter assez facilement sur une autre machine qui n'aurait potentiellement pas le même processeur, c'est aussi une manière de faciliter les itérations. Le jeu manipulant des objets, des pièces pour circuler, un personnage, il est intéressant de pouvoir se reposer sur des structures de données et de les manipuler, de les faire évoluer, sans avoir à adapter un code assembleur en parallèle (même s'il existe des assembleurs qui peuvent faciliter ces opérations).&lt;/p&gt;
&lt;h3&gt;Les pièces&lt;/h3&gt;
&lt;p&gt;La première structure que je présente est celle des &lt;strong&gt;pièces&lt;/strong&gt; de la maison et des &lt;strong&gt;portes&lt;/strong&gt; qui les relient. Ces données sont fixes et pourraient se situer en ROM si je jeu était sur ROM.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Door&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;destination_room&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;destination_position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Door&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Une porte a une position dans la pièce et amène vers une pièce de destination (identifiée par un octet) à une position donnée dans cette pièce de destination.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shift_to_next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shift_to_doors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enter_text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;door_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Door&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Une pièce est un peu plus complexe. Elle est identifiée par un octet (&lt;code&gt;id&lt;/code&gt;) qui est suivi par deux nombres de 16 bits qui sont en fait des déplacements en mémoire. &lt;code&gt;shift_to_next&lt;/code&gt; est un offset de chaînage vers la pièce suivante. Toutes les données des pièces sont contiguës en mémoire formant une liste chaînée unidirectionnelle. Ainsi, avec un pointeur vers une structure &lt;code&gt;Room&lt;/code&gt;, si on avance de &lt;code&gt;shift_to_next&lt;/code&gt; octets, on arrivera sur la pièce suivante dans les données.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;shift_to_doors&lt;/code&gt; est un peu plus complexe. C'est une indication qui permet de construire le pointeur &lt;code&gt;doors&lt;/code&gt; un peu plus loin dans la structure.&lt;/p&gt;
&lt;p&gt;Comme on peut le voir, la structure &lt;code&gt;Room&lt;/code&gt; se termine par un tableau de taille non spécifiée d'octets. Dans ce tableau se trouvent les données graphiques de la pièce suivies par les données des portes présentes dans la pièce. Ces deux données sont de taille variable et s'il est facile de connaître l'emplacement des données graphiques (c'est &lt;code&gt;data&lt;/code&gt;), il est plus compliqué de connaître le début des portes qui suivent. Surtout que les données graphiques sont compressées.&lt;/p&gt;
&lt;p&gt;Il y aurait plusieurs autres manières de faire. J'aurais pu mettre les portes (dont les données ne sont pas compressées) en premier et calculer le déplacement à partir du nombre de portes qui est une donnée connue. Mais les portes ont connu différentes implémentations et se sont finalement retrouvées là. Puis la fin du projet est arrivée et elles y sont restées.&lt;/p&gt;
&lt;p&gt;La &lt;code&gt;position&lt;/code&gt; et la taille (&lt;code&gt;size&lt;/code&gt;) de la pièce indiquent la façon dont elle doit-être affichée à l'écran. &lt;code&gt;enter_text&lt;/code&gt; est un identifiant vers le texte qui apparaît à l'écran en entrant. Et &lt;code&gt;door_count&lt;/code&gt; comme son nom l'indique, précise le nombre de portes présentes dans la pièce.&lt;/p&gt;
&lt;p&gt;Les données graphiques d'une pièce sont compressées selon un schéma RLE. Lorsqu'on entre dans un pièce ces données sont décompressées dans une zone temporaire et envoyées à l'affichage.&lt;/p&gt;
&lt;h3&gt;Les objets&lt;/h3&gt;
&lt;p&gt;La structure qui décrit les objets est la suivante. Là encore, ce sont des données fixes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// the resource id for the text in the inventory. Used also to designate the object.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// what mode for the display&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// what char to display&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// object properties&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;room_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// initial room&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// initial position in the room&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action_text_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;// text id when the action is done on the object&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Magnifique, le code est commenté.&lt;/p&gt;
&lt;p&gt;Un objet est donc identifié par un identifiant &lt;code&gt;name_id&lt;/code&gt; qui est aussi l'identifiant du texte qui y est associé. C'est un choix que j'ai regretté, il aurait été bien plus pratique d'avoir un identifiant pour l'objet lui-même séparé du texte qui le décrit. Plus loin, on voit un autre identifiant du texte écrit lorsque l'on effectue une action. Là encore, c'est assez peu flexible et cela m'a obligé à ne considérer qu'une seule action par objet. Je m'en suis sorti et on dit que les contraintes amènent de la créativité.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;char_mode&lt;/code&gt; et &lt;code&gt;character&lt;/code&gt; donnent les informations d'affichage. Il n'y a pas de couleur car les objets ont une couleur fixe dans ce jeu, pour indiquer que des actions peuvent être faites dessus.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;properties&lt;/code&gt; indique ce que l'on peut faire de l'objet : est-ce qu'on peut le prendre, est-ce qu'on peut le lire, est-ce que c'est un déclencheur d'évènement, est-ce que l'on peut marcher dessus, est-ce qu'il est transformable en un autre objet et enfin, est-ce que c'est un téléporteur.&lt;/p&gt;
&lt;p&gt;Les téléporteurs sont en fait les portes. Initialement, j'avais un système spécifique de traitement des portes. Je l'ai plus tard unifié avec le traitement des objets de manière générale.&lt;/p&gt;
&lt;p&gt;L'objet a aussi un pièce (&lt;code&gt;room_id&lt;/code&gt;) et un emplacement (&lt;code&gt;position&lt;/code&gt;) qui désignent l'endroit où se trouve l'objet en début de jeu. Cette information est immuable et servira lorsque l'on relance le jeu à tout remettre en place. Au début du jeu, un tableau des localisations réelles des objets est créé en mémoire et ce tableau qui sera modifié en fonction des actions.&lt;/p&gt;
&lt;p&gt;Il existe deux pièces spéciales dans le jeu. Un pièce « nulle part » dans laquelle sont déplacés les objets qui ne sont plus valides (par exemple, une clé après avoir été utilisée). La seconde pièce est « l'inventaire ». Cela permet de s'assurer qu'un objet est toujours dans une pièce. Prendre un objet, c'est changer sa pièce courante pour celle de l'inventaire. En échangeant ses informations avec l'objet qu'il remplace dans l'inventaire, ce dernier est naturellement posé dans la pièce.&lt;/p&gt;
&lt;h3&gt;La binarisation&lt;/h3&gt;
&lt;h4&gt;Partie logique&lt;/h4&gt;
&lt;p&gt;Si au début du développement il est possible d'indiquer directement dans le code les pièces (non compressées) et les objets, ça se révèle rapidement impraticable. Pour mettre au point le jeu, un éditeur est plus pratique. Cependant je n'avais non beaucoup de temps à consacrer au développement d'un éditeur de jeu. &lt;/p&gt;
&lt;p&gt;Dans ces cas là, une manière classique de faire est de travailler sur des fichiers texte que l'on transpose dans le format binaire attendu par le jeu. D'où le terme « binarisation ». Un autre terme existe : « cooking »... et probablement d'autres.&lt;/p&gt;
&lt;p&gt;Voici à quoi ressemble la première pièce du jeu :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;Room&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Entrée&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;Id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;Position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;Size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;15&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;EnterText&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;42&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nt"&gt;Description&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#########&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;###&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;D&lt;/span&gt;&lt;span class="err"&gt;####&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;E&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;E&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;###&lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;F&lt;/span&gt;&lt;span class="err"&gt;####&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;#########&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nt"&gt;Doors&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;3&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;E&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;255&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nt"&gt;Objects&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;G&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nt"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;68&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;None&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Apparition&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nt"&gt;Locks&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nt"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;18&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;56&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nt"&gt;EndRoom&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tous les &lt;code&gt;#&lt;/code&gt; sont des emplacements bloquants : des murs ou des objets de décors. Les autres caractères (souvent des lettres) sont des emplacements spéciaux décrits à la suite de la partie graphique. Ainsi, on voit trois portes, un objet et un verrou.&lt;/p&gt;
&lt;p&gt;Les portes sont suivies d'un petit code qui indique la pièce d'arrivée et un emplacement sous la forme d'une lettre (que l'on trouvera dans cette pièce) ainsi qu'une direction naturelle pour le sprite du personnage.&lt;/p&gt;
&lt;p&gt;Les objets sont suivis d'informations graphiques (G'10,68 signifie : caractère numéro 68 dans la palette G'10), des propriété et d'un identifiant de texte. Ce qui suit le point virgule est un commentaire, il n'est pas lu.&lt;/p&gt;
&lt;p&gt;Toutes ces données sont traitées et envoyées dans un fichier de données qui sera inclus au jeu.&lt;/p&gt;
&lt;h4&gt;Partie graphique&lt;/h4&gt;
&lt;p&gt;La parte graphique est elle aussi binarisée. Pour cela, j'utilise &lt;a href="https://orama-interactive.itch.io/pixelorama"&gt;Pixelorama&lt;/a&gt; avec une palette d'objets graphiques et je dessine la pièce. La binarisation s'occupe de découper cela en morceaux de 10 pixels par 8 afin de construire la liste des caractères à redéfinir.&lt;/p&gt;
&lt;p&gt;C'est à moi de m'assurer que les données logiques et graphiques sont cohérentes. Entre autre que les tailles de pièces soient identiques. Il y aurait de la marge pour aller plus loin avec un éditeur mais encore une fois, c'était dans un délai trop court pour cela. Peut-être plus tard ?&lt;/p&gt;
&lt;h2&gt;La suite ?&lt;/h2&gt;
&lt;p&gt;En effet, l'idée que j'avais en essayant de construire des structures réutilisables et flexibles étaient de pouvoir les... réutiliser. Et pourquoi pas étendre le jeu ou bien en faire un autre sur le même principe ? Avec cette fois un peu plus de temps à passer sur les outils.&lt;/p&gt;
&lt;p&gt;Pourquoi pas. C'est une idée que je garde dans un coin de la tête.&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>La Maison dans la colline, partie 5</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-5.html" rel="alternate"></link><published>2023-02-23T00:00:00+01:00</published><updated>2023-02-23T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-02-23:/la-maison-dans-la-colline-partie-5.html</id><summary type="html">&lt;p&gt;Dans ce cinquième article, je vais aborder la méthodologie que j'ai appliquée pour le développement de « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; ».&lt;/p&gt;
&lt;h2&gt;La planification&lt;/h2&gt;
&lt;p&gt;Dans un premier temps, j'avais jeté sur papier (électronique) la liste des fonctionnalités que je voulais implémenter, en partant de l'idée générale du jeu et en descendant successivement sur ce dont je pensais avoir besoin. Puis j'ai segmenté cette liste en thèmes, comme par exemple « mouvements du personnage » ou bien « gestion de l'inventaire ».&lt;/p&gt;
&lt;p&gt;Ces fonctionnalités ont besoin les unes des autres, je suis descendu jusqu'aux briques de bases, comme « afficher quelque chose à l'écran » ou bien « lire une touche du clavier ». Entre toutes ces fonctionnalités, j'ai créé des dépendances : afficher un personnage nécessaire de savoir afficher quelque chose à l'écran. L'animer nécessite de savoir l'afficher. Et ainsi de suite.&lt;/p&gt;
&lt;p&gt;Mes dépendances ne sont pas complètes. J'ai celles qui concernent les premières tâches à effectuer, mais c'est tout …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans ce cinquième article, je vais aborder la méthodologie que j'ai appliquée pour le développement de « &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; ».&lt;/p&gt;
&lt;h2&gt;La planification&lt;/h2&gt;
&lt;p&gt;Dans un premier temps, j'avais jeté sur papier (électronique) la liste des fonctionnalités que je voulais implémenter, en partant de l'idée générale du jeu et en descendant successivement sur ce dont je pensais avoir besoin. Puis j'ai segmenté cette liste en thèmes, comme par exemple « mouvements du personnage » ou bien « gestion de l'inventaire ».&lt;/p&gt;
&lt;p&gt;Ces fonctionnalités ont besoin les unes des autres, je suis descendu jusqu'aux briques de bases, comme « afficher quelque chose à l'écran » ou bien « lire une touche du clavier ». Entre toutes ces fonctionnalités, j'ai créé des dépendances : afficher un personnage nécessaire de savoir afficher quelque chose à l'écran. L'animer nécessite de savoir l'afficher. Et ainsi de suite.&lt;/p&gt;
&lt;p&gt;Mes dépendances ne sont pas complètes. J'ai celles qui concernent les premières tâches à effectuer, mais c'est tout. Inutile de travailler sur celles qui viendront bien plus tard, et ce pour une raison très simple : il est très probable qu'elles changent au fur et à mesure que j'avance dans le développement. Voire pour certaines, qu'elles disparaissent.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Liste terminée des fonctions du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202302/20230223-ListeFonctionsMDLC.png"&gt;&lt;/p&gt;
&lt;h3&gt;La qualité progressive&lt;/h3&gt;
&lt;p&gt;Dernière étape, pour chaque fonctionnalités, séparer des niveaux de qualité. Par exemple, je sais que je vais un personnage avec un affichage fin, et animé. Mais je ne sais pas encore trop ce que ça donne d'un point de vue jeu, est-ce qu'il me faut un sprite de 8 pixels de large ou de 16 pixels de large ? J'ai même joué avec l'idée à un moment qu'il fasse 8 de large de côté, mais 16 de large de face.&lt;/p&gt;
&lt;p&gt;Je sais que dessiner un sprite va me prendre du temps, surtout que ça n'est pas mon domaine. Je ne veux pas avoir à le refaire trop de fois. Donc dans les premiers niveaux de qualité, je note que je vais afficher des caractères prédéfinis de l'ordinateur.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Version de développement de MDLC" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202302/20220813-vg5000-aventure-01.png"&gt;&lt;/p&gt;
&lt;p&gt;Je note ensuite que je pourrais tenter avec un personnage fixe. Puis enfin un personnage animé. Cela me donne trois étapes de qualité pour cette fonctionnalité. Et celles-ci ne seront pas forcément exécutées consécutivement. C'est important car le temps de la jam est limité et je fais ça sur mon temps libre, qui est très variable. Si la fin arrive avant qu'un niveau de qualité soit atteint, ce n'est pas grave, j'aurais tout de même quelque chose de moins joli que prévu, mais quelque chose quand même.&lt;/p&gt;
&lt;p&gt;Je fais de même avec les fonctionnalités : je les classe par importance, mêlée de difficulté. Un personnage qui se déplace, c'est essentiel. Parmi les interactions avec les objets, j'en avais initialement prévus beaucoup plus que ce qui est dans le jeu à la fin. Quant à l'audio... je n'ai pas eu le temps et j'ai laissé de côté.&lt;/p&gt;
&lt;p&gt;De même j'avais prévu quelques scènes graphiques d'illustration en « haute résolution ». C'est passé à la trappe.&lt;/p&gt;
&lt;h3&gt;Sur le long terme&lt;/h3&gt;
&lt;p&gt;À chaque fois que je termine une fonctionnalité, je reviens sur le document et j'ajuste. En voyant le jeu progresser, je comprends qu'il y a des choses que je voulais faire qui ne vont pas avec le reste. Ou parfois, je vois qu'il me manque un morceau, que j'avais oublié quelque chose.&lt;/p&gt;
&lt;p&gt;Ce document va souvent être modifié. Je garde l'idée générale du jeu, les grandes lignes. Mais je me laisse aussi porter par ce qu'il devient. Ça m'évite de me bloquer sur quelque chose trop longtemps alors que ça ne fonctionne pas, que ce soit techniquement ou en game design.&lt;/p&gt;
&lt;p&gt;Il ne faut pas hésiter à couper par manque de temps, ou parce qu'on a vu trop gros pour la machine. À modifier parce que ça ne convient plus. Ou parce qu'une nouvelle idée arrive. Ce dernier cas est à évaluer avec prudence ceci dit : il faut l'intégrer correctement à l'existant, et à l'état actuel du projet. Les idées arrivent toujours plus nombreuses et plus rapidement que leur temps de développement nécessaire.&lt;/p&gt;
&lt;h2&gt;La programmation&lt;/h2&gt;
&lt;p&gt;Niveau programmation, j'applique là aussi une démarche itérative « par petits pas ». En reprenant l'affiche, par exemple, je commence par m'adresser directement à l'EF9345, à travers une &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-4.html"&gt;liste d'affichage&lt;/a&gt;, avec une position et un caractère fixes. Puis j'extrais la position pour qu'elle devienne variable, mais toujours localement. Puis je la passe par paramètre de la liste d'affichage. Et enfin je l'injecte depuis le programme principal, avant de répéter la même démarche pour le caractère affiché.&lt;/p&gt;
&lt;p&gt;L'idée ici est de vérifier que le code fonctionne sur un cas simple, s'assurer qu'on a bien compris le problème. Dans le cas de l'EF9345, être certain qu'on a bien compris son fonctionnement par exemple. Puis petit à petit, on généralise, si nécessaire, avant d'extraire les données variables.&lt;/p&gt;
&lt;p&gt;Cela permet de valider chaque étape individuellement et d'éviter les bugs dus à un développement avec beaucoup de changements différents. Cela permet aussi de s'arrêter en chemin. Soit pour passer à autre chose que l'on développe en parallèle car en lien. Ou tout simplement parce que c'est l'heure de manger, et qu'il est toujours préférable de laisser le programme dans un état fonctionnel sur lequel on peut reprendre plus tard.&lt;/p&gt;
&lt;p&gt;Et enfin, parce que parfois, on s'aperçoit qu'il n'est pas nécessaire de généraliser plus avant. Ou alors pas tout de suite. Et peut-être jamais. La fonctionnalité arrive à un point satisfaisant.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;S'il faut retenir une chose de cette méthodologie, c'est le concept d'avancée graduelle. Faire des « petits pas », monter petit à petit en qualité et savoir s'arrêter.&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>La Maison dans la colline, partie 4</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-4.html" rel="alternate"></link><published>2023-02-20T00:00:00+01:00</published><updated>2023-02-20T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-02-20:/la-maison-dans-la-colline-partie-4.html</id><summary type="html">&lt;p&gt;Dans ce quatrième article concernant le développement de « La maison dans la colline », je vais aborder quelques points de programmation. Deux points en particulier : la structure générale du programme, puis les listes d'affichage.&lt;/p&gt;
&lt;h3&gt;Structure générale&lt;/h3&gt;
&lt;p&gt;Un jeu vidéo, c'est un programme qui ne s'arrête pas. Enfin si... quand on a fini de jouer. Mais il s'oppose aux programmes en « batch » qui doivent résoudre une fonction à partir de données en entrée. Un jeu vidéo se situe donc dans la classe des applications qui font évoluer un état en fonction des entrées de l'utilisateur.&lt;/p&gt;
&lt;p&gt;Ainsi, un tel programme peut se résumer à cette structure :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;read_input&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;update_state&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;display_state&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Autrement dit : tant que le logiciel tourne, on lit les entrées, on met à jour les états du jeu, on affiche l'état du jeu (on peut aussi diffuser le son, mais ce jeu n'en n'a pas) et on recommence.&lt;/p&gt;
&lt;p&gt;Voilà …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans ce quatrième article concernant le développement de « La maison dans la colline », je vais aborder quelques points de programmation. Deux points en particulier : la structure générale du programme, puis les listes d'affichage.&lt;/p&gt;
&lt;h3&gt;Structure générale&lt;/h3&gt;
&lt;p&gt;Un jeu vidéo, c'est un programme qui ne s'arrête pas. Enfin si... quand on a fini de jouer. Mais il s'oppose aux programmes en « batch » qui doivent résoudre une fonction à partir de données en entrée. Un jeu vidéo se situe donc dans la classe des applications qui font évoluer un état en fonction des entrées de l'utilisateur.&lt;/p&gt;
&lt;p&gt;Ainsi, un tel programme peut se résumer à cette structure :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;read_input&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;update_state&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;display_state&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Autrement dit : tant que le logiciel tourne, on lit les entrées, on met à jour les états du jeu, on affiche l'état du jeu (on peut aussi diffuser le son, mais ce jeu n'en n'a pas) et on recommence.&lt;/p&gt;
&lt;p&gt;Voilà la base.&lt;/p&gt;
&lt;p&gt;Au deuxième étage, le jeu est constitué de « pages ». Il y a la page d'accueil, avec le titre, la page d'introduction, qui donne le texte de début, le jeu en lui-même, et le texte de fin. Comme le jeu est à tout moment dans une seule de ces pages, j'utilise pour les représenter une paire de fonctions. L'une est appelée lorsque l'on entre dans la page, et l'autre à chaque mise à jour, en boucle, tant que cette page est active.&lt;/p&gt;
&lt;h3&gt;Fonction d'entrée&lt;/h3&gt;
&lt;p&gt;La fonction d'entrée permet de changer le contexte du jeu, de mettre l'écran dans les bonnes conditions. Par exemple, voici la fonction d'entrée de la page de titre :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;page_title_enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PageContext&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__z88dk_fastcall&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;initialize_40_long&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// Initialisation du mode 40 colonne format long de l&amp;#39;EF9345&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;clear_40_long&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Effacement de l&amp;#39;écran dans ce mode&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Affichage du titre&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_print_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M40LONG_COLOR_FG_WHITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;M40LONG_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;extract_string_from_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Affichage de l&amp;#39;auteur&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_print_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M40LONG_COLOR_FG_WHITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;extract_string_from_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Affichage du PRESS START&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_print_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M40LONG_COLOR_FG_WHITE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;M40LONG_FLASH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;extract_string_from_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;press&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Quelques commentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le paramètre &lt;code&gt;context&lt;/code&gt; n'est pas utilisé ici. Nous verrons dans la fonction suivante son utilité. À vrai dire, je ne l'ai jamais utilisé dans les fonctions d'entrée et il devrait probablement être enlevé.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__z88dk_fastcall&lt;/code&gt; est une annotation pour la suite &lt;code&gt;z88dk&lt;/code&gt; qui indique au compilateur que le pointeur passé en argument devra être passé dans &lt;code&gt;HL&lt;/code&gt;, plutôt que par la pile. Nous verrons plus tard que c'est bien pratique lorsque l'on mélange C et assembleur.&lt;/li&gt;
&lt;li&gt;les chaînes de caractères sont appelées via un système d'accès à des ressources. J'en parlerai probablement dans un autre article plus tard.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fonction de mise à jour&lt;/h3&gt;
&lt;p&gt;L'autre fonction qui décrit une page est celle de la mise à jour. Elle sera appelée en boucle tant que la page est active. Contrairement à ce que j'indiquais au tout début de l'article, il n'y a pas de séparation entre la mise à jour et l'affichage. Dans ce programme, la fonction de mise à jour s'occupe des deux étapes.&lt;/p&gt;
&lt;p&gt;Voici par exemple la fonction de mise à jour pour l'écran de titre :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;page_title_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PageContext&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__z88dk_fastcall&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;just_pressed_key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CHANGE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;command_param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INTRODUCTION_PAGE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Commentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ici, le &lt;code&gt;context&lt;/code&gt; est utilisé. On peut voir qu'il sert de communication avec l'état extérieur à la page.&lt;/li&gt;
&lt;li&gt;en lecture, le &lt;code&gt;context&lt;/code&gt; fourni une information sur une touche du clavier éventuellement appuyée.&lt;/li&gt;
&lt;li&gt;en écriture, le &lt;code&gt;context&lt;/code&gt; permet de donner une information à transmettre à l'extérieur. Ici, l'information est celle d'un changement de page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En effet, au-dessus des pages, il y a un petit superviseur, qui n'est en fait rien d'autre que la boucle principale du jeu. Celle-ci va s'occuper de peupler le &lt;code&gt;context&lt;/code&gt; avec les informations systèmes, dont les touches du clavier, puis va vérifier si la page en cours a donné une commande. Il y a trois commandes possibles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CHANGE&lt;/code&gt; : qui indique une page de destination, et qui provoquera donc un changement de page. Ici, lorsqu'une touche est appuyée, on passe à la page d'introduction du jeu.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RUN&lt;/code&gt; : qui indique que la page actuelle doit continuer à être appelée, c'est la page active.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STOP&lt;/code&gt; : qui demande l'arrêt du programme. C'est une commande que j'ai utilisée en début de développement pour certains tests, mais que j'ai arrêté d'utiliser. Le programme ne s'arrête pas.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voilà pour la structure générale du jeu. Passons maintenant aux listes d'affichage.&lt;/p&gt;
&lt;h2&gt;Les listes d'affichage&lt;/h2&gt;
&lt;p&gt;Comme je l'avais mentionné dans un article précédent, je voulais dans ce jeu avoir un affichage rapide avec lequel le scintillement de mise à jour était, au moins dans la majorité des cas, invisible. Et cela signifie une chose : il faut afficher vite, et au bon moment.&lt;/p&gt;
&lt;p&gt;Si la mise à jour de l'écran se fait au fil de la mise à jour de l'état du jeu, il y a de bonnes chances qu'une mise à jour de l'affichage arrive au mauvais moment. De plus, l'EF9345 est pleinement efficace en début de traçage de l'écran, dans la zone de bord haute. Par la suite, il commence à être occupé avec la génération de l'image et a moins de temps à consacrer aux données qui arrivent depuis le Z80.&lt;/p&gt;
&lt;p&gt;Il y a deux outils classiques pour cela :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la synchronisation verticale, qui permet de savoir quand le processeur vidéo commence une nouvelle image,&lt;/li&gt;
&lt;li&gt;les listes d'affichage (Display Lists en anglais), qui sont des listes de commandes préparées pour être exécutées le plus vite possible. Ou en tout cas, « assez vite »&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Mise en place&lt;/h3&gt;
&lt;p&gt;Par bonheur, le VG5000µ est conçu de manière à être mis au courant d'une synchronisation verticale. En effet, le signal de synchronisation, envoyé par l'EF9345, est branché sur l'interruption (IRQ) du Z80. Comme je l'avais abordé dans l'article sur les &lt;a href="https://www.triceraprog.fr/vg5000m-les-hooks.html"&gt;hooks&lt;/a&gt; de la ROM du VG5000µ, le système appel une emplacement en RAM avant d'effectuer son affichage. Il est possible remplacer l'instruction &lt;code&gt;RET&lt;/code&gt; initialement positionné à cette adresse par un saut (&lt;code&gt;JMP xxxx&lt;/code&gt;) vers l'adresse que l'on veut.&lt;/p&gt;
&lt;p&gt;Et c'est une des premières opérations que fait le programme : une mise en place d'un routage vers l'exécution des listes d'affichage en cours. La routine dépile aussi l'adresse de retour sur la pile, afin de désactiver complètement l'affichage géré par la ROM.&lt;/p&gt;
&lt;p&gt;On est donc en contrôle complet de l'affichage du VG5000µ. Une lourde responsabilité !&lt;/p&gt;
&lt;h3&gt;Gestion de listes&lt;/h3&gt;
&lt;p&gt;Il y a de nombreuses manières différentes d'implémenter des listes d'affichage, en fonction des besoins en vitesse balancés avec la place prise et probablement d'autres paramètres encore.&lt;/p&gt;
&lt;p&gt;Dans ce programme, les listes d'affichage sont formées par une suite d'appels, au sens machine (&lt;code&gt;CALL&lt;/code&gt;) vers de fonctions spécialisées. Ce sont des listes chaînées qui ont le format suivant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l'adresse du lien vers l'élément suivant, ou zéro pour la fin de liste,&lt;/li&gt;
&lt;li&gt;l'adresse d'appel,&lt;/li&gt;
&lt;li&gt;les paramètres de l'appel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ajouter un élément à la liste d'affichage est donc ajouter à la liste une nouvelle adresse d'appel ainsi que des arguments, puis ajuste le lien de la chaîne. &lt;/p&gt;
&lt;p&gt;Rejouer une liste consiste à parcourir la liste et appeler les fonctions spécialisées en fournissant les paramètres.&lt;/p&gt;
&lt;p&gt;Tout cela est stocké dans l'espace de la RAM que la ROM utilise normalement pour traiter l'affichage. Il y a là plein de place inutilisée.&lt;/p&gt;
&lt;p&gt;J'ai considéré un temps utiliser aussi l'espace des variables internes du BASIC, mais &lt;code&gt;z88dk&lt;/code&gt; en utilise une partie, par exemple pour la lecture des touches, que je n'ai pas réécrite. Il est cependant possible d'utiliser cette partie avec un peu plus d'efforts.&lt;/p&gt;
&lt;h3&gt;Un exemple&lt;/h3&gt;
&lt;p&gt;Dans la fonction d'affichage de l'écran titre plus haut, il est cette ligne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set_print_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M40LONG_COLOR_FG_WHITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;M40LONG_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette fonction &lt;code&gt;set_print_attributes&lt;/code&gt; n'agit pas directement sur l'EF9345. Si on regarde son implémentation, on peut voir qu'elle se contente d'ajouter à la liste d'affichage un appel différé vers la routine spécialisée :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set_print_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;add_to_display_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dl_set_attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les trois paramètres indiquent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l'adresse de la routine spécialisée,&lt;/li&gt;
&lt;li&gt;la taille des paramètres, en octets,&lt;/li&gt;
&lt;li&gt;les paramètres, sous forme d'un buffer qui sera copié dans la liste d'affichage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Au prochain traçage de l'écran, la routine sera alors appelée. Dans ce cas précis, c'est une routine en assembleur.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Sets the A and B attributes to used for KRF&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Parameters are A then B&lt;/span&gt;
&lt;span class="nl"&gt;_dl_set_attributes:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ef9345_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;EF9345_SEL&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="no"&gt;REG_R3_CMDST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Loads A&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ef9345_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;wait_impl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ef9345_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;EF9345_SEL&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="no"&gt;REG_R2_CMDST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Loads B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ef9345_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;wait_impl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mais il est possible d'appeler une fonction C annotée avec l'attribut &lt;code&gt;__z88dk_fastcall&lt;/code&gt; vu plus haut. Ainsi, la fonction C recevra le buffer de paramètre naturellement. Il n'existe qu'une seule fonction dans le programme qui utilise cette méthode, car j'ai progressivement réécrit les autres en assembleur. C'était cependant bien pratique pendant le développement.&lt;/p&gt;
&lt;p&gt;Cette fonction s'occupe de l'affichage des pièces, et commence comme ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dl_display_room&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RoomNew&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p_room_param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__z88dk_fastcall&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Le système de page est simple et efficace dans le cadre de ce jeu. Et le système de liste d'affichage a bien joué son rôle : l'affichage du jeu est rapide et agréable. Il a fallu quelques ajustements sur matériel réel sur quelques synchronisation, car j'envoyais parfois les commandes trop vite, ce qui est accepté par les émulateurs, mais pas par un vrai VG5000µ.&lt;/p&gt;
&lt;p&gt;Dans le prochain article, je compte parler de la méthodologie de développement que j'ai utilisé sur le jeu. À la prochaine !&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>Récréation 3D, Micral N</title><link href="https://www.triceraprog.fr/recreation-3d-micral-n.html" rel="alternate"></link><published>2023-02-15T00:00:00+01:00</published><updated>2023-02-15T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-02-15:/recreation-3d-micral-n.html</id><summary type="html">&lt;p&gt;Je l'avais brièvement mentionné il y a &lt;a href="https://www.triceraprog.fr/baisse-de-regime-en-apparence.html"&gt;presque un an&lt;/a&gt; : j'ai eu la chance de pouvoir travailler avec l'association &lt;a href="https://www.mo5.com"&gt;M05.COM&lt;/a&gt; à l'analyse et restauration d'un exemplaire de « &lt;strong&gt;Micral N&lt;/strong&gt; ».&lt;/p&gt;
&lt;p&gt;Entre deux analyses, j'ai reproduis cet exemplaire en &lt;strong&gt;modèle 3D&lt;/strong&gt;, que je présente ici dans un rendu assez simple.&lt;/p&gt;
&lt;p&gt;J'y voyais &lt;strong&gt;deux intérêts&lt;/strong&gt;. Le premier est que c'est pour moi une façon d'étudier l'&lt;strong&gt;aspect extérieur&lt;/strong&gt; d'une machine. Dans le cas de celle-ci, est-ce que j'ai bien vu tous les détails ? Est-ce que j'ai bien vu toutes les LEDs et tous les interrupteurs. L'exercice de modélisation force à se pencher sur les détails.&lt;/p&gt;
&lt;p&gt;En comparant les photos, on peut aussi voir les différences entre différents exemplaires. Par exemple, l'exemplaire de l'association a un &lt;strong&gt;interrupteur&lt;/strong&gt; ajouté sur la droite du panneau de contrôle par rapport aux autres exemplaires dont les photos sont disponibles.&lt;/p&gt;
&lt;p&gt;Le deuxième intérêt est que cette modélisation pourra …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Je l'avais brièvement mentionné il y a &lt;a href="https://www.triceraprog.fr/baisse-de-regime-en-apparence.html"&gt;presque un an&lt;/a&gt; : j'ai eu la chance de pouvoir travailler avec l'association &lt;a href="https://www.mo5.com"&gt;M05.COM&lt;/a&gt; à l'analyse et restauration d'un exemplaire de « &lt;strong&gt;Micral N&lt;/strong&gt; ».&lt;/p&gt;
&lt;p&gt;Entre deux analyses, j'ai reproduis cet exemplaire en &lt;strong&gt;modèle 3D&lt;/strong&gt;, que je présente ici dans un rendu assez simple.&lt;/p&gt;
&lt;p&gt;J'y voyais &lt;strong&gt;deux intérêts&lt;/strong&gt;. Le premier est que c'est pour moi une façon d'étudier l'&lt;strong&gt;aspect extérieur&lt;/strong&gt; d'une machine. Dans le cas de celle-ci, est-ce que j'ai bien vu tous les détails ? Est-ce que j'ai bien vu toutes les LEDs et tous les interrupteurs. L'exercice de modélisation force à se pencher sur les détails.&lt;/p&gt;
&lt;p&gt;En comparant les photos, on peut aussi voir les différences entre différents exemplaires. Par exemple, l'exemplaire de l'association a un &lt;strong&gt;interrupteur&lt;/strong&gt; ajouté sur la droite du panneau de contrôle par rapport aux autres exemplaires dont les photos sont disponibles.&lt;/p&gt;
&lt;p&gt;Le deuxième intérêt est que cette modélisation pourra servir pour l'&lt;strong&gt;émulateur&lt;/strong&gt; « grand public » (toute proportion gardée), afin de manipuler le clone virtuel de cette machine.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Reproduction en image de synthèse de l'exemplaire Micral N de l'association MO5" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202302/remake-micral-n-v4-750.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;L'exemplaire original, lui, peut-être vu dans &lt;a href="https://mo5.com/site/premier-apercu-du-micral-n-de-lassociation-mo5/"&gt;cet article de blog&lt;/a&gt; sur le site de l'association.&lt;/p&gt;</content><category term="Divers"></category><category term="Micral"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>La Maison dans la colline, partie 3</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-3.html" rel="alternate"></link><published>2023-01-26T00:00:00+01:00</published><updated>2023-01-26T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-01-26:/la-maison-dans-la-colline-partie-3.html</id><summary type="html">&lt;p&gt;Suite de la série sur le développement du jeu &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; sur VG5000µ. Après, un exposé du contexte dans la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;première partie&lt;/a&gt;, puis un aperçu des outils utilisés dans la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;seconde partie&lt;/a&gt;, cet article aborde l'idée du jeu et de son évolution au fur et à mesure du développement.&lt;/p&gt;
&lt;h3&gt;La première idée&lt;/h3&gt;
&lt;p&gt;LE VG5000µ est une machine que je commence à bien connaître, et, comme expliqué dans le premier article, j'étais en train d'approfondir les capacités du VDP lorsque ce petit défi a commencé. Je voulais me servir des mes nouvelles connaissances et je suis parti sur l'idée de faire un &lt;strong&gt;affichage « fin »&lt;/strong&gt; et sans clignotement.&lt;/p&gt;
&lt;p&gt;L'idée de faire un jeu d'&lt;strong&gt;aventure graphique&lt;/strong&gt; me trottait dans la tête depuis quelques temps, et c'est un genre qui collait bien à mes objectifs. Peu de mouvements à l'écran, donc l'affichage pourrait être maîtrisé.&lt;/p&gt;
&lt;p&gt;Initialement, le jeu se passe …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Suite de la série sur le développement du jeu &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; sur VG5000µ. Après, un exposé du contexte dans la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;première partie&lt;/a&gt;, puis un aperçu des outils utilisés dans la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;seconde partie&lt;/a&gt;, cet article aborde l'idée du jeu et de son évolution au fur et à mesure du développement.&lt;/p&gt;
&lt;h3&gt;La première idée&lt;/h3&gt;
&lt;p&gt;LE VG5000µ est une machine que je commence à bien connaître, et, comme expliqué dans le premier article, j'étais en train d'approfondir les capacités du VDP lorsque ce petit défi a commencé. Je voulais me servir des mes nouvelles connaissances et je suis parti sur l'idée de faire un &lt;strong&gt;affichage « fin »&lt;/strong&gt; et sans clignotement.&lt;/p&gt;
&lt;p&gt;L'idée de faire un jeu d'&lt;strong&gt;aventure graphique&lt;/strong&gt; me trottait dans la tête depuis quelques temps, et c'est un genre qui collait bien à mes objectifs. Peu de mouvements à l'écran, donc l'affichage pourrait être maîtrisé.&lt;/p&gt;
&lt;p&gt;Initialement, le jeu se passe dans un manoir, c'est-à-dire un lieu avec de nombreuses pièces. Et puis, c'est le classique des jeux graphiques ou textuels, repris aussi par des standards comme « Alone in the Dark » en jeu vidéo, ou « Mansions of Madness » en jeu de plateau. Les jeux où le but est de sortir d'une &lt;strong&gt;maison fermée&lt;/strong&gt; ne manquent pas.&lt;/p&gt;
&lt;p&gt;Rapidement, je fais quelques croquis pour me fixer une idée de ce à quoi le jeu ressemblerait. Un peu de place pour l'affichage de la pièce courante vue de dessus, de la place pour un texte et un inventaire.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Premières notes manuscrites du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202301/MDLC-Notes-220602.png"&gt;&lt;/p&gt;
&lt;h3&gt;Creuser les idées&lt;/h3&gt;
&lt;p&gt;Dans ce genre de jeux, il s'agit de &lt;strong&gt;résoudre des énigmes&lt;/strong&gt; qui prennent la forme de trouver les &lt;strong&gt;bons objets&lt;/strong&gt; pour les amener aux &lt;strong&gt;bons endroits&lt;/strong&gt;. Il peut y avoir quelques énigmes plus complexes à résoudre, mais je veux m'arrêter là. Le temps va passer vite, et il faut rester sur du faisable, et sachant que ça sera déjà probablement trop.&lt;/p&gt;
&lt;p&gt;Je lance quelques idées d'objets. Une torche électrique. Une boite d'allumettes. Ah, donc autant remplacer la torche pas une lanterne à allumer. Des livres. Des clés. C'est vague, mais cela me permet de définir quels types d'interactions le personnage du jeu peut avoir. Ah, et des portes aussi.&lt;/p&gt;
&lt;p&gt;Au tout début, les interactions sont nombreuses : prendre, lire, utiliser, combiner, poser, ouvrir... Mais je sens que cela va faire beaucoup. Je voudrais aussi essayer que le jeu soit jouable avec la manette, à un seul bouton (ce ne sera pas le cas au final). Cette contrainte me fait réfléchir à &lt;strong&gt;réduire&lt;/strong&gt; le nombre d'&lt;strong&gt;interactions&lt;/strong&gt;, ou en tout cas de faire en sorte qu'elles soient automatiques : si je fais une action sur un livre, c'est pour le lire. Si je fais une action devant une porte en ayant une clé, c'est pour l'ouvrir. Et ainsi de suite. Mais pour le moment, je ne creuse pas plus avant. Je laisse cette idée mûrir.&lt;/p&gt;
&lt;p&gt;Je veux aussi me détacher des jeux d'époque dont une partie de la difficulté est de comprendre comment manipuler le jeu. De ce côté-ci, je veux apporter de la &lt;strong&gt;modernité&lt;/strong&gt; (toute relative) : en jouant, les objets sur lesquels ont peut &lt;strong&gt;agir&lt;/strong&gt; doivent être &lt;strong&gt;facilement identifiables&lt;/strong&gt;, et les actions possibles indiquées en fonction du contexte. Ça va probablement raboter la durée du jeu, mais cela sera beaucoup plus agréable.&lt;/p&gt;
&lt;p&gt;Concernant la durée d'ailleurs, je ne vise pas quelque chose de très long. Les quelques personnes susceptibles de jouer à ce jeu ne cherchent probablement pas une expérience de douze heures. Ni même d'une heure. Trente minutes pour quelqu'un qui ne connaît pas la solution, ça semble bien. Même si je cherche à ce que le jeu soit agréable à jouer et un bon moment à passer, c'est avant tout une preuve de concept d'affichage sur VG5000µ. Et c'est un hobby à mes heures perdues.&lt;/p&gt;
&lt;p&gt;Ci-dessous, une &lt;strong&gt;maquette&lt;/strong&gt; préliminaire du jeu avec des essais de rendu. On y voit un essaie de personnage plus large. Les portes sont différentes aussi.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Maquette préliminaire du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202301/20220710-MDLC-Maquette-Initiale-EcranDeJeu.png"&gt;&lt;/p&gt;
&lt;h3&gt;Évolutions&lt;/h3&gt;
&lt;p&gt;Toutes ces idées, je les notes sur un &lt;strong&gt;carnet&lt;/strong&gt; (électronique), et je n'hésite pas à les annoter, les &lt;strong&gt;modifier&lt;/strong&gt;, les corriger, en fonction des développements, du temps qui passe, des choses plus faciles à programmer que d'autres, des simplifications,... Cette espèce de document de design est un &lt;strong&gt;document vivant&lt;/strong&gt;, que j'adapte au fur et à mesure.&lt;/p&gt;
&lt;p&gt;Je commence à coller un &lt;strong&gt;scénario&lt;/strong&gt; sur mes éléments de gameplay, afin d'expliquer les contraintes. Pourquoi est-ce que le personnage ne peut pas sortir de la maison une fois qu'il y est entrée. Que s'est-il passé dans les différentes pièces.&lt;/p&gt;
&lt;p&gt;En retour, le scénario influe sur le design. Comment est-ce que j'agence les pièces, quels objets vont dans quelles pièces, qu'est-ce que je fais faire aux gens qui jouent ?&lt;/p&gt;
&lt;p&gt;C'est allers et retours entre conception du jeu, de niveaux, du scénario et du programme nourrissent peu à peu ces différentes parties et les font avancer de concert.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;manoir&lt;/strong&gt; initial se transforme en une &lt;strong&gt;maison&lt;/strong&gt; à moitié &lt;strong&gt;troglodyte&lt;/strong&gt;, car c'est un moyen assez « simple » d'avoir un environnement d'intérieur de maison et de grotte dans un espace assez restreint. C'est un peu tiré par les cheveux mais bon, on est dans du jeu vidéo rétro. Je me trouve même assez sobre par rapport à certaines productions.&lt;/p&gt;
&lt;p&gt;Petit à petit se construit aussi un &lt;strong&gt;double objectif&lt;/strong&gt; afin de pouvoir terminer le jeu. Sortir de la maison, mais aussi pouvoir reprendre la voiture qui nous a amené sur les lieux.&lt;/p&gt;
&lt;p&gt;J'ajoute aussi un peu de « lore » avec quelques objets qui ne sont pas nécessaires, mais qui font transparaître une &lt;strong&gt;histoire assez simple&lt;/strong&gt;, mais je pense suffisante pour l'ambition toute relative de ce jeu. J'ai donc écrit un petit background sur les évènements passés de cette maison. Qui sait ? Peut-être que je compléterai l'histoire grâce à d'autres jeux dans le futur.&lt;/p&gt;
&lt;h3&gt;Léger&lt;/h3&gt;
&lt;p&gt;La constante, c'est de &lt;strong&gt;rester léger&lt;/strong&gt;. Comme je l'ai évoqué, c'est un petit défi de programmation hobbyiste. Il ne faut surtout pas hésiter à couper, et donc prévoir des choses de manières à ce qu'elles puissent facilement être enlevées en modifiées.&lt;/p&gt;
&lt;p&gt;Je suis assez satisfait du résultat, même si j'y vois plein de petites erreurs, ou maladresses, en y jouant.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagramme montrant les étapes du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202301/MDLC-flow.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>Mattel Aquarius, scan des touches en assembleur</title><link href="https://www.triceraprog.fr/mattel-aquarius-scan-des-touches-en-assembleur.html" rel="alternate"></link><published>2023-01-19T00:00:00+01:00</published><updated>2023-01-19T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-01-19:/mattel-aquarius-scan-des-touches-en-assembleur.html</id><summary type="html">&lt;p&gt;Le scan du clavier, sur &lt;strong&gt;Mattel Aquarius&lt;/strong&gt;, à lieu dans la ROM à l'adresse &lt;code&gt;$1e80&lt;/code&gt;. Cette fonction traite les minuscules, les majuscules mais aussi les raccourcis BASIC, en injectant au fur et à mesure les touches nécessaires comme si elles avaient été tapées au clavier.&lt;/p&gt;
&lt;p&gt;C'est &lt;strong&gt;beaucoup trop&lt;/strong&gt; pour un scan de clavier dans un jeu, et peut même poser quelques soucis. Mais c'est une &lt;strong&gt;bonne base&lt;/strong&gt; pour écrire une routine de lecture de clavier, car la lecture des valeurs des touches n'est pas forcément très simples.&lt;/p&gt;
&lt;p&gt;Ce que nous apprends la lecture de la routine en ROM est qu'il semble falloir &lt;strong&gt;attendre une stabilité&lt;/strong&gt; dans les valeurs avant d'accepter la touche. En effet, la routine fait plusieurs lectures et ne considère la touche appuyée que si cette lecture est stable.&lt;/p&gt;
&lt;p&gt;Voici une version de la routine, où j'ai enlever ce qui était traitement de raccourcis BASIC, ainsi que le …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Le scan du clavier, sur &lt;strong&gt;Mattel Aquarius&lt;/strong&gt;, à lieu dans la ROM à l'adresse &lt;code&gt;$1e80&lt;/code&gt;. Cette fonction traite les minuscules, les majuscules mais aussi les raccourcis BASIC, en injectant au fur et à mesure les touches nécessaires comme si elles avaient été tapées au clavier.&lt;/p&gt;
&lt;p&gt;C'est &lt;strong&gt;beaucoup trop&lt;/strong&gt; pour un scan de clavier dans un jeu, et peut même poser quelques soucis. Mais c'est une &lt;strong&gt;bonne base&lt;/strong&gt; pour écrire une routine de lecture de clavier, car la lecture des valeurs des touches n'est pas forcément très simples.&lt;/p&gt;
&lt;p&gt;Ce que nous apprends la lecture de la routine en ROM est qu'il semble falloir &lt;strong&gt;attendre une stabilité&lt;/strong&gt; dans les valeurs avant d'accepter la touche. En effet, la routine fait plusieurs lectures et ne considère la touche appuyée que si cette lecture est stable.&lt;/p&gt;
&lt;p&gt;Voici une version de la routine, où j'ai enlever ce qui était traitement de raccourcis BASIC, ainsi que le traitement des touches de modifications. Ainsi, la traduction ne se fait qu'avec les touches minuscules.&lt;/p&gt;
&lt;p&gt;Attention, je n'ai pas encore testé cette routine sur du matériel réel !&lt;/p&gt;
&lt;h2&gt;La routine&lt;/h2&gt;
&lt;p&gt;Dans cette version, le &lt;strong&gt;décodage&lt;/strong&gt; de la touche est faite par rapport aux minuscules. En changeant vers la fin la valeur de HL de &lt;code&gt;lower_key_table-1&lt;/code&gt; vers &lt;code&gt;upper_key_table-1&lt;/code&gt;, il est possible d'obtenir un décodage avec des majuscules.&lt;/p&gt;
&lt;p&gt;Il est aussi possible de ne traiter que des codes de touches, sans traductions. Dans ce cas là, il suffit de remplacer les trois instructions après &lt;code&gt;accept_key&lt;/code&gt; par un simple &lt;code&gt;LD A, E&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;deux emplacements&lt;/strong&gt; en RAM, qui commencent ce code source, doivent être en RAM et être &lt;strong&gt;adaptés&lt;/strong&gt; à votre programme.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;latest_keycode_pressed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;EQU&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0380&lt;/span&gt;&lt;span class="no"&gt;eh&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;keyword_delay_value:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;EQU&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0380&lt;/span&gt;&lt;span class="no"&gt;fh&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;lower_key_table:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;EQU&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="no"&gt;f38h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;upper_key_table:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;EQU&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="no"&gt;f66h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;check_key:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;EXX&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;BC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0xff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;IN&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CPL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;AND&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0x3f&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;latest_keycode_pressed&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;no_key_scanned&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; ?No row were selected, quick skip?&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0x7f&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;; Input row 7&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;IN&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CPL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;AND&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0xf&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;; Only 4 keys in lower bits&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;NZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;decode_key_scan&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0xbf&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;; Input rows 6 to 0&lt;/span&gt;

&lt;span class="nl"&gt;loop_input_rows:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;IN&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CPL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;AND&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0x3f&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; 5 keys in lower bits&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;NZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;decode_key_scan&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;RRC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;loop_input_rows&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;no_key_scanned:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0x46&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CP&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Compare with delay&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;return_no_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;reset_latest_key&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Increment delay&lt;/span&gt;

&lt;span class="nl"&gt;return_no_key_value:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;XOR&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;EXX&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;RET&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;reset_latest_key:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;DEC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;0x0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;return_no_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;decode_key_scan:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;DE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0x0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;count_row:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;RRA&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;NC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;count_row&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;; E is the active row&lt;/span&gt;

&lt;span class="nl"&gt;count_add_column:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;RR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;NC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;keycode_found&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0x6&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="c1"&gt;; Add 6 for each column&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;count_add_column&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;keycode_found:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CP&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; HL = 0380eh&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;NZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;new_key_delay&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; That&amp;#39;s a new key, we need a bit of selay&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0x4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;CP&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;commit_key_delay_continued&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;accept_key&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Wait if over, accept key!&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;INC&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Increment delay from 4 to 6 iteratively&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;return_no_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;commit_key_delay_continued:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;0x6&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;; Set the delay for the second pass&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;return_no_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;new_key_delay:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;0x0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;JR&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;return_no_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;accept_key:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;IX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;lower_key_table-1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;IX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;DE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;LD&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="no"&gt;IX&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Read decoded Key value&lt;/span&gt;

&lt;span class="nf"&gt;return_key_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;EXX&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;RET&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="Aquarius"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category></entry><entry><title>Mattel Aquarius, entrées des commandes BASIC</title><link href="https://www.triceraprog.fr/mattel-aquarius-entrees-des-commandes-basic.html" rel="alternate"></link><published>2023-01-18T00:00:00+01:00</published><updated>2023-01-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-01-18:/mattel-aquarius-entrees-des-commandes-basic.html</id><summary type="html">&lt;p&gt;Commençant à étudier le &lt;strong&gt;Mattel Aquarius&lt;/strong&gt; afin de participer à la nouvelle session de « Retro Programmers United for Obscure Systems », et devant le manque de documentation, j'ai regardé ce qu'il y avait dans la ROM. Et c'est un BASIC Microsoft qui y est implémenté, ce qui est bien pratique puisque c'est un BASIC que j'ai bien étudié à travers le VG5000µ.&lt;/p&gt;
&lt;p&gt;J'ai donc ressorti ma &lt;strong&gt;trousse à outils&lt;/strong&gt; et voici la liste des &lt;strong&gt;points d'entrées&lt;/strong&gt; des commandes et fonctions du BASIC.&lt;/p&gt;
&lt;p&gt;La première colonne est le &lt;strong&gt;token&lt;/strong&gt; BASIC, la seconde l'&lt;strong&gt;adresse&lt;/strong&gt; du point d'entrée en ROM et la troisième &lt;strong&gt;le nom&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Les commandes&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    128     $0c21         end
    129     $05bc         for
    130     $0d13         next
    131     $071c         data
    132     $0893         input
    133     $10cc         dim
    134     $08be         read
    135     $0731         let
    136     $06dc         goto
    137     $06be         run
    138     $079c         if
    139     $0c05         restore
    140     $06cb         gosub
    141     $06f8         return
    142     $071e         rem
    143 …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Commençant à étudier le &lt;strong&gt;Mattel Aquarius&lt;/strong&gt; afin de participer à la nouvelle session de « Retro Programmers United for Obscure Systems », et devant le manque de documentation, j'ai regardé ce qu'il y avait dans la ROM. Et c'est un BASIC Microsoft qui y est implémenté, ce qui est bien pratique puisque c'est un BASIC que j'ai bien étudié à travers le VG5000µ.&lt;/p&gt;
&lt;p&gt;J'ai donc ressorti ma &lt;strong&gt;trousse à outils&lt;/strong&gt; et voici la liste des &lt;strong&gt;points d'entrées&lt;/strong&gt; des commandes et fonctions du BASIC.&lt;/p&gt;
&lt;p&gt;La première colonne est le &lt;strong&gt;token&lt;/strong&gt; BASIC, la seconde l'&lt;strong&gt;adresse&lt;/strong&gt; du point d'entrée en ROM et la troisième &lt;strong&gt;le nom&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Les commandes&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    128     $0c21         end
    129     $05bc         for
    130     $0d13         next
    131     $071c         data
    132     $0893         input
    133     $10cc         dim
    134     $08be         read
    135     $0731         let
    136     $06dc         goto
    137     $06be         run
    138     $079c         if
    139     $0c05         restore
    140     $06cb         gosub
    141     $06f8         return
    142     $071e         rem
    143     $0c1f         stop
    144     $0780         on
    145     $07b5         lprint
    146     $1b15         copy
    147     $0b3b         def
    148     $0b6d         poke
    149     $07bc         print
    150     $0c4b         cont
    151     $056c         list
    152     $0567         llist
    153     $0ccd         clear
    154     $1c2c         cload
    155     $1c08         csave
    156     $1a4f         pset
    157     $1a4c         preset
    158     $1ad6         sound
    159     $0bbd         new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Les fonctions&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    178     $14f5         sgn
    179     $15b1         int
    180     $1509         abs
    181     $3803         usr
    182     $10a8         fre
    183     $0b2e         lpos
    184     $0b33         pos
    185     $1775         sqr
    186     $1866         rnd
    187     $1385         log
    188     $17cd         exp
    189     $18d7         cos
    190     $18dd         sin
    191     $1970         tan
    192     $1985         atn
    193     $0b63         peek
    194     $0ff3         len
    195     $0e29         str
    196     $1084         val
    197     $1002         asc
    198     $1013         chr
    199     $1021         left
    200     $1050         right
    201     $1059         mid
    202     $4ec5         point
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cela peut aider à donner des points d'entrée pour comprendre comment fonctionne la machine.&lt;/p&gt;</content><category term="Machines"></category><category term="Aquarius"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category></entry><entry><title>La Maison dans la colline, partie 2</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-2.html" rel="alternate"></link><published>2023-01-06T00:00:00+01:00</published><updated>2023-01-06T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-01-06:/la-maison-dans-la-colline-partie-2.html</id><summary type="html">&lt;p&gt;Suite de la série sur le développement du jeu &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; sur VG5000µ. Après, la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;première partie&lt;/a&gt;, qui donnait le contexte de création, voici donc la deuxième partie, où j'aborde les outils de développement utilisés.&lt;/p&gt;
&lt;h3&gt;Les bases&lt;/h3&gt;
&lt;p&gt;Lorsque je développe un logiciel, je veux pouvoir me consacrer sur un temps contiguë maximum au cœur du projet. Même, et peut-être surtout, lorsque ce développement est un &lt;strong&gt;hobby&lt;/strong&gt;, et que j'ai peu d'heures à y consacrer, ici et là en fonction de mon temps libre.&lt;/p&gt;
&lt;p&gt;Ainsi, une fois le projet en développement, lorsque j'ai une petite demi-heure par-ci ou une grosse heure par là, je veux pouvoir m'installer et me consacrer à la valeur de ce projet. À son &lt;strong&gt;développement concret&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour moi, cela signifie que tout ce que je peux automatiser et qui me permettra de profiter de ces temps là au maximum doit l'être fait en amont …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Suite de la série sur le développement du jeu &lt;a href="https://mokona78.itch.io/la-maison-dans-la-colline"&gt;La maison dans la colline&lt;/a&gt; sur VG5000µ. Après, la &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;première partie&lt;/a&gt;, qui donnait le contexte de création, voici donc la deuxième partie, où j'aborde les outils de développement utilisés.&lt;/p&gt;
&lt;h3&gt;Les bases&lt;/h3&gt;
&lt;p&gt;Lorsque je développe un logiciel, je veux pouvoir me consacrer sur un temps contiguë maximum au cœur du projet. Même, et peut-être surtout, lorsque ce développement est un &lt;strong&gt;hobby&lt;/strong&gt;, et que j'ai peu d'heures à y consacrer, ici et là en fonction de mon temps libre.&lt;/p&gt;
&lt;p&gt;Ainsi, une fois le projet en développement, lorsque j'ai une petite demi-heure par-ci ou une grosse heure par là, je veux pouvoir m'installer et me consacrer à la valeur de ce projet. À son &lt;strong&gt;développement concret&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour moi, cela signifie que tout ce que je peux automatiser et qui me permettra de profiter de ces temps là au maximum doit l'être fait en amont. Si je dois cliquer sur des boutons, faire des manipulations, lancer ou configurer des logiciels à chaque fois que je fais un essai, voire même à chaque fois que je débute une session, c'est un &lt;strong&gt;temps précieux&lt;/strong&gt; qui est inutilisé. Chaque manipulation est aussi une occasion de faire une &lt;strong&gt;erreur&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Dans le passé sur ce site, j'ai déjà présenté &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html"&gt;quelques outils&lt;/a&gt; destinés à me faciliter la tâche. Et dès les essais sur l'EF9345 dont je parlais dans l'article précédent, j'ai remis en place un script qui permet de lancer l'émulateur automatiquement, configuré avec lancement du chargement.&lt;/p&gt;
&lt;p&gt;Comme je me doutais que le programme allait gagner en taille, j'ai ajouté au script une manière de passer l'émulateur en vitesse accélérée le temps du chargement.&lt;/p&gt;
&lt;p&gt;Ainsi, dès que je termine une compilation, je n'ai que &lt;strong&gt;quelques secondes&lt;/strong&gt; à attendre avant de retrouver le jeu, prêt à être testé, dans l'émulateur.&lt;/p&gt;
&lt;h3&gt;Le framework&lt;/h3&gt;
&lt;p&gt;Afin de pouvoir itérer sur le jeu, particulièrement sur son gameplay, j'ai choisi de développer dans un mélange de &lt;strong&gt;C&lt;/strong&gt; et d'&lt;strong&gt;assembleur&lt;/strong&gt;. Le C permet des modifications simples de morceaux de code sans trop se poser de questions bas niveau. L'assembleur permet d’accélérer certaines parties une fois qu'elles sont fixes, ainsi qu'un accès rapide au matériel.&lt;/p&gt;
&lt;p&gt;Car en effet, si j'ai choisi de faire un jeu d'aventure graphique, je tiens à deux choses au niveau de l'&lt;strong&gt;affichage&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;que l'affichage d'une pièce soit &lt;strong&gt;très rapide&lt;/strong&gt; (si ce n'est immédiat),&lt;/li&gt;
&lt;li&gt;que les mouvements à l'écran ne provoquent &lt;strong&gt;aucun clignotement&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Difficile voire impossible à faire cela en BASIC. Plus facile à faire en C, mais c'est l'assembleur qui me permettra de vraiment réaliser ces objectifs.&lt;/p&gt;
&lt;p&gt;De même, je voulais initialement que le jeu tienne sur une machine sans extension mémoire. Malheureusement, je ne réaliserai pas cet objectif. De peu...&lt;/p&gt;
&lt;h4&gt;z88dk&lt;/h4&gt;
&lt;p&gt;Quelques temps (années ?) auparavant, j'avais croisé le chemin de &lt;a href="https://z88dk.org/site/"&gt;z88dk&lt;/a&gt;, un framework de programmation en C dédié aux machines &lt;strong&gt;Z80&lt;/strong&gt;. Cela me semblait être une bonne occasion pour l'essayer, avoir l'espoir qu'il vienne avec des fonctionnalités intéressantes qui me feraient gagner du temps.&lt;/p&gt;
&lt;p&gt;Après tout, il y a des outils de création de programme assemblés dans une suite complète, une &lt;strong&gt;bibliothèque C&lt;/strong&gt; pour Z80, un &lt;strong&gt;support VG5000µ&lt;/strong&gt; et un fichier &lt;code&gt;crt.s&lt;/code&gt; déjà configuré et configurable. Ça, se sont les avantages.&lt;/p&gt;
&lt;p&gt;Après usage pendant toute la durée du projet, voici les inconvénients :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le programme principal qui appelle les autres pour la compilation n'a &lt;strong&gt;pas une syntaxe d'option standard&lt;/strong&gt;, et cela me posera des problèmes avec &lt;code&gt;cmake&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;le &lt;strong&gt;compilateur&lt;/strong&gt; par défaut n'est &lt;strong&gt;pas le meilleur&lt;/strong&gt;, je m'en rendrai compte beaucoup plus tard, vers la fin du projet. Il est possible d'utiliser un compilateur alternatif, qui optimise visiblement mieux. Malheureusement, les deux ne se comportent pas tout à fait de la même façon, et j'ai préférer ne pas changer en chemin. On verra pour un futur projet peut-être,&lt;/li&gt;
&lt;li&gt;le support VG5000µ est axé sur une utilisation en &lt;strong&gt;mode texte&lt;/strong&gt;, et passe par le système implémenté par la &lt;strong&gt;ROM&lt;/strong&gt;, sans accès direct à l'EF9345. Ce n'est pas cohérent avec ce que je veux faire, et je n'utiliserai finalement aucune fonction spécifiquement dédiée au VG5000µ.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Au final, je ne suis pas entièrement convaincu par z88dk, qui à l'air de prendre une orientation plutôt CP/M et machined un peu plus puissantes qu'un VG5000µ.&lt;/p&gt;
&lt;h3&gt;Gestion de la construction&lt;/h3&gt;
&lt;p&gt;Pour le gestionnaire de construction de version, je suis parti sur &lt;code&gt;cmake&lt;/code&gt;. C'est très probablement &lt;strong&gt;surdimensionné&lt;/strong&gt;, mais je connais son utilisation classique. Ici, je voulais pousser plus loin et aborder sa configuration de chaîne de compilation « exotique ».&lt;/p&gt;
&lt;p&gt;J'ai beaucoup appris sur &lt;code&gt;cmake&lt;/code&gt; au passage ; ma solution finale n'est pas entièrement solide, je confirme à nouveau que Stack Overflow n'est d'aucune aide dès que vous avez un soucis qui n'est pas basique, que la documentation de &lt;code&gt;cmake&lt;/code&gt; est toujours peu aidante... et qu'un &lt;strong&gt;Makefile&lt;/strong&gt; tout simple aurait été probablement tout aussi efficace. Mais je m'emmêle toujours les pinceaux avec un Makefile dès que je quitte les règles de bases.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cmake&lt;/code&gt; est probablement trop automatique sur certains points, et il n'est pas toujours facile de lui faire comprendre que la buildchain utilisé ne se comporte pas tout à fait comme ce à quoi il s'attend.&lt;/p&gt;
&lt;p&gt;Enfin maintenant c'est fait, et même si je dois corriger certaines petites choses au niveau des dépendances entre les &lt;code&gt;.c&lt;/code&gt;, les &lt;code&gt;.h&lt;/code&gt; et les &lt;code&gt;.asm&lt;/code&gt;, ça marche globalement bien.&lt;/p&gt;
&lt;h3&gt;Éditeur de code&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cmake&lt;/code&gt; était surdimensionné ? Que dire de l'éditeur de code que j'ai utilisé. &lt;code&gt;CLion&lt;/code&gt;... &lt;code&gt;vim&lt;/code&gt; ou &lt;code&gt;visual studio code&lt;/code&gt; auraient suffit. Et il m'est arrivé d'utiliser &lt;code&gt;vim&lt;/code&gt; pendant le développement pour quelques modifs rapides. Mais là encore, je connais bien &lt;code&gt;CLion&lt;/code&gt;, ses outils, sa configuration, et l'habitude, ça compte.&lt;/p&gt;
&lt;p&gt;De toute façon, mes outils d'automatisation ne sont dépendants ni de &lt;code&gt;cmake&lt;/code&gt;, ni de &lt;code&gt;clion&lt;/code&gt;, ce sont donc des choix indépendants.&lt;/p&gt;
&lt;h3&gt;Paré au départ !&lt;/h3&gt;
&lt;p&gt;Ou presque. J'ai cité les outils de développement principaux. Mais je parlais en introduction d'automatiser la mise en place de l'environnement de développement. Pour cela, j'utilise le terminal &lt;code&gt;kitty&lt;/code&gt; associé à un script. Lorsque je lance &lt;strong&gt;ce script&lt;/strong&gt;, le terminal se met en place avec les bon terminaux ouverts dans les bons répertoire, et des outils textes déjà lancés (&lt;code&gt;ranger&lt;/code&gt; pour la gestion de fichier, &lt;code&gt;lazygit&lt;/code&gt; pour la gestion de version, &lt;code&gt;nb&lt;/code&gt; pour la prise de notes, le script d'automatisation à l'écoute).&lt;/p&gt;
&lt;p&gt;Ainsi, démarrer une session depuis un ordinateur fraîchement allumé me prend &lt;strong&gt;deux clics&lt;/strong&gt; pour avoir l'intégralité de l'environnement en place, et j'ai tout ce qu'il me faut pour la session. Cela aurait été un seul si je n'avais pas choisi &lt;code&gt;Clion&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alors... clic, clic... et la suite au prochain épisde.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture montrant l'explorateur textuel Ranger dans le répertoire du jeu." class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202301/20230106-Ranger-MDLC.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>Plouf ... in space</title><link href="https://www.triceraprog.fr/plouf-in-space.html" rel="alternate"></link><published>2023-01-03T00:00:00+01:00</published><updated>2023-01-03T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2023-01-03:/plouf-in-space.html</id><summary type="html">&lt;p&gt;En attendant de revenir sur le déroulé du développement de « &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;La maison dans la colline&lt;/a&gt; », voici un article beaucoup plus court pour présenter ma contribution à la session la plus récente de « &lt;a href="https://itch.io/jam/retro-programmers-united-for-obscure-systems-exelvision"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt; », consacrée à &lt;strong&gt;Exelvision&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;La découverte de la machine&lt;/h3&gt;
&lt;p&gt;Exelvision, une entreprise française, a produit au milieu des années 80 une série de machines assez originales. Ce sont des machines de type familial, mais avec un look un peu pro, un choix audacieux mais probablement désastreux d'une connectique sans fil pour le clavier et les joysticks, de la synthèse vocale, et des capacités graphiques plutôt correctes.&lt;/p&gt;
&lt;p&gt;Pour ce challenge, je me suis orienté vers la première de ces machines, l'&lt;strong&gt;EXL 100&lt;/strong&gt;, dont vous pouvez trouver une présentation détaillée sur &lt;a href="http://www.ti99.com/exelvision/website/index.php?page=exl100"&gt;ce site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;C'est une machine que je ne connaissais pas vraiment. Ou tout du moins, je ne m'étais pas penché sur ces caractéristiques …&lt;/p&gt;</summary><content type="html">&lt;p&gt;En attendant de revenir sur le déroulé du développement de « &lt;a href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html"&gt;La maison dans la colline&lt;/a&gt; », voici un article beaucoup plus court pour présenter ma contribution à la session la plus récente de « &lt;a href="https://itch.io/jam/retro-programmers-united-for-obscure-systems-exelvision"&gt;Retro Programmers United for Obscure Systems&lt;/a&gt; », consacrée à &lt;strong&gt;Exelvision&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;La découverte de la machine&lt;/h3&gt;
&lt;p&gt;Exelvision, une entreprise française, a produit au milieu des années 80 une série de machines assez originales. Ce sont des machines de type familial, mais avec un look un peu pro, un choix audacieux mais probablement désastreux d'une connectique sans fil pour le clavier et les joysticks, de la synthèse vocale, et des capacités graphiques plutôt correctes.&lt;/p&gt;
&lt;p&gt;Pour ce challenge, je me suis orienté vers la première de ces machines, l'&lt;strong&gt;EXL 100&lt;/strong&gt;, dont vous pouvez trouver une présentation détaillée sur &lt;a href="http://www.ti99.com/exelvision/website/index.php?page=exl100"&gt;ce site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;C'est une machine que je ne connaissais pas vraiment. Ou tout du moins, je ne m'étais pas penché sur ces caractéristiques, son architecture ni même sur les périphériques disponibles. Et la &lt;strong&gt;surprise&lt;/strong&gt; fut là.&lt;/p&gt;
&lt;p&gt;Côté processeur principal, je savais qu'il faisait dans l'original, un &lt;strong&gt;TMS 7020&lt;/strong&gt;. Côté RAM, tout est côté vidéo, associée à un TMS 3556, non accessible directement par le TMS 7020. Ça promet. Toute cette place mémoire, &lt;strong&gt;32 ko&lt;/strong&gt; tout de même, hors de porté du bus principal. Et en RAM principale ? ... &lt;strong&gt;2 ko&lt;/strong&gt;. Deux tout petits kilo octets, déjà très occupés par le système.&lt;/p&gt;
&lt;p&gt;Je me tourne vers le &lt;strong&gt;BASIC&lt;/strong&gt; pour découvrir la machine. Celui-ci est disponible sur cartouche. Et ses données sont bien en VRAM, le seul endroit où il y a de la place. Les performances sont en adéquation. C'est lent. Pas très lent, il y a pire, mais lent tout de même.&lt;/p&gt;
&lt;p&gt;La machine peut bien supporter des extensions mémoires, mais l'architecture laisse peu de place au doute : c'est une machine qui est faite pour lancer ses programmes sur &lt;strong&gt;cartouches&lt;/strong&gt; en priorité, à moins de lui adjoindre l'extension &lt;strong&gt;disquettes&lt;/strong&gt;, qui fait entrer la machine dans une toute autre dimension.&lt;/p&gt;
&lt;p&gt;Ces matériels ne sont pas très courant, et semblent complexifier la machine, je décide donc de cibler l'EXL100 de base, sans extension.&lt;/p&gt;
&lt;h3&gt;Les deux premières pistes&lt;/h3&gt;
&lt;p&gt;La première piste que j'explore est &lt;strong&gt;technique&lt;/strong&gt; : celle de proposer le logiciel sur cartouche. L'avantage me semble être une rapidité d'exécution. L'inconvénient est que je n'ai aucune idée de comment fonctionne la ROM de la machine, de ce qu'il faut pour la faire reconnaître. Ça se trouve bien entendu, mais je ne connais pas non plus l'assembleur TMS 7020. Je laisse l'idée rapidement de côté, il y a trop d'inconnues pour moi sur cette machine.&lt;/p&gt;
&lt;p&gt;La seconde piste est &lt;strong&gt;logicielle&lt;/strong&gt; : écrire une machine virtuelle qui tiendrait dans la petite RAM de la machine pour exécuter un byte code présent dans la VRAM. L'idée me plaît bien et j'y réfléchi un temps tout en consultant les documentations de la machine. Mais encore un fois, je m'aperçois des particularités de la machine. Je crains le hors sujet.&lt;/p&gt;
&lt;p&gt;Au final, faisons simple : un petit jeu en BASIC pour s'entraîner. Et si j'ai le temps, loger un peu d'assembleur pour accélérer certaines parties.&lt;/p&gt;
&lt;h3&gt;Plouf&lt;/h3&gt;
&lt;p&gt;Puisque j'ai besoin de creuser ma connaissance de la machine, je ne peux pas me lancer dans quelque chose de compliqué. Je vais donc chercher dans &lt;strong&gt;les classiques&lt;/strong&gt;. Après quelques hésitations, je choisi la &lt;strong&gt;bataille navale&lt;/strong&gt;. C'est un jeu qui peut se représenter avec des graphismes détaillé tout comme en caractères, c'est assez simple à programmer. Petit inconvénient, il me faudra une IA pour un jeu à une seule personne.&lt;/p&gt;
&lt;p&gt;Je cherche un &lt;strong&gt;petit twist&lt;/strong&gt; tout de même pour ne pas aller dans le trop classique et je me dis que faire bouger les bateaux entre deux tours pourrait être sympa sans trop complexifier le jeu. Là encore, c'est débrayable, si je n'ai pas le temps, je ferai sans.&lt;/p&gt;
&lt;p&gt;Et donc c'est parti.&lt;/p&gt;
&lt;h3&gt;Le BASIC&lt;/h3&gt;
&lt;p&gt;La plupart des &lt;strong&gt;BASIC&lt;/strong&gt;s de l'époque se ressemblent, souvent parce qu'ils sont soient des adaptations du BASIC Microsoft, soit parce qu'ils ont été créés avec une syntaxe similaire, ou en tout cas en suivant cette branche d'évolution du BASIC.&lt;/p&gt;
&lt;p&gt;Sans être complètement différent, le BASIC Exelevision a des &lt;strong&gt;particularités&lt;/strong&gt;. Entre autre, il a un concept de &lt;strong&gt;routines&lt;/strong&gt; appelables sans tenir compte de son numéro de ligne. Pratique à première vue. De plus, dans ces routines, les &lt;strong&gt;variables sont locales&lt;/strong&gt;. C'est plutôt attrayant.&lt;/p&gt;
&lt;p&gt;Rapidement, les routines semblent être une fausse bonne idée. En premier lieu, même si le numéro de ligne n'a pas d'importance, elles doivent absolument se trouver à la fin du programme, sous peine d'erreur (et les erreurs sont sous forme de nombres seulement, mieux vaut avoir le manuel sous les yeux). Et puis la localité des variables est tout ou rien. Et on ne peut pas passer de tableaux à ces routines.&lt;/p&gt;
&lt;p&gt;Au final, je ne garde qu'une paire de fonctionnalités sous forme de routines. Le reste sera fait avec ce bon vieux &lt;strong&gt;GOSUB&lt;/strong&gt; et des numéros de ligne.&lt;/p&gt;
&lt;p&gt;Le BASIC permet aussi un traitement d'exception, avec de la récupération d'erreurs. C'est plutôt pas mal... mais je ne penserai à m'en servir que tard dans le développement. Ce BASIC semble cependant un peu &lt;strong&gt;capricieux&lt;/strong&gt;, avec des commandes qui parfois ne veulent pas être sur la même ligne et parfois oui... je n'ai pas vraiment compris les raisons.&lt;/p&gt;
&lt;p&gt;Le démarrage d'un programme après un RUN est assez long, et de plus en plus long avec l'avancée du projet. J'acquière la certitude que RUN effectue une &lt;strong&gt;vérification&lt;/strong&gt; du programme. Peut-être pas une compilation, quoi que je n'en sais rien, mais il est capable de détecter avant démarrage les erreurs de numéros de lignes dans les GOTO/GOSUB, et les mauvais appariement de boucles FOR/NEXT.&lt;/p&gt;
&lt;p&gt;C'est pratique pour le premier cas, parfois un peu obscure pour le second, car la ligne en erreur n'est pas toujours celle où se trouve vraiment l'erreur.&lt;/p&gt;
&lt;p&gt;Cependant, c'est une &lt;strong&gt;fonctionnalité notable&lt;/strong&gt;, car peu présente, voire pas, sur d'autres BASIC de cette époque.&lt;/p&gt;
&lt;h3&gt;Le jeu&lt;/h3&gt;
&lt;p&gt;Je n'ai pas grand chose à dire sur le jeu lui-même. La principale difficulté est d'arriver à caser deux grilles à l'écran. L'algorithme de déplacement et collision des bateaux me pose aussi quelques soucis, et debugguer n'est pas des plus plaisants, même sur émulateur. Cette machine est peu utilisée, peu connue, et le manque d'outils se fait cruellement sentir.&lt;/p&gt;
&lt;p&gt;Mais je crois bien que ça sera le cas à chaque fois pour ces Game Jams, étant donné que le but est d'aller sur des machines sur lesquels il y a peu de développement.&lt;/p&gt;
&lt;p&gt;Mon principal &lt;strong&gt;problème&lt;/strong&gt; est la &lt;strong&gt;vitesse&lt;/strong&gt;. Le jeu est affreusement lent. Vraiment. Le fait que les bateaux bougent et collisionnent pour faire demi tour demande de longs calculs. Un temps, j'imagine couper les collisions et dire que après tout, ce sont des sous-marins et qu'ils peuvent passer l'un sur l'autre.&lt;/p&gt;
&lt;p&gt;Cependant, cela complexifie la compréhension du jeu, ainsi que la gestion des tirs, qui peuvent toucher plusieurs sous-marins en même temps. Je décide donc qu'il est temps de s'essayer à un peu d'assembleur.&lt;/p&gt;
&lt;h3&gt;Optimisations assembleur&lt;/h3&gt;
&lt;p&gt;Le TMS 7020, de la série &lt;strong&gt;TMS 7000&lt;/strong&gt;, est un processeur connu, même si pas aussi utilisé dans les ordinateurs personnes que le Z80 ou le 6809. Il est donc supporté par des assembleurs et en particulier par &lt;a href="http://john.ccac.rwth-aachen.de:8000/as/"&gt;celui-ci&lt;/a&gt;, que je connais déjà. Parfait.&lt;/p&gt;
&lt;p&gt;J'avais déjà commencé à lire des ressources sur la programmation de cette machine et ses 128 registres. &lt;strong&gt;Quel luxe&lt;/strong&gt;... ou presque, car c'est dans cette mémoire interne que se loge la pile aussi. Ça reste quand même bien spacieux.&lt;/p&gt;
&lt;p&gt;Et au final, c'est un processeur plutôt agréable. Très simple à programmer. La plus grosse difficulté étant plutôt, à nouveau, de comprendre l'environnement de la machine, les registres à préférer et/ou à laisser tranquille. Comment discuter avec le processeur vidéo et accéder à la VRAM. Mais là encore, il y a de nombreux exemples dans de la documentation.&lt;/p&gt;
&lt;p&gt;La machine, bien que peu connue et peu dynamique, a eu déjà eu des retro-développeurs dans le passé proche. La route est pavée. Un peu laissée à l'abandon, mais pavée quand même, et c'est agréable. &lt;strong&gt;Merci à eux&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Au final, transférer en assembleur mes routines les plus coûteuses se révèle &lt;strong&gt;extrêmement bénéfique&lt;/strong&gt;. J'en aurais bien transféré plus, mais d'après la documentation, j'ai évalué à un peu moins de 500 octets la place disponible de manière « sûre ». On devrait pouvoir pousser un peu plus, mais je n'avais pas le temps de pousser les tests. Restons prudent.&lt;/p&gt;
&lt;h3&gt;... in Space&lt;/h3&gt;
&lt;p&gt;Pendant le développement, j'ai souvent hésité. Est-ce que ce sont des &lt;strong&gt;bateaux&lt;/strong&gt; ? Est-ce que ce sont des &lt;strong&gt;vaisseaux spaciaux&lt;/strong&gt; ? Initialement, je comptais redéfinir des caractères afin d'avoir un affichage un peu plus joli. Le temps manquant, je suis resté sur le jeu de caractères disponibles dans le BASIC, qui heureusement à quelques caractères permettant de tracer des lignes en mode basse résolution.&lt;/p&gt;
&lt;p&gt;Pas non plus le temps d'enjoliver en utilisant un peu de mode haute résolution, qui peut se partager l'écran sur cette machine avec le mode texte. L'essentiel du développement se fait pendant mes vacances de fin d'années, et donc juste à la fin de la période de la Game Jam.&lt;/p&gt;
&lt;p&gt;Donc bateau ou vaisseau... cela n'a pas vraiment d'importance en soi.&lt;/p&gt;
&lt;p&gt;Oui mais, dans cette Game Jam, même si on n'en est qu'à la deuxième session, il est de « tradition » de pousser un peu la qualité en ayant une &lt;strong&gt;couverture&lt;/strong&gt; de jeu, une &lt;strong&gt;illustration&lt;/strong&gt;, un &lt;strong&gt;manuel&lt;/strong&gt;, ou un peu de tout ça. Et les jeux de l'époque misaient beaucoup sur ce packaging pour faire travailler l'imagination.&lt;/p&gt;
&lt;p&gt;Donc je dois choisir. Et je choisi l'espace... même si le fond de l'écran pendant le jeu reste bleu foncé. Les vaisseaux ne sont pas coulés après avoir été touchés, mais désactivés, ce qui me donne une justification au RADAR, qui réagi aux morceaux de vaisseaux touchés.&lt;/p&gt;
&lt;p&gt;Il me reste une &lt;strong&gt;IA&lt;/strong&gt; à &lt;strong&gt;bricoler&lt;/strong&gt;. Je fais simple : si le RADAR ne donne pas d'information, le coup prochain se fera au hasard. S'il donne une information, le tir se fera d'autant de cases que la distance indiquée par le RADAR, réparties en horizontal et en vertical. Cela ne prend pas en compte le déplacement des vaisseaux, ni les touches précédentes, mais après quelques parties, je juge que c'est suffisant pour mettre une petite pression à l'humain.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Une &lt;strong&gt;machine originale&lt;/strong&gt;, qui demande vraiment à y revenir. Un jeu qui ne vole pas très haut, mais qui a été intéressant à optimiser et comme toujours, à terminer et présenter.&lt;/p&gt;
&lt;p&gt;Si vous aussi vous voulez jouer avec des torpilles photoniques, c'est &lt;a href="https://mokona78.itch.io/plouf-in-space"&gt;par ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran de jeu de Plouf... in Space" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202301/20230103-PloufInSpace.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category></entry><entry><title>Inifinite Turtles, un jeu avec des tortues jusqu'en bas.</title><link href="https://www.triceraprog.fr/inifinite-turtles-un-jeu-avec-des-tortues-jusquen-bas.html" rel="alternate"></link><published>2022-12-22T00:00:00+01:00</published><updated>2022-12-22T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2022-12-22:/inifinite-turtles-un-jeu-avec-des-tortues-jusquen-bas.html</id><summary type="html">&lt;p&gt;Le jeu « &lt;a href="https://store.steampowered.com/app/1952740/Infinite_Turtles/"&gt;&lt;strong&gt;Inifinite Turtles&lt;/strong&gt;&lt;/a&gt; », de Charlie Brej, est un casse-tête de programmation. De manière classique dans ce type de jeu, vous êtes exposés à des problèmes de plus en plus complexe à résoudre, en ayant à votre disposition de nouvelles briques du système.&lt;/p&gt;
&lt;p&gt;En ce sens, il se rapproche des jeux de &lt;em&gt;Zachtronics&lt;/em&gt; comme &lt;em&gt;Shenzhen I/O&lt;/em&gt;, de &lt;em&gt;Human Resource Machine&lt;/em&gt; ou bien d'autres, à un niveau de réalisation moins poussé tout en étant tout à fait acceptable.&lt;/p&gt;
&lt;p&gt;Dans « Infinite Turtles », votre terrain est une grille de positions avec quatre « portes » aux points cardinaux. Ces portes sont des entrées ou des sorties par lesquels vont transiter des jetons numérotés.&lt;/p&gt;
&lt;p&gt;À votre charge d'acheminer les jetons grâce à des tapis roulants à travers la grille.&lt;/p&gt;
&lt;p&gt;Chaque niveau vous indique l'objectif à atteindre et vous donne, pour les premiers niveaux, des indications sur le fonctionnement du jeu, ainsi qu'une nouvelle brique fonctionnelle …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Le jeu « &lt;a href="https://store.steampowered.com/app/1952740/Infinite_Turtles/"&gt;&lt;strong&gt;Inifinite Turtles&lt;/strong&gt;&lt;/a&gt; », de Charlie Brej, est un casse-tête de programmation. De manière classique dans ce type de jeu, vous êtes exposés à des problèmes de plus en plus complexe à résoudre, en ayant à votre disposition de nouvelles briques du système.&lt;/p&gt;
&lt;p&gt;En ce sens, il se rapproche des jeux de &lt;em&gt;Zachtronics&lt;/em&gt; comme &lt;em&gt;Shenzhen I/O&lt;/em&gt;, de &lt;em&gt;Human Resource Machine&lt;/em&gt; ou bien d'autres, à un niveau de réalisation moins poussé tout en étant tout à fait acceptable.&lt;/p&gt;
&lt;p&gt;Dans « Infinite Turtles », votre terrain est une grille de positions avec quatre « portes » aux points cardinaux. Ces portes sont des entrées ou des sorties par lesquels vont transiter des jetons numérotés.&lt;/p&gt;
&lt;p&gt;À votre charge d'acheminer les jetons grâce à des tapis roulants à travers la grille.&lt;/p&gt;
&lt;p&gt;Chaque niveau vous indique l'objectif à atteindre et vous donne, pour les premiers niveaux, des indications sur le fonctionnement du jeu, ainsi qu'une nouvelle brique fonctionnelle.&lt;/p&gt;
&lt;p&gt;Ces briques fonctionnelles occupent un espace sur la grille. Elles réalisent une fonction simple, comme par exemple un aiguillage, un clonage du jeton ou encore un filtre.&lt;/p&gt;
&lt;p&gt;De plus, chaque niveau réalisé devient une nouvelle brique fonctionnelle que vous pouvez utiliser pour résoudre d'autres niveaux. Et bien entendu, le jeu est construit de manière à ce que les nouvelles fonctions servent dans les problèmes suivants.&lt;/p&gt;
&lt;p&gt;Enfin, pour vous aider à la réalisation du niveau, un batterie de tests est disponible, que vous pouvez exécuter plus ou moins rapidement, afin d'aider à mettre au point la solution.&lt;/p&gt;
&lt;p&gt;Et enfin, un score vous indique l'efficacité en temps et en briques utilisées et vous pouvez le comparer aux autres joueurs.&lt;/p&gt;
&lt;h2&gt;Des tortues jusqu'en bas&lt;/h2&gt;
&lt;p&gt;Le titre du jeu ne fait pas référence à une tortue de type de celle utilisée dans le langage Logo, mais à la cosmogonie qui dit que la Terre repose sur une tortue, elle même reposant sur une tortue,... et tout ceci &lt;a href="https://fr.wikipedia.org/wiki/Des_tortues_jusqu%27en_bas"&gt;jusqu'en bas&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le thème est introduit dès le début dans les explications par les dialogues des personnages qui animent la narration, qui sont toujours par couple identique mais de tailles différentes.&lt;/p&gt;
&lt;p&gt;Ainsi, le jeu introduit l'utilisation de briques fonctionnelles qui utilisent elles-mêmes d'autres briques fonctionnelles qui utilisent, etc.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Aperçu du jeu Infinite Turtles" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202212/InfiniteTurtles-750.jpeg"&gt;&lt;/p&gt;
&lt;h1&gt;Tout dans la synchro&lt;/h1&gt;
&lt;p&gt;La difficulté des problèmes n'est pas tant de les résoudre fonctionnellement, mais de les placer sur une grille restreinte. En effet, rapidement, la place se fait rare, et l'utilisation des briques déjà faites est nécessaire.&lt;/p&gt;
&lt;p&gt;Cependant, le système que crée le jeu est très dépendant des synchronisations. En effet, les jetons arrivent avec un tempo déterminé par les tests et leur temps de trajet sur les tapis roulants est entièrement dépendant de la longueur de ces trajets, y compris des trajets dans les briques internes.&lt;/p&gt;
&lt;p&gt;Dès les premiers niveaux, les défis proposés sont clairs : il va falloir trouver des moyens de synchroniser tous ces jetons pour qu'ils arrivent face au briques fonctionnelles au moment voulu. Le jeu guide vers des systèmes de synchronisation que l'on découvre et que l'on pourra appliquer plus tard.&lt;/p&gt;
&lt;p&gt;Mais ces systèmes prennent de la place, beaucoup de place, car basé sur de l'envoi de messages par jetons. Ils nécessitent donc des tapis roulants encombrants.&lt;/p&gt;
&lt;h1&gt;Et donc ?&lt;/h1&gt;
&lt;p&gt;Je n'ai pas terminé tous les niveaux du jeu. Je suis allé assez loin, mais au bout d'un moment, j'avais l'impression que le problème à résoudre était essentiellement du routage de jeton et comment faire tenir le tout dans la grille.&lt;/p&gt;
&lt;p&gt;Les fonctions d'édition avancées de la grille, qui ne sont pas présentée dès le début, ne sont pas toujours très agréable non plus. Quand on veut essayer différents type de routages afin de voir celui qui prend le moins d'espace, le comportement des tapis roulant est rapidement agaçant.&lt;/p&gt;
&lt;p&gt;Un autre défaut, mais moindre, est la progression des niveaux, qui mériterait plus de fluidité. Les problèmes par lesquels ont passe ont un objectif, on le sent bien, mais on passe parfois du coq à l'âne, sur des voies que l'on sent se rejoindre au loin, mais qui produisent une sorte de « task switching » peu agréable.&lt;/p&gt;
&lt;p&gt;Malgré ces petits soucis, et sur la vingtaine de niveaux que j'ai pu résoudre, j'ai trouvé le jeu amusant et plutôt original. Le modèle d'automation et le type de programmation qu'il induit sont plutôt originaux, avec une petite histoire métaphysique pour enrober le tout.&lt;/p&gt;
&lt;p&gt;C'est un jeu qui se défend tout à fait dans sa catégorie, et si vous êtes curieux et aimez les jeux d'énigmes logiques, cela pourra vous plaire.&lt;/p&gt;</content><category term="Jeux"></category><category term="Machine virtuelle"></category><category term="Jeu Vidéo"></category></entry><entry><title>La Maison dans la colline, partie 1</title><link href="https://www.triceraprog.fr/la-maison-dans-la-colline-partie-1.html" rel="alternate"></link><published>2022-12-22T00:00:00+01:00</published><updated>2022-12-22T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2022-12-22:/la-maison-dans-la-colline-partie-1.html</id><summary type="html">&lt;p&gt;En juin 2022, sur Facebook, &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; lance un groupe avec l'objectif de donner un peu d'activité à des ordinateurs qui n'en n'ont pas beaucoup. En effet, si quelques anciennes machines bénéficient de nombreux nouveaux logiciels homebrew toujours de nos jours, certaines autres ont une base d'utilisateurs beaucoup plus restreinte. Et souvent une ludothèque maigrichonne.&lt;/p&gt;
&lt;p&gt;Initialement, je n'ai pas trop prêté attention à l'initiative. J'étais justement en train de nettoyer mon compte Facebook avec l'idée de ne plus y mettre les pieds, tout en gardant un accès minimale « au cas où ». Mais quand on m'avertie qu'un vote a désigné le &lt;strong&gt;VG5000µ&lt;/strong&gt; comme première machine, je dresse l'oreille.&lt;/p&gt;
&lt;p&gt;Ça tombe bien, je m'étais remis à l'étude du VG5000µ après le hiatus de l'étude du &lt;a href="https://www.triceraprog.fr/baisse-de-regime-en-apparence.html"&gt;Micral N&lt;/a&gt;. C'est une excellente occasion pour relier les deux activités : continuer l'exploration de la machine, tout en développant un jeu.&lt;/p&gt;
&lt;p&gt;Reste à trouver l'idée. J'aimerais quelque chose …&lt;/p&gt;</summary><content type="html">&lt;p&gt;En juin 2022, sur Facebook, &lt;a href="https://www.youtube.com/@Olipix"&gt;Olipix&lt;/a&gt; lance un groupe avec l'objectif de donner un peu d'activité à des ordinateurs qui n'en n'ont pas beaucoup. En effet, si quelques anciennes machines bénéficient de nombreux nouveaux logiciels homebrew toujours de nos jours, certaines autres ont une base d'utilisateurs beaucoup plus restreinte. Et souvent une ludothèque maigrichonne.&lt;/p&gt;
&lt;p&gt;Initialement, je n'ai pas trop prêté attention à l'initiative. J'étais justement en train de nettoyer mon compte Facebook avec l'idée de ne plus y mettre les pieds, tout en gardant un accès minimale « au cas où ». Mais quand on m'avertie qu'un vote a désigné le &lt;strong&gt;VG5000µ&lt;/strong&gt; comme première machine, je dresse l'oreille.&lt;/p&gt;
&lt;p&gt;Ça tombe bien, je m'étais remis à l'étude du VG5000µ après le hiatus de l'étude du &lt;a href="https://www.triceraprog.fr/baisse-de-regime-en-apparence.html"&gt;Micral N&lt;/a&gt;. C'est une excellente occasion pour relier les deux activités : continuer l'exploration de la machine, tout en développant un jeu.&lt;/p&gt;
&lt;p&gt;Reste à trouver l'idée. J'aimerais quelque chose qui pousse un peu les capacités d'affichage de la machine. En attendant, je commence à mettre en place une chaîne d'outils de développements avec comme premier objectif le développement d'un programme de tests des différentes possibilités graphiques de l'EF9345.&lt;/p&gt;
&lt;p&gt;L'idée derrière la batterie de tests est de documenter l'utilisation de ce processeur graphique en publiant les sources, de démontrer ses différents modes (ce qui a déjà été fait par le passé), et de proposer des tests pour pouvoir travailler les détails des timings et les commandes non implémentées actuellement dans les deux émulateurs du VG5000µ (&lt;a href="http://dcvg5k.free.fr/"&gt;dcvg5k&lt;/a&gt; et &lt;a href="https://www.mamedev.org/"&gt;MAME&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Je n'ai pas encore terminé cette batterie de tests, puisque je suis passé entre temps sur le développement du jeu. Je publierai ça sous peu, même si pas terminé, accompagné d'articles.&lt;/p&gt;
&lt;p&gt;En attendant, en voici une copie d'écran.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran de jeu de la Maison dans la colline" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202212/20220927232738-MaisonColline-01.png"&gt;&lt;/p&gt;</content><category term="Projets"></category><category term="Jeu"></category><category term="MDLC"></category></entry><entry><title>Utilisation de z88dk pour le VG5000</title><link href="https://www.triceraprog.fr/utilisation-de-z88dk-pour-le-vg5000.html" rel="alternate"></link><published>2022-07-03T00:00:00+02:00</published><updated>2022-07-03T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2022-07-03:/utilisation-de-z88dk-pour-le-vg5000.html</id><summary type="html">&lt;p&gt;Encore ?! Oui... encore. Une nouvelle manière de gérer la construction d'un programme VG5000µ. Après la version &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-sublime-text-3.html"&gt;Sublime Text et z80asm&lt;/a&gt; en 2018, puis la version &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-visual-studio-code.html"&gt;Visual Studio Code et sjasmplus&lt;/a&gt; en 2020, je voulais essayer autre chose.&lt;/p&gt;
&lt;p&gt;J'avais laissé de côté Sublime Text et z80asm pour deux raisons : le changement de license de Sublime Text que je n'avais pas apprécié, et le côté très simpliste de z80asm, dont je touchais des limites.&lt;/p&gt;
&lt;p&gt;Pour un nouveau projet, je voulais utiliser &lt;a href="https://z88dk.org/"&gt;z88dk&lt;/a&gt;, un kit de développement pour machines Z80, avec du support C et ASM, ainsi que des bibliothèques standards. Je voulais aussi approfondir ma connaissance du support de toolchains avec CMake.&lt;/p&gt;
&lt;p&gt;Alors oui, &lt;code&gt;cmake&lt;/code&gt; pour un tout petit projet pour des machines des années 80, ça fait un peu surdimensionné... Je le concède. Et ça n'enlève en rien mon envie de fouiller de ce côté.&lt;/p&gt;
&lt;p&gt;Un exemple, qui peut servir de …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Encore ?! Oui... encore. Une nouvelle manière de gérer la construction d'un programme VG5000µ. Après la version &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-sublime-text-3.html"&gt;Sublime Text et z80asm&lt;/a&gt; en 2018, puis la version &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-visual-studio-code.html"&gt;Visual Studio Code et sjasmplus&lt;/a&gt; en 2020, je voulais essayer autre chose.&lt;/p&gt;
&lt;p&gt;J'avais laissé de côté Sublime Text et z80asm pour deux raisons : le changement de license de Sublime Text que je n'avais pas apprécié, et le côté très simpliste de z80asm, dont je touchais des limites.&lt;/p&gt;
&lt;p&gt;Pour un nouveau projet, je voulais utiliser &lt;a href="https://z88dk.org/"&gt;z88dk&lt;/a&gt;, un kit de développement pour machines Z80, avec du support C et ASM, ainsi que des bibliothèques standards. Je voulais aussi approfondir ma connaissance du support de toolchains avec CMake.&lt;/p&gt;
&lt;p&gt;Alors oui, &lt;code&gt;cmake&lt;/code&gt; pour un tout petit projet pour des machines des années 80, ça fait un peu surdimensionné... Je le concède. Et ça n'enlève en rien mon envie de fouiller de ce côté.&lt;/p&gt;
&lt;p&gt;Un exemple, qui peut servir de base, est disponibles sur &lt;a href="https://gitlab.com/mokona/vg5000-with-z88dk"&gt;GitLab&lt;/a&gt; et &lt;a href="https://github.com/Triceraprog/vg5000-with-z88dk"&gt;GitHub&lt;/a&gt;. Il y a quelques limitations quand à l'environnement supporté, car je n'ai testé que sur mon ordinateur de développement.&lt;/p&gt;
&lt;p&gt;Mais l'essentiel est là, et peut éviter des heures de recherches entre la documentation de CMake et StackOverflow, la première était connue pour son aridité et le second pour, en ce qui concerne CMake, ses 99% de réponses fausses, ou tout du moins obsolètes.&lt;/p&gt;
&lt;p&gt;Par la suite, je vais décrire les différents éléments qui forment le projet CMake.&lt;/p&gt;
&lt;h3&gt;CMakeLists.txt&lt;/h3&gt;
&lt;p&gt;Tout projet cmake a pour point d'entrée un fichier &lt;code&gt;CMakeLists.txt&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;cmake_minimum_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;3.20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout d'abord, on indique la version minimale de &lt;code&gt;cmake&lt;/code&gt; à utiliser. Il est toujours préférable de mettre celle sur laquelle on a validé le fonctionnement, car &lt;code&gt;cmake&lt;/code&gt; évolue souvent et tenter d'en mettre une plus ancienne est acrobatique.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;APPEND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;CMAKE_MODULE_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${CMAKE_CURRENT_SOURCE_DIR}/cmake/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Je vais avoir besoin d'ajouter des scripts de description de machine et de compilateur localement, car non reconnus nativement, du moins aujourd'hui, par &lt;code&gt;cmake&lt;/code&gt;. J'indique donc que certains scripts se trouvent dans le répertoire locale &lt;code&gt;cmake/&lt;/code&gt;, en modifiant la variable &lt;code&gt;CMAKE_MODULE_PATH&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;vg_tests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ASM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Je déclare ensuite le nom du projet &lt;code&gt;vg_tests&lt;/code&gt;, ainsi que les langages de programmation supportés.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# If need for cmake debug, the next line can help&lt;/span&gt;
&lt;span class="c"&gt;# set(CMAKE_VERBOSE_MAKEFILE 1)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Comme indiqué, mettre la variable &lt;code&gt;CMAKE_VERBOSE_MAKEFILE&lt;/code&gt; à 1 permet d'avoir des informations sur les actions qui sont faites lors de la génération du projet. Très pratique pour comprendre quelles sont les lignes de commandes générées, avec leurs options. Essentiel pour mettre au point quand on tâtonne.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;../output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La variable &lt;code&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/code&gt; indique où sont les artefacts de sortie. Dans notre cas, c'est là que se trouveront les &lt;code&gt;.k7&lt;/code&gt; utilisables pour le vg5000µ (ou les &lt;code&gt;.wav&lt;/code&gt;, si vous le désirez).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;SOURCE_FILES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;src/main.c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;src/auxiliary.asm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;SOURCE_FILES&lt;/code&gt; est une variable interne à ce script. C'est une habitude que de passer par une variable intermédiaire pour spécifier la liste des fichiers sources. Dans certains cas, on peut avoir besoin de la réutiliser.&lt;/p&gt;
&lt;p&gt;Ici, je vais compiler et assembler un fichier C et un fichier assembleur.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;add_executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SOURCE_FILES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PRIVATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-I&lt;/span&gt;&lt;span class="o"&gt;$ENV{&lt;/span&gt;&lt;span class="nv"&gt;Z88DK_HOME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Isrc/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-vn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_link_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PRIVATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-create-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-subtype=default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La déclaration de l'exécutable utilise la variable &lt;code&gt;PROJECT_NAME&lt;/code&gt;, qui prend le nom spécifié dans &lt;code&gt;project()&lt;/code&gt; au tout début, et y associe la liste des fichiers sources.&lt;/p&gt;
&lt;p&gt;Puis sont définies les options de compilations et les options pour l'éditeur de liens. La nature des options ne sont pas du domaine de cet article. Elles seront transmises à &lt;code&gt;zcc&lt;/code&gt;, qui est la commande générique pour toutes les opérations de construction dans &lt;code&gt;z88dk&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;# Fixes the k7 format for old z88dk versions.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;INPUT_FOR_FIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.k7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;ZERO_FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/zero-file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;OUTPUT_FOR_FIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.fix.k7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_custom_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;k7_fix&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;DEPENDS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;COMMAND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_COMMAND&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-E&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INPUT_FOR_FIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ZERO_FILE&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTPUT_FOR_FIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_custom_target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-fix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;DEPENDS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;k7_fix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La version actuelle de &lt;code&gt;z88dk&lt;/code&gt; a un bug au niveau de la génération des données du VG5000µ. Il manque des octets à la fin, qui sont attendues par la ROM pour valider la fin du fichier.&lt;/p&gt;
&lt;p&gt;J'ai soumis un fix, qui a été accepté, mais le temps que cela soit déployé partout, j'ajoute cette &lt;code&gt;custom_target&lt;/code&gt;, qui utilise une &lt;code&gt;custom_command&lt;/code&gt;. Le fichier &lt;code&gt;zero-file&lt;/code&gt; est le fichier nécessaire à l'ajustement, et ne contient que des &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Compilation croisée&lt;/h3&gt;
&lt;p&gt;Lancer &lt;code&gt;cmake&lt;/code&gt; tel quel ne va pas fonctionner, car par défaut, cela utilisera les outils de compilation de la machine hôte. Il faut donc spécifier une environnement de compilation croisée, c'est-à-dire les outils pour compiler pour une machine cible, et non la machine hôte.&lt;/p&gt;
&lt;p&gt;Pour cela, &lt;code&gt;cmake&lt;/code&gt; a un mécanisme de déclaration de compilation croisée. Lors de l'initialisation de &lt;code&gt;cmake&lt;/code&gt;, il faut spécifier la variable &lt;code&gt;CMAKE_TOOLCHAIN_FILE&lt;/code&gt;. Ici, &lt;code&gt;cmake -DCMAKE_TOOLCHAIN_FILE=z88dk-vg5000.cmake&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ici, on entre un peu dans le tâtonnement. Ce que j'expliquer fonctionne, mais est-ce que c'est carré ? C'est une bonne question.&lt;/p&gt;
&lt;p&gt;Voici l'explication du fichier &lt;code&gt;z88dk-vg5000.cmake&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;vg5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_SYSTEM_PROCESSOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Z80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_C_COMPILER_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;z88dk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_ASM_COMPILER_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;z88dk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En premier lieu, on fourni des valeurs à des variables internes de &lt;code&gt;cmake&lt;/code&gt; indiquant le nom du système, le processeur, et des identifiants du compilateur et de l'assembleur. Ces variables seront utilisées par &lt;code&gt;cmake&lt;/code&gt; pour déterminer quels fichiers de description il doit chercher.&lt;/p&gt;
&lt;p&gt;Il n'est pas toujours très clair de savoir quelle variable influe sur quoi. Il faut se fier aux messages d'erreurs lorsqu'un fichier n'est pas trouvé...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_TRY_COMPILE_TARGET_TYPE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;STATIC_LIBRARY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette variable indique à &lt;code&gt;cmake&lt;/code&gt; si, pour valider le fonctionnement de la chaîne de compilation, un essai se fera sur une bibliothèque ou sur un exécutable. L'exécutable, pour être validé, doit être lancé. Comme je ne définie pas de moyen de lancer l'exécutable, je demande à ne faire l'essai de compilation que sur une bibliothèque, ce qui est en fait le défaut lors d'une compilation croisée.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;TOOLCHAIN_PREFIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;z88dk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_C_COMPILER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOOLCHAIN_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.zcc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_ASM_COMPILER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOOLCHAIN_PREFIX&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.zcc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ici, j'indique le nom des compilateurs et assembleur. Pour &lt;code&gt;cmake&lt;/code&gt;, tout ce qui prend une source et sort un fichier objet est un &lt;code&gt;compiler&lt;/code&gt;. Pour &lt;code&gt;z88dk&lt;/code&gt;, je passe par le &lt;code&gt;frontend&lt;/code&gt; &lt;code&gt;zcc&lt;/code&gt; plutôt que les exécutable eux-mêmes, ce qui semble être préféré dans la documentation (et dans la façon dont est construit le paquetage).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_DEPENDS_USE_COMPILER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;J'indique aussi à &lt;code&gt;cmake&lt;/code&gt; d'utiliser le compilateur pour trouver les dépendances entre les fichiers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_C_COMPILE_OBJECT&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;CMAKE_C_COMPILER&amp;gt; +vg5k &amp;lt;DEFINES&amp;gt; &amp;lt;INCLUDES&amp;gt; &amp;lt;FLAGS&amp;gt; -o &amp;lt;OBJECT&amp;gt; -c &amp;lt;SOURCE&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_C_LINK_EXECUTABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;CMAKE_C_COMPILER&amp;gt; +vg5k &amp;lt;FLAGS&amp;gt; &amp;lt;OBJECTS&amp;gt; -o &amp;lt;TARGET&amp;gt; &amp;lt;CMAKE_C_LINK_FLAGS&amp;gt; &amp;lt;LINK_FLAGS&amp;gt; &amp;lt;LINK_LIBRARIES&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_ASM_COMPILE_OBJECT&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;CMAKE_C_COMPILER&amp;gt; +vg5k &amp;lt;DEFINES&amp;gt; &amp;lt;INCLUDES&amp;gt; &amp;lt;FLAGS&amp;gt; -o &amp;lt;OBJECT&amp;gt; -c &amp;lt;SOURCE&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On y est presque. Dans un cas classique où le compilateur se comporte de manière classique (disons comme un &lt;code&gt;gcc&lt;/code&gt;, un &lt;code&gt;clang&lt;/code&gt; ou autre), on pourrait se passer de ces lignes. Mais &lt;code&gt;zcc&lt;/code&gt; à besoin comme premier paramètre de la plateforme cible (&lt;code&gt;+vg5k&lt;/code&gt; ici).&lt;/p&gt;
&lt;p&gt;J'indique donc à &lt;code&gt;cmake&lt;/code&gt; comment générer la ligne de commande pour les fichiers &lt;code&gt;C&lt;/code&gt; et &lt;code&gt;ASM&lt;/code&gt;, avec une syntaxe de template.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_FIND_ROOT_PATH_MODE_PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;NEVER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_FIND_ROOT_PATH_MODE_LIBRARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;NEVER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_FIND_ROOT_PATH_MODE_INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;NEVER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et enfin, je demande à &lt;code&gt;cmake&lt;/code&gt; de ne pas chercher à résoudre les commandes &lt;code&gt;find_library&lt;/code&gt;, que je n'utiliserai pas.&lt;/p&gt;
&lt;h3&gt;Et ce n'est pas fini !&lt;/h3&gt;
&lt;p&gt;Le fichier de compilation croisée indique que l'on compile pour &lt;strong&gt;VG5000µ&lt;/strong&gt;. Mais &lt;code&gt;cmake&lt;/code&gt; ne connait pas cette plateforme, et va donc chercher un script qui lui en dirait plus.&lt;/p&gt;
&lt;p&gt;Ce que j'ai fait n'est probablement pas entièrement correct, car j'associe la plateforme avec la chaîne de compilation. Et je fais ça dans le fichier &lt;code&gt;cmake/Platform/vg5000.cmake&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PROPERTY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;TARGET_SUPPORTS_SHARED_LIBS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;z88dk&lt;/code&gt; ne supporte pas un systmème de bibliothèque dynamiques (style &lt;code&gt;DLL&lt;/code&gt;, &lt;code&gt;so&lt;/code&gt; ou &lt;code&gt;dynlib&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_C_OUTPUT_EXTENSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;.o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;z88dk&lt;/code&gt; ne reconnaît que l'extension &lt;code&gt;.o&lt;/code&gt; comme fichiers objets. On indique donc à &lt;code&gt;cmake&lt;/code&gt; de produire des fichiers objets avec cette extension.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_SYSTEM_INCLUDE_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$ENV{&lt;/span&gt;&lt;span class="nv"&gt;Z88DK_HOME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/include&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_SYSTEM_LIBRARY_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$ENV{&lt;/span&gt;&lt;span class="nv"&gt;Z88DK_HOME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_SYSTEM_PROGRAM_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$ENV{&lt;/span&gt;&lt;span class="nv"&gt;Z88DK_HOME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/bin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ces variables ont l'air d'être les pendants des &lt;code&gt;CMAKE_FIND_ROOT_PATH_MODE_*&lt;/code&gt; indiqués dans le fichier de compilation croisée. Le fonctionnement n'est pas hyper clair.&lt;/p&gt;
&lt;p&gt;Voilà, à présent &lt;code&gt;cmake&lt;/code&gt; sait compiler un fichier &lt;code&gt;C&lt;/code&gt; avec &lt;code&gt;z88dk&lt;/code&gt; pour &lt;strong&gt;VG5000µ&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Et l'assembleur ?&lt;/h3&gt;
&lt;p&gt;Pour une raison que je n'ai pas creusé, mais probablement concernant la séparation des plateformes des compilateurs, le support d'un assembleur nécessite un autre fichier, différent du précédent &lt;code&gt;vg5000.cmake&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;C'est dans &lt;code&gt;cmake/Compiler/z88dk-ASM.cmake&lt;/code&gt; que &lt;code&gt;cmake&lt;/code&gt; va chercher l'outil pour traiter l'&lt;code&gt;ASM&lt;/code&gt; pour &lt;code&gt;z88dk&lt;/code&gt;. Ce qui se tient. Pourquoi est-ce qu'il ne va pas chercher &lt;code&gt;z88dk-C.cmake&lt;/code&gt; au même endroit, cela m'échappe...&lt;/p&gt;
&lt;p&gt;Le contenu est strictement identique à celui du fichier &lt;code&gt;vg5000.cmake&lt;/code&gt;, puisque l'on s'adresse au même outil &lt;code&gt;zcc&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Et la cerise optionnelle&lt;/h3&gt;
&lt;p&gt;Le fichier &lt;code&gt;z88dk-clion.yaml&lt;/code&gt; est un fichier qui ajoute un support de &lt;code&gt;z88dk&lt;/code&gt; (assez succin) à &lt;code&gt;Clion&lt;/code&gt;. Par défaut, lors de la génération de &lt;code&gt;cmake&lt;/code&gt;, l'IDE va essayer de trouver un certain nombre d'information en interrogeant le compilateur. Les &lt;code&gt;#define&lt;/code&gt; par exemple, ou les répertoires d'inclusion par défaut.&lt;/p&gt;
&lt;p&gt;Mais &lt;code&gt;zcc&lt;/code&gt; ne réagissant par bien à la question, Clion affiche un warning. Il est cependant possible de lui indiquer manuellement les informations recherchées, et c'est le but de ce fichier. Cependant, sa description tombe hors du sujet de cet article.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Ça a été une aventure, comme à chaque fois que l'on sort des sentiers battus avec &lt;code&gt;cmake&lt;/code&gt;. J'y ai appris un peu plus de choses, ce qui était probablement l'objectif initial. Et j'ai une façon de générer un programme &lt;strong&gt;VG5000µ&lt;/strong&gt; à partir de tout outil qui utilise &lt;code&gt;cmake&lt;/code&gt;, ce qui couvre aussi Visual Studio Code.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="C"></category><category term="Outils"></category><category term="Clion"></category><category term="z88dk"></category><category term="cmake"></category></entry><entry><title>Apprendre l'assembleur... mais comment ?</title><link href="https://www.triceraprog.fr/apprendre-lassembleur-mais-comment.html" rel="alternate"></link><published>2022-03-05T00:00:00+01:00</published><updated>2022-03-05T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2022-03-05:/apprendre-lassembleur-mais-comment.html</id><summary type="html">&lt;p&gt;Il y a peu, j'ai eu une discussion à propos de l'apprentissage de l'assembleur. La discussion était partie de l'envie d'une personne de créer un jeu sur MSX, mais directement au niveau de la machine, plutôt que de passer par un langage de haut niveau, comme le BASIC natif. Et pourquoi pas. Une donnée importante : la personne en question connaît déjà la programmation, c'est donc un abord de nouveau langage dont on parle, et non des concepts généraux du développement d'un programme.&lt;/p&gt;
&lt;p&gt;Lorsque l'on aborde un langage de plus haut niveau, que ce soit BASIC ou Pascal, on va se concentrer sur la manière d'exprimer des concepts dans ce langage en particulier. Lorsque l'on connaît déjà un autre langage de même famille (large), il s'agit même souvent de comprendre quelle sont les particularité du langage appris.&lt;/p&gt;
&lt;p&gt;Lorsque l'on aborde une machine en particulier dans un langage de haut niveau, il …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Il y a peu, j'ai eu une discussion à propos de l'apprentissage de l'assembleur. La discussion était partie de l'envie d'une personne de créer un jeu sur MSX, mais directement au niveau de la machine, plutôt que de passer par un langage de haut niveau, comme le BASIC natif. Et pourquoi pas. Une donnée importante : la personne en question connaît déjà la programmation, c'est donc un abord de nouveau langage dont on parle, et non des concepts généraux du développement d'un programme.&lt;/p&gt;
&lt;p&gt;Lorsque l'on aborde un langage de plus haut niveau, que ce soit BASIC ou Pascal, on va se concentrer sur la manière d'exprimer des concepts dans ce langage en particulier. Lorsque l'on connaît déjà un autre langage de même famille (large), il s'agit même souvent de comprendre quelle sont les particularité du langage appris.&lt;/p&gt;
&lt;p&gt;Lorsque l'on aborde une machine en particulier dans un langage de haut niveau, il s'agit en suite de connaître les bons appels, les bonnes fonctions, particulières à cette machine.&lt;/p&gt;
&lt;p&gt;Mais comment démarrer en assembleur ? Avec l'assembleur, toute la couche d'abstraction est retirée, il n'y a plus de concept de variables, de fonctions, de structures de données, on se retrouve face à face à la machine. Cela implique en premier lieu qu'apprendre l'assembleur, c'est apprendre le fonctionnement particulier de cette machine, et même pas seulement du fonctionnement du processeur.&lt;/p&gt;
&lt;p&gt;Quand on regarde les ressources qui enseignent l'assembleur, que ce soit pour une machine ou seulement un processeur, on se retrouve avec une structure assez similaire où il est d'abord expliqué l'arithmétique et la logique binaire, la représentation des entiers, puis sont abordés les registres et globalement l'architecture du processeur. Ce sont des dizaines de pages à comprendre, suivre... et la plupart du temps sans exercice pratique, sans mise en application. Cela semble sous-entendre que pour démarrer la moindre opération, il faut lire une centaine de pages.&lt;/p&gt;
&lt;p&gt;Lorsque l'on a déjà des connaissances sur d'autres machines et processeurs similaire, cela peut aller vite. Mais lorsque c'est le premier abord du mode du bas niveau, c'est beaucoup à ingurgiter et probablement très démotivant.&lt;/p&gt;
&lt;p&gt;Je me suis posé la question de comment pourrait être abordé la question, j'ai pris quelques notes et je vais m'essayer à l'exercice dans des articles qui suivront. Mon objectif est de pouvoir construire de la connaissance sur la programmation en assembleur pour des personnages qui n'en n'auraient jamais fait.&lt;/p&gt;
&lt;p&gt;Voyons ce que cela donne...&lt;/p&gt;</content><category term="Langages"></category><category term="ASM"></category><category term="Programmation"></category></entry><entry><title>Baisse de régime... en apparence.</title><link href="https://www.triceraprog.fr/baisse-de-regime-en-apparence.html" rel="alternate"></link><published>2022-03-04T00:00:00+01:00</published><updated>2022-03-04T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2022-03-04:/baisse-de-regime-en-apparence.html</id><summary type="html">&lt;p&gt;Après une grosse activité sur le VG5000µ principalement, il y a eu bien moins d'article sur Triceraprog, et la troisième vidéo sur les langages de programmation qui est prévue depuis deux ans n'est toujours pas là. Mais que se passe-t-il ?&lt;/p&gt;
&lt;p&gt;En Janvier 2021, l'association &lt;a href="https://www.mo5.com"&gt;M05.COM&lt;/a&gt; m'a proposé de travailler sur &lt;a href="https://micral.mo5.com/"&gt;le projet de restauration et de documentation d'un « Micral N »&lt;/a&gt;. Toute l'année 2021, avec d'autres membres de l'association, nous nous sommes plongé dans la compréhension de cette machine historique, ainsi que dans la création d'une version virtuelle qui a permis d'en comprendre les détails.&lt;/p&gt;
&lt;p&gt;C'est une activité passionnante, j'ai appris énormément de choses et j'ai même pu écrire (ou porter) une poignée de logiciels pour cette machine. Forcément, mes autres sujets en ont pâti et le VG5000µ est un peu en pause. Mais il est toujours sur mon bureau prêt à reprendre du service.&lt;/p&gt;
&lt;p&gt;La communication des avancées sur …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Après une grosse activité sur le VG5000µ principalement, il y a eu bien moins d'article sur Triceraprog, et la troisième vidéo sur les langages de programmation qui est prévue depuis deux ans n'est toujours pas là. Mais que se passe-t-il ?&lt;/p&gt;
&lt;p&gt;En Janvier 2021, l'association &lt;a href="https://www.mo5.com"&gt;M05.COM&lt;/a&gt; m'a proposé de travailler sur &lt;a href="https://micral.mo5.com/"&gt;le projet de restauration et de documentation d'un « Micral N »&lt;/a&gt;. Toute l'année 2021, avec d'autres membres de l'association, nous nous sommes plongé dans la compréhension de cette machine historique, ainsi que dans la création d'une version virtuelle qui a permis d'en comprendre les détails.&lt;/p&gt;
&lt;p&gt;C'est une activité passionnante, j'ai appris énormément de choses et j'ai même pu écrire (ou porter) une poignée de logiciels pour cette machine. Forcément, mes autres sujets en ont pâti et le VG5000µ est un peu en pause. Mais il est toujours sur mon bureau prêt à reprendre du service.&lt;/p&gt;
&lt;p&gt;La communication des avancées sur le « Micral N » ayant besoin d'être coordonnée avec l'association, je ne parle pas des avancées sur Triceraprog. En tout cas pas pour le moment, à part la &lt;a href="https://www.triceraprog.fr/breve-presentation-de-lintel-8008.html"&gt;petite présentation du 8008&lt;/a&gt; que j'ai écrite il y a quelques mois.&lt;/p&gt;
&lt;p&gt;Un live Twitch est visible où nous présentons la machine. Malheureusement un peu gâché par des problèmes de micros.&lt;/p&gt;
&lt;p&gt;J'ai hâte de pouvoir parler de cette machine plus en détails.&lt;/p&gt;
&lt;div class="embed-yt text-center" data-video-id="BE7X611r_Uk" style="width: 560; height:315"&gt;
    &lt;div class="embed-yt-play"&gt;&lt;/div&gt;
&lt;/div&gt;</content><category term="Divers"></category><category term="Divers"></category><category term="Micral"></category></entry><entry><title>Récréation 3D, Apple II</title><link href="https://www.triceraprog.fr/recreation-3d-apple-ii.html" rel="alternate"></link><published>2021-12-15T00:00:00+01:00</published><updated>2021-12-15T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-12-15:/recreation-3d-apple-ii.html</id><content type="html">&lt;p&gt;L'un des tout premiers micro ordinateurs de très grande popularité, particulièrement aux États-Unis. L'Apple II.&lt;/p&gt;
&lt;p&gt;Voici une recréation en synthèse, avec un moniteur ambre posé lui-même sur une paire de lecteurs Disk II.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Apple II" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202112/20211216-Apple-II-Render-750.jpeg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Apple"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>Récréation 3D, CDC 6400</title><link href="https://www.triceraprog.fr/recreation-3d-cdc-6400.html" rel="alternate"></link><published>2021-11-18T00:00:00+01:00</published><updated>2021-11-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-11-18:/recreation-3d-cdc-6400.html</id><content type="html">&lt;p&gt;Le langage Pascal, nommé ainsi en référence à Blaise Pascal, concepteur de la &lt;a href="https://www.triceraprog.fr/recreation-3d-pascaline.html"&gt;Pascaline&lt;/a&gt;, a été développé sur une machine nommée CDC 6400. C'est une machine de type &lt;em&gt;mainframe&lt;/em&gt;, un gros truc, même si la version 6400 est une version allégée d'une autre de la gamme, et dont l'unité de mémoire adressée a une largeur de 60 bits.&lt;/p&gt;
&lt;p&gt;Voici une recréation en synthèse, où l'on voit en premier lieu la console avec ses deux écrans ronds, hérités des écrans de RADARs. Les calculs sont fait dans les grosses armoires que je n'ai pas détaillées.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CDC6400" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202111/20211117-Rendu-002-750.jpeg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="CDC"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>Brève présentation de l'Intel 8008</title><link href="https://www.triceraprog.fr/breve-presentation-de-lintel-8008.html" rel="alternate"></link><published>2021-11-01T00:00:00+01:00</published><updated>2021-11-01T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-11-01:/breve-presentation-de-lintel-8008.html</id><summary type="html">&lt;p&gt;Le 8008 d'Intel est un processeur assez particulier. C'est le premier micro-processeur 8 bits, et on peut même dire : le premier micro-processeur tout court. Son grand frère, le 4004, étant plutôt considéré comme un micro-contrôleur. D'autres sites expliquent le pourquoi de cette distinction.&lt;/p&gt;
&lt;p&gt;Je veux ici me pencher sur le 8008 sous certains aspects techniques. Une brève introduction d'une puce qui va en générer d'autres (8080, 8086, Z80,...)&lt;/p&gt;
&lt;p&gt;Cette puce, je l'ai étudiée à travers son utilisation dans le Micral N de la R2E, mais ceci est une autre histoire. Le 8008 est rapidement utilisé dans une série de micro-ordinateurs (le terme apparaît avec le Micral N) sur un cours laps de temps. Dans le désordre, MCM/70, SCELBI, Intellec-8, Mark-8, MCS 8, Bill-1,... Certaines de ces machines reçoivent très rapidement une mise à jour vers le 8080, beaucoup plus flexible. Cependant, c'est bien avec le 8008 que cela commence …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Le 8008 d'Intel est un processeur assez particulier. C'est le premier micro-processeur 8 bits, et on peut même dire : le premier micro-processeur tout court. Son grand frère, le 4004, étant plutôt considéré comme un micro-contrôleur. D'autres sites expliquent le pourquoi de cette distinction.&lt;/p&gt;
&lt;p&gt;Je veux ici me pencher sur le 8008 sous certains aspects techniques. Une brève introduction d'une puce qui va en générer d'autres (8080, 8086, Z80,...)&lt;/p&gt;
&lt;p&gt;Cette puce, je l'ai étudiée à travers son utilisation dans le Micral N de la R2E, mais ceci est une autre histoire. Le 8008 est rapidement utilisé dans une série de micro-ordinateurs (le terme apparaît avec le Micral N) sur un cours laps de temps. Dans le désordre, MCM/70, SCELBI, Intellec-8, Mark-8, MCS 8, Bill-1,... Certaines de ces machines reçoivent très rapidement une mise à jour vers le 8080, beaucoup plus flexible. Cependant, c'est bien avec le 8008 que cela commence.&lt;/p&gt;
&lt;h2&gt;La puce&lt;/h2&gt;
&lt;p&gt;Et le voici en image de synthèse. Ou du moins, dans l'un des boîtiers existant, car il en existe plusieurs. C'est celui que j'avais en référence, et c'est donc celui que j'ai modélisé.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image de synthèse d'un 8008 avec brochage." src="https://www.triceraprog.fr/images/202108/Intel-8008-750.png"&gt;&lt;/p&gt;
&lt;p&gt;Une première chose étonnante : pas de masse. Le 8008 prend du +5V et du -9V. Il semble que la raison soit une volonté d'être compatible avec des circuits électroniques 5V, mais avec un besoin d'une tension totale de 14V... Ce n'est pas trop mon rayon, alors je laisse ça en note. Pour plus de précisions, jusqu'au niveau transistor, je vous dirige vers l'&lt;a href="http://www.righto.com/2016/12/die-photos-and-analysis-of_24.html"&gt;analyse en anglais&lt;/a&gt; de Ken Shirriff.&lt;/p&gt;
&lt;h2&gt;Branchements&lt;/h2&gt;
&lt;p&gt;Mis à part VCC et VDD, les deux tensions nécessaires, le 8008 communique avec l'extérieur à travers 16 autres broches.&lt;/p&gt;
&lt;p&gt;À noter que le 8008 travaille en « logique physique inversée » par rapport aux signaux logiques : le 0 logique est à +5V, le 1 logique est entre ~0.8V et -9V.&lt;/p&gt;
&lt;h3&gt;Broche de synchronisation&lt;/h3&gt;
&lt;p&gt;En entrée, le 8008 reçoit en entrée deux horloges déphasées, de même fréquence (500 kHz) : Ø1 et Ø2. Ces deux horloges lui permettent de cadencer les opérations internes.&lt;/p&gt;
&lt;p&gt;À partir de ces impulsions, le 8008 forme en sortie le signal &lt;code&gt;SYNC/&lt;/code&gt; qui est haut pendant un premier cycle Ø1, Ø2, puis bas pendant un second cycle Ø1, Ø2. Le tout forme un état processeur complet.&lt;/p&gt;
&lt;p&gt;Vu qu'il y a un temps de 2µs entre deux fronts de Ø1, cela signifie qu'un état du 8008 dure 4µs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chronogramme des horloges et de la synchro du 8008." src="https://www.triceraprog.fr/images/202111/8008-clock-sync.png"&gt;&lt;/p&gt;
&lt;h3&gt;Broches d'états&lt;/h3&gt;
&lt;p&gt;Trois autres broches en sortie : &lt;code&gt;S1&lt;/code&gt;, &lt;code&gt;S2&lt;/code&gt; et &lt;code&gt;S3&lt;/code&gt;, forment un triplet indiquant dans quel état le processeur se trouve.&lt;/p&gt;
&lt;p&gt;Les états sont les suivants : &lt;code&gt;T1&lt;/code&gt; et &lt;code&gt;T1I&lt;/code&gt;, &lt;code&gt;T2&lt;/code&gt;, &lt;code&gt;T3&lt;/code&gt;, &lt;code&gt;T4&lt;/code&gt;, &lt;code&gt;T5&lt;/code&gt;, &lt;code&gt;WAIT&lt;/code&gt; et &lt;code&gt;STOPPED&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les états &lt;code&gt;T1&lt;/code&gt; et &lt;code&gt;T2&lt;/code&gt; forment ensemble une demande d'information au reste du système. Lors de T1, le 8008 place la partie basse de l'adresse de l'information à obtenir sur les broches d'entrées/sorties. Lors de T2 y est placée la partie haute de l'adresse, ainsi que deux bits indiquant le type de cycle actuel et donc la nature de la donnée attendue : est-ce une instruction, une lecture ou une écriture de donnée en mémoire, ou une opération d'entrée/sortie ?&lt;/p&gt;
&lt;p&gt;Cette manière de placer une adresse sur le bus se fera toujours de la même manière lors de différents cycles d'une instruction, et toujours sur les états T1 et T2 : d'abord les 8 bits bas de l'adresse, puis les 6 bits haut (le 8008 a un espace d'adressage de 14 bits), complétés par 2 bits indiquant au système ce que ce couple d'information représente.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;T1I&lt;/code&gt; est une variante de T1 qui est utilisée lorsque le processeur a validé une interruption. L'état est le même que T1 à l'exception du traitement du compteur d'instruction (le registre interne PC), qui n'est pas avancé. Après T1I, le 8008 passera à un état T2.&lt;/p&gt;
&lt;p&gt;Lors de l'état &lt;code&gt;T3&lt;/code&gt;, le processeur lit la donnée obtenue. Si c'est une instruction à exécuter, celle-ci est stockée pour les états suivants, sauf pour l'instruction &lt;code&gt;HLT&lt;/code&gt;, qui est immédiate.&lt;/p&gt;
&lt;p&gt;Les états &lt;code&gt;T4&lt;/code&gt; et &lt;code&gt;T5&lt;/code&gt; sont des états supplémentaires qui existent dans certaines instructions.&lt;/p&gt;
&lt;p&gt;Et chaque instruction peut répéter l'ensemble de ces états dans l'ordre pour compléter son exécution. L'instruction &lt;code&gt;INr&lt;/code&gt; (incrément d'un registre) va s'exécuter en un seul cycle avec les états T1, T2, T3, T4 et T5, pour un total de 5 états. L'instruction &lt;code&gt;JMP&lt;/code&gt; (branchement à une adresse absolue) aura besoin de trois cycles : le premier et le second avec T1, T2 et T3, le troisième avec T1, T2, T3, T4 et T5, pour un total de 11 états.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chronogramme des horloges et de la synchro du 8008." src="https://www.triceraprog.fr/images/202111/8008-Instruction-States.png"&gt;&lt;/p&gt;
&lt;h3&gt;Broches d'entrée&lt;/h3&gt;
&lt;p&gt;Le 8008 possède deux broches en entrée en plus des deux phases d'horloges : &lt;code&gt;INTERRUPT/&lt;/code&gt; et &lt;code&gt;READY/&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;READY/&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;La broche READY/ permet de synchroniser le temps que prend l'acquisition d'une donnée avec le 8008. En effet, le cycle T3 s'attend à pouvoir lire une donnée sur les broches d'entrées/sorties. L'emplacement de cette donnée a été complètement caractérisée (emplacement et nature) lors du cycle T2.&lt;/p&gt;
&lt;p&gt;Pour être certain que le monde extérieur est prêt, le 8008 ne passera de l'état T2 à T3 que si READY/ est au 1 logique. Dans le cas contraire, il se placera dans l'état WAIT et patientera... Dès que READY/ est signalé par le reste du système, le 8008 reprend sa course en passant vers l'état T3.&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;INTERRUPT/&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;La broche INTERRUPT/, comme son nom l'indique, place le 8008 dans un état d'interruption. La gestion des interruptions par le 8008 est très rudimentaire. Lorsqu'une instruction est terminée, si INTERRUPT/ est signalée, alors le processeur passe en état T1I plutôt que T1.&lt;/p&gt;
&lt;p&gt;Et c'est tout !&lt;/p&gt;
&lt;p&gt;C'est aussi le seul moyen pour le processeur de sortir de l'état STOPPED si une instruction &lt;code&gt;HLT&lt;/code&gt; (halt) a été exécutée. Et de la même manière, le premier état sera alors T1I.&lt;/p&gt;
&lt;p&gt;Comme indiquée plus haut, la différence entre l'état T1 et T1I est que pour T1, le registre PC est incrémenté après l'émission de l'adresse. Pas dans le cas de T1I. L'idée est pour le système de placer sur le bus lors d'un état T1I une instruction particulière, généralement &lt;code&gt;RST&lt;/code&gt; (Restart).&lt;/p&gt;
&lt;p&gt;L'instruction &lt;code&gt;RST&lt;/code&gt; est une instruction d'un octet de taille qui permet de brancher sur une sous-routine (comme un &lt;code&gt;CAL&lt;/code&gt;) à une des 8 adresses multiples de 8 en mémoire. Elle est faite pour être utilisée dans ce contexte.&lt;/p&gt;
&lt;p&gt;Le 8008 doit donc être aidé par le reste du système pour gérer des interruptions. Le processeur lui-même ne fait que le strict minimum... &lt;/p&gt;
&lt;h3&gt;Les broches d'entrées/sorties&lt;/h3&gt;
&lt;p&gt;Il reste 8 broches à décrire, et celles-ci fonctionnent en entrée comme en sortie. Elles forment l'interface d'échange de données entre le 8008 et le reste du système. Ces broches ne sont pas spécialisées : toute donnée passe par là, que ce soit un morceau d'adresse, une données à échanger avec la mémoire ou avec un périphérique.&lt;/p&gt;
&lt;p&gt;Comme indiqué plus haut, une combinaison de l'état courant du 8008 et des deux bits hauts placés en T2 sur ces broches permet de déterminer la fonction de ces 8 broches.&lt;/p&gt;
&lt;p&gt;Sur T1 et T2, ce sont des broches en sortie qui indiquent deux morceaux d'adresse ainsi que la nature du cycle. Sauf dans le cas d'une données adressée à un périphérique, qui se trouvera en cycle T1 du second cycle.&lt;/p&gt;
&lt;p&gt;En T3, ce sont des broches en entrée qui vont y lire une donnée... ou rien (dans le cas de &lt;code&gt;OUT&lt;/code&gt; lors du second cycle).&lt;/p&gt;
&lt;p&gt;Les broches ne servent pas lors des autres états.&lt;/p&gt;
&lt;h3&gt;Les registres&lt;/h3&gt;
&lt;p&gt;Le 8008 possède des registres accessibles par le code utilisateur, ainsi que quelques registres internes, non accessibles.&lt;/p&gt;
&lt;p&gt;Passons sur la plupart des registres internes, qui servent au fonctionnement... interne (deux registres temporaires, celui d'instruction, de cycle,...) mais arrêtons nous sur une particularité : le pointeur d'instruction, généralement nommé &lt;code&gt;PC&lt;/code&gt; sur les micro-processeurs, n'est pas accessible au code exécuté !&lt;/p&gt;
&lt;h3&gt;Le PC&lt;/h3&gt;
&lt;p&gt;En premier lieu, il faut dire que ce registre n'existe pas vraiment. Le 8008 possède une mémoire de 8 x 14 bits organisée en pile, munie de son pointeur de pile. L'adresse pointée est le &lt;code&gt;PC&lt;/code&gt; actuel. Lors d'un branchement, l'adresse pointée est mise à jour, avec une mise à jour potentielle du pointeur dans le cas d'instruction d'appel de sous-routine (&lt;code&gt;CAL&lt;/code&gt; par exemple).&lt;/p&gt;
&lt;p&gt;Cela signifie au passage que le 8008, sans aide externe et avec ses seules instructions, ne peut pas dépasser une profondeur d'appel de plus de 8. Ou plutôt, il peut, mais la mémoire étant cyclique, il ne pourra pas &lt;em&gt;remonter&lt;/em&gt; correctement.&lt;/p&gt;
&lt;p&gt;Et le contenu de cette mémoire est parfaitement inaccessible. Il n'y a pas d'instruction permettant de lire le contenu de la pile, ni le niveau du pointeur.&lt;/p&gt;
&lt;h3&gt;Les autres registres&lt;/h3&gt;
&lt;p&gt;Les registres accessibles sont &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;D&lt;/code&gt;, &lt;code&gt;E&lt;/code&gt;, &lt;code&gt;H&lt;/code&gt; et &lt;code&gt;L&lt;/code&gt;. Rien de très étonnant si vous connaissez le &lt;strong&gt;Z80&lt;/strong&gt; par exemple.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;A&lt;/code&gt; est l'accumulateur. Toutes les opérations logiques et arithmétiques se font par rapport à A, et le résultat potentiel est stocké dans A. Sauf pour les opérations d'incréments et décréments, qui ne peuvent être appliqués que sur les registres généraux qui suivent.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;B&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;D&lt;/code&gt; et &lt;code&gt;E&lt;/code&gt; sont 4 registres généraux. On peut copier le contenu de n'importe lequel vers n'importe quel autre (y compris l'accumulateur). On peut même copier le contenu d'un registre vers lui-même. Et c'est d'ailleurs, par convention, la copie de A vers A (&lt;code&gt;LAA&lt;/code&gt;) qui forme l'instruction &lt;code&gt;NOP&lt;/code&gt; du 8008.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;H&lt;/code&gt; et &lt;code&gt;L&lt;/code&gt; sont 2 autres registres généraux qui se comportent comme les précédents, mais qui ont une capacité supplémentaire. Pris ensemble, ils forme &lt;code&gt;HL&lt;/code&gt;, nommé aussi &lt;code&gt;M&lt;/code&gt;, un pseudo registre de pointeur vers la mémoire.&lt;/p&gt;
&lt;p&gt;Ainsi, l'instruction &lt;code&gt;LAM&lt;/code&gt; copie le contenu du pseudo registre &lt;code&gt;M&lt;/code&gt; vers l'accumulateur. Autrement dit, l'octet pointé par la paire &lt;code&gt;HL&lt;/code&gt; est chargée dans A.&lt;/p&gt;
&lt;h2&gt;Mot de la fin.&lt;/h2&gt;
&lt;p&gt;Le 8008, conçu et construit par Intel, est avant tout une commande pour reproduire dans un petit volume les fonctionnalités d'un appareil existant. C'est sous cet aspect qu'il est à comprendre et comprendre une partie des choix techniques et donc de ses limitations. &lt;/p&gt;</content><category term="Machines"></category><category term="i8008"></category><category term="CPU"></category></entry><entry><title>Récréation 3D, Pascaline</title><link href="https://www.triceraprog.fr/recreation-3d-pascaline.html" rel="alternate"></link><published>2021-10-19T00:00:00+02:00</published><updated>2021-10-19T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-10-19:/recreation-3d-pascaline.html</id><content type="html">&lt;p&gt;Depuis longtemps, très longtemps, les humains cherchent des moyens pour aider aux calculs. Blaise Pascal fut de ceux-ci, lorsqu'il conçu un modèle fonctionnel d'une machine mécanique permettant d'additionner et de soustraire des nombres.&lt;/p&gt;
&lt;p&gt;La Pascaline devient la première machine à calculer de bureau commercialisée (même si elle le fut à très peu d'exemplaires).&lt;/p&gt;
&lt;p&gt;En voici une modélisation que j'ai terminée récemment.&lt;/p&gt;
&lt;p&gt;&lt;img alt="une Pascaline" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202110/Render-Pascaline-002-750-sepia.jpeg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Pascaline"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>VG5000µ, Schémas de principe mis à jour en v1.4</title><link href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v14.html" rel="alternate"></link><published>2021-04-29T00:00:00+02:00</published><updated>2021-04-29T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-04-29:/vg5000m-schemas-de-principe-mis-a-jour-en-v14.html</id><summary type="html">&lt;p&gt;Il y a deux ans et demi, &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe.html"&gt;je publiais ici&lt;/a&gt; une remise au propre du &lt;strong&gt;schéma de principe&lt;/strong&gt; de la documentation du VG5000µ.&lt;/p&gt;
&lt;p&gt;Cette première version a été mise à jour avec la découvertes d'erreurs, ou de précisions à apporter.&lt;/p&gt;
&lt;p&gt;Cette fois-ci, c'est l'œil exercé de &lt;em&gt;6502man&lt;/em&gt; du forum &lt;strong&gt;system-cfg&lt;/strong&gt; qui, lors de la réparation d'un VG5000µ, m'a fait parvenir des corrections. Et je le remercie ici à nouveau.&lt;/p&gt;
&lt;p&gt;Les modifications par rapport à la v1.3 sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;retirer la broche &lt;code&gt;A14&lt;/code&gt; de la ROM &lt;code&gt;7802&lt;/code&gt; et les broches &lt;code&gt;A13&lt;/code&gt; des deux RAM en accès direct par le Z80, &lt;code&gt;7804&lt;/code&gt; et &lt;code&gt;7805&lt;/code&gt;. Du copier coller raté très probablement.&lt;/li&gt;
&lt;li&gt;correction d'un inversion des broches 26 et 28 sur la ROM &lt;code&gt;7802&lt;/code&gt;. Le +5V arrive sur 28.&lt;/li&gt;
&lt;li&gt;inversion des broches 4 et 5 de la porte NAND fournie par &lt;code&gt;7812&lt;/code&gt;. Les broches indiquées sur les versions précédentes sont fidèles au schéma de …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Il y a deux ans et demi, &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe.html"&gt;je publiais ici&lt;/a&gt; une remise au propre du &lt;strong&gt;schéma de principe&lt;/strong&gt; de la documentation du VG5000µ.&lt;/p&gt;
&lt;p&gt;Cette première version a été mise à jour avec la découvertes d'erreurs, ou de précisions à apporter.&lt;/p&gt;
&lt;p&gt;Cette fois-ci, c'est l'œil exercé de &lt;em&gt;6502man&lt;/em&gt; du forum &lt;strong&gt;system-cfg&lt;/strong&gt; qui, lors de la réparation d'un VG5000µ, m'a fait parvenir des corrections. Et je le remercie ici à nouveau.&lt;/p&gt;
&lt;p&gt;Les modifications par rapport à la v1.3 sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;retirer la broche &lt;code&gt;A14&lt;/code&gt; de la ROM &lt;code&gt;7802&lt;/code&gt; et les broches &lt;code&gt;A13&lt;/code&gt; des deux RAM en accès direct par le Z80, &lt;code&gt;7804&lt;/code&gt; et &lt;code&gt;7805&lt;/code&gt;. Du copier coller raté très probablement.&lt;/li&gt;
&lt;li&gt;correction d'un inversion des broches 26 et 28 sur la ROM &lt;code&gt;7802&lt;/code&gt;. Le +5V arrive sur 28.&lt;/li&gt;
&lt;li&gt;inversion des broches 4 et 5 de la porte NAND fournie par &lt;code&gt;7812&lt;/code&gt;. Les broches indiquées sur les versions précédentes sont fidèles au schéma de la documentation, mais le relevé sur le matériel montre le contraire. Il est possible qu'il existe différente carte mère, mais je donne la priorité à un relevé vérifié. D'un point de vue logique, inverser les branches d'une porte NAND ne change rien.&lt;/li&gt;
&lt;li&gt;ajout de la mention 4Mhz sur la sortie HP du VDP &lt;code&gt;7801&lt;/code&gt;, pour plus d'information lors de la recherche de panne.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui donne, mis à jour.&lt;/p&gt;
&lt;h4&gt;La platine principale&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 29 avril 2021)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/202104/VG5000-Schema-v1.4.png"&gt;&lt;img alt="Platine principale" src="https://www.triceraprog.fr/images/202104/VG5000-Schema-v1.4-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;La platine K7/Son&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2.png"&gt;&lt;img alt="Platine K7/Son" src="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;Le schéma a été mis à jour dans &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v15.html"&gt;un nouvel article&lt;/a&gt;.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Schéma"></category></entry><entry><title>Programmer sur Nintendo Switch en BASIC</title><link href="https://www.triceraprog.fr/programmer-sur-nintendo-switch-en-basic.html" rel="alternate"></link><published>2021-03-28T00:00:00+01:00</published><updated>2021-03-28T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2021-03-28:/programmer-sur-nintendo-switch-en-basic.html</id><summary type="html">&lt;p&gt;« &lt;strong&gt;Petit Computer&lt;/strong&gt; » est un environnement de programmation qui est apparu initialement sur la Nintendo DSi. Cet environnement se programme dans un dialecte de &lt;strong&gt;BASIC&lt;/strong&gt; du nom de « &lt;strong&gt;Smile BASIC&lt;/strong&gt; ». Et c'est sous le nom « Smile BASIC v4 » qu'il est disponible en version numérique sur l'eShop de la &lt;strong&gt;Nintendo Switch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Après un lancement un peu chaotique en Europe au printemps 2020, à cause d'une erreur dans la classification d'âge il semblerait, il a été à nouveau disponible. Une fois téléchargé et après avoir branché un clavier et une souris en USB sur la Switch, la console se transforme en &lt;strong&gt;ordinateur programmable en BASIC&lt;/strong&gt;. Et c'est amusant !&lt;/p&gt;
&lt;h3&gt;Un environnement presque à l'ancienne...&lt;/h3&gt;
&lt;p&gt;Au &lt;strong&gt;démarrage&lt;/strong&gt;, on est pris en main avec des explications sur l'environnement. Les explications ne sont pas très poussées, et même après avoir parcouru le &lt;strong&gt;très bavard tutoriel&lt;/strong&gt;, je pense que des apprentis programmeurs resteront un peu sur leur faim …&lt;/p&gt;</summary><content type="html">&lt;p&gt;« &lt;strong&gt;Petit Computer&lt;/strong&gt; » est un environnement de programmation qui est apparu initialement sur la Nintendo DSi. Cet environnement se programme dans un dialecte de &lt;strong&gt;BASIC&lt;/strong&gt; du nom de « &lt;strong&gt;Smile BASIC&lt;/strong&gt; ». Et c'est sous le nom « Smile BASIC v4 » qu'il est disponible en version numérique sur l'eShop de la &lt;strong&gt;Nintendo Switch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Après un lancement un peu chaotique en Europe au printemps 2020, à cause d'une erreur dans la classification d'âge il semblerait, il a été à nouveau disponible. Une fois téléchargé et après avoir branché un clavier et une souris en USB sur la Switch, la console se transforme en &lt;strong&gt;ordinateur programmable en BASIC&lt;/strong&gt;. Et c'est amusant !&lt;/p&gt;
&lt;h3&gt;Un environnement presque à l'ancienne...&lt;/h3&gt;
&lt;p&gt;Au &lt;strong&gt;démarrage&lt;/strong&gt;, on est pris en main avec des explications sur l'environnement. Les explications ne sont pas très poussées, et même après avoir parcouru le &lt;strong&gt;très bavard tutoriel&lt;/strong&gt;, je pense que des apprentis programmeurs resteront un peu sur leur faim.&lt;/p&gt;
&lt;p&gt;Ah, une autre précision : le logiciel n'existe qu'en anglais et en japonais.&lt;/p&gt;
&lt;p&gt;Niveau documentation, le site officiel donne une &lt;strong&gt;référence plutôt complète&lt;/strong&gt;, et trois &lt;em&gt;PDF&lt;/em&gt;s d'explications parcellaires qui donnent quelques idées du fonctionnement.&lt;/p&gt;
&lt;p&gt;Très pratique cependant, l'&lt;strong&gt;aide en ligne&lt;/strong&gt; est disponible et est très complète. &lt;code&gt;F1&lt;/code&gt; après un mot clé donne les explications. &lt;code&gt;F1&lt;/code&gt; sans mot clé amène au manuel général.&lt;/p&gt;
&lt;p&gt;Malgré tout cela, au début, on retrouve un peu la sensation d'une machine à l'ancienne : il semble y avoir plein de possibilités, mais il va falloir les découvrir en tâtonnant, et faisant des essais. En ce sens, « &lt;strong&gt;Smile BASIC&lt;/strong&gt; » est ludique.&lt;/p&gt;
&lt;h3&gt;Cloud et Partage&lt;/h3&gt;
&lt;p&gt;Moyennant l'achat d'un « &lt;strong&gt;ticket&lt;/strong&gt; » &lt;strong&gt;supplémentaire&lt;/strong&gt; à l'achat du logiciel, on peut sauvegarder et surtout partager ses créations sur un serveur dédié à la communauté Smile BASIC. Et puisqu'il y a partage, il est aussi possible de &lt;strong&gt;télécharger les créations&lt;/strong&gt; des autres, pour s'en inspirer, &lt;strong&gt;les modifier&lt;/strong&gt; ou tout simplement y &lt;strong&gt;jouer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sans le ticket, on ne pourra charger qu'une seule création toutes les huit heures, et pas partager les siennes.&lt;/p&gt;
&lt;p&gt;Par contre, pas moyen d'échanger des données avec le monde extérieur, comme un PC. Ou du moins pas simplement. Ce qui est créé dans Smile BASIC reste dans Smile BASIC. Cela inclus le code BASIC tout autant que les musiques, sprites,...&lt;/p&gt;
&lt;h3&gt;Ça ressemble à quoi ?&lt;/h3&gt;
&lt;p&gt;Lorsque l'on passe en mode « création », on arrive sur un écran qui ne dépayse pas lorsque l'on est habitué de vieilles machines.&lt;/p&gt;
&lt;p&gt;La résolution de l'écran est de 400 par 240, mais cela peut se changer jusqu'à du 720p.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: mes captures bavent à cause de mon périphérique d'acquisition, ce n'est pas le cas de l'image en sortie de la Switch, qui est très bonne.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le mode direct de Smile Basic 4" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202103/20210327-SmileBasic-Direct.png"&gt;&lt;/p&gt;
&lt;p&gt;En &lt;strong&gt;mode direct&lt;/strong&gt;, on peut taper des commandes et voir le résultat. Il est possible de dessiner grâce à des primitives telles que point, ligne, cercle, rectangle ou triangle. Le système propose aussi un système de &lt;strong&gt;sprites&lt;/strong&gt; avec collisions possibles et de la composition de plans d'affichages.&lt;/p&gt;
&lt;p&gt;Cela peut commencer très simple, mais être poussé assez loin.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Commandes de dessin avec Smile Basic 4" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202103/20210327-SmileBasic-Graphics.png"&gt;&lt;/p&gt;
&lt;p&gt;Et pour créer ces sprites, ou n'importe quel dessin, un &lt;strong&gt;logiciel&lt;/strong&gt; de &lt;strong&gt;pixel art&lt;/strong&gt; est disponible sur &lt;code&gt;F10&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Editeur graphique Smile Basic 4" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202103/20210327-SmileBasic-Gahaku.png"&gt;&lt;/p&gt;
&lt;p&gt;La programmation est sans numéro de ligne. On bascule dans un &lt;strong&gt;éditeur de texte&lt;/strong&gt; pour entrer un programme résident. Il est possible de sauver les fichiers bien entendu, et d'en rappeler d'autres. Le tout, comme je le mentionnais, avec une aide en ligne.&lt;/p&gt;
&lt;p&gt;&lt;img alt="L'aide en ligne Smile Basic 4" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202103/20210327-SmileBasic-Help.png"&gt;&lt;/p&gt;
&lt;h3&gt;Conclusion pour le moment&lt;/h3&gt;
&lt;p&gt;« Smile BASIC » est plutôt &lt;strong&gt;sympathique&lt;/strong&gt;. On est un peu perdu en arrivant dessus la première fois, mais à force d'essais, de lectures de la référence et de l'aide en ligne, on peut commencer à faire des petites choses sympa.&lt;/p&gt;
&lt;p&gt;Le système, bien qu'assez complet, n'est pas là pour pousser la Switch à fond, ce n'est pas le but. L'idée est plutôt de s'amuser à programmer dans un environnement simple, avec des outils et ressources clés en main (il y a aussi des effets sonores et des musiques disponibles de base).&lt;/p&gt;
&lt;p&gt;La communauté à l'air assez réduite hors Japon cependant, c'est un peu dommage, mais assez compréhensible.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un petit programme" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202103/20210327-SmileBasic-Program.png"&gt;&lt;/p&gt;</content><category term="Langages"></category><category term="BASIC"></category><category term="Nintendo Switch"></category></entry><entry><title>Automatisation : utilisation de Visual Studio Code</title><link href="https://www.triceraprog.fr/automatisation-utilisation-de-visual-studio-code.html" rel="alternate"></link><published>2020-12-27T00:00:00+01:00</published><updated>2020-12-27T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-12-27:/automatisation-utilisation-de-visual-studio-code.html</id><summary type="html">&lt;p&gt;Il y a &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-sublime-text-3.html"&gt;presque trois ans&lt;/a&gt; (déjà !), j'avais mis en place un &lt;strong&gt;environnement de programmation&lt;/strong&gt; pour me permettre de mettre au point un programme en assembleur &lt;strong&gt;Z80&lt;/strong&gt; et de l'envoyer vers &lt;strong&gt;MAME&lt;/strong&gt;, afin de réduire le nombre d'opérations manuelles. Le tout à partir de &lt;strong&gt;Sublime Text 3&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Peut-être parce que la documentation de cet éditeur n'est pas des plus détaillée, ou peut-être parce que c'est avant tout un éditeur de texte, les extensions autour de l'assembleur Z80 sont peu nombreuses. C'est plutôt du côté de &lt;strong&gt;Visual Studio Code&lt;/strong&gt; que ces extensions sont apparues.&lt;/p&gt;
&lt;p&gt;Récemment, j'ai donc fait deux changements dans ma chaîne de mise au point pour &lt;strong&gt;VG5000µ&lt;/strong&gt;. Tout d'abord, j'utilise à présent &lt;strong&gt;Visual Studio Code&lt;/strong&gt; comme éditeur, et ensuite, j'ai changé d'assembleur.&lt;/p&gt;
&lt;h2&gt;Visual Studio Code&lt;/h2&gt;
&lt;p&gt;Tout comme Sublime Text 3, l'important pour moi est que l'éditeur puisse fonctionner sur diverses plateformes, et entre autre sur celle que j'utilise pour …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Il y a &lt;a href="https://www.triceraprog.fr/automatisation-utilisation-de-sublime-text-3.html"&gt;presque trois ans&lt;/a&gt; (déjà !), j'avais mis en place un &lt;strong&gt;environnement de programmation&lt;/strong&gt; pour me permettre de mettre au point un programme en assembleur &lt;strong&gt;Z80&lt;/strong&gt; et de l'envoyer vers &lt;strong&gt;MAME&lt;/strong&gt;, afin de réduire le nombre d'opérations manuelles. Le tout à partir de &lt;strong&gt;Sublime Text 3&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Peut-être parce que la documentation de cet éditeur n'est pas des plus détaillée, ou peut-être parce que c'est avant tout un éditeur de texte, les extensions autour de l'assembleur Z80 sont peu nombreuses. C'est plutôt du côté de &lt;strong&gt;Visual Studio Code&lt;/strong&gt; que ces extensions sont apparues.&lt;/p&gt;
&lt;p&gt;Récemment, j'ai donc fait deux changements dans ma chaîne de mise au point pour &lt;strong&gt;VG5000µ&lt;/strong&gt;. Tout d'abord, j'utilise à présent &lt;strong&gt;Visual Studio Code&lt;/strong&gt; comme éditeur, et ensuite, j'ai changé d'assembleur.&lt;/p&gt;
&lt;h2&gt;Visual Studio Code&lt;/h2&gt;
&lt;p&gt;Tout comme Sublime Text 3, l'important pour moi est que l'éditeur puisse fonctionner sur diverses plateformes, et entre autre sur celle que j'utilise pour mes projets rétro : &lt;strong&gt;Ubuntu Linux&lt;/strong&gt;. De ce côté, c'est ok.&lt;/p&gt;
&lt;p&gt;Pour la syntaxe colorée, j'utilise le plugin &lt;strong&gt;Z80 Macro-Assembleur&lt;/strong&gt;. Le plugin apporte aussi un « problem matcher », qui est la façon pour l'éditeur de savoir si des erreurs ont été levées lors de phase de construction.&lt;/p&gt;
&lt;p&gt;Il offre aussi un support d'&lt;strong&gt;Intellisense&lt;/strong&gt;, mais que je n'ai pas encore mis en fonctionnement. A priori, ça ne fonctionne pas tout seul.&lt;/p&gt;
&lt;p&gt;J'ai aussi ajouté &lt;strong&gt;Z80 Assembly meter&lt;/strong&gt; qui permet d'évaluer le nombre de cycles pris par du code sélectionné, avec une option &lt;code&gt;MSX&lt;/code&gt; qui allonge d'un cycle les instructions, ce qui est aussi valable pour le &lt;strong&gt;VG5000µ&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;L'assembleur&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Auparavant&lt;/strong&gt;, j'utilisais l'assembleur &lt;strong&gt;z80asm&lt;/strong&gt; livré avec l'environnement &lt;strong&gt;z88dk&lt;/strong&gt;. C'était un choix historique venant de mes essais en C sur le Z80. Cet assembleur fonctionne bien, mais est très minimaliste. En effet, un assembleur derrière un compilateur n'a pas besoin de beaucoup d'aides, le compilateur pouvant générer le code in extenso.&lt;/p&gt;
&lt;p&gt;Lorsque l'on met au point du code à la main, rapidement, pouvoir écrire des macros, manipuler des adresses via des expressions, devient un outil nécessaire.&lt;/p&gt;
&lt;p&gt;C'est vers &lt;strong&gt;sjasmplus&lt;/strong&gt; que je me suis tourné. Comme souvent, l'assembleur est fait avec une machine particulière en tête, ici la ligne des &lt;strong&gt;Spectrum&lt;/strong&gt;. Mais ce n'est pas bien grave. L'assembleur a des &lt;strong&gt;macros&lt;/strong&gt;, est assez &lt;strong&gt;souple&lt;/strong&gt; sur la syntaxe, a pas mal d'&lt;strong&gt;instructions&lt;/strong&gt; pour déclarer ce que l'on veut faire.&lt;/p&gt;
&lt;h2&gt;La tuyauterie&lt;/h2&gt;
&lt;p&gt;Voici le fichier &lt;code&gt;tasks.json&lt;/code&gt; que j'ai écris. Il est probablement perfectible car je ne connais pas toutes les subtilités de &lt;strong&gt;Visual Studio Code&lt;/strong&gt;, mais il fait l'affaire pour le moment.&lt;/p&gt;
&lt;p&gt;Pour le fonctionnement du script &lt;code&gt;vgboot.lua&lt;/code&gt;, je vous renvois à &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html"&gt;cet article&lt;/a&gt;. Le script n'a pas bougé depuis.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    &amp;quot;version&amp;quot;: &amp;quot;2.0.0&amp;quot;,
    &amp;quot;tasks&amp;quot;: [
        {
            &amp;quot;label&amp;quot;: &amp;quot;sjasmplus - Build&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;shell&amp;quot;,
            // Options: No fake instructions, Warning as Errors, Multi arg is &amp;#39;,,&amp;#39;
            &amp;quot;command&amp;quot;: &amp;quot;sjasmplus --syntax=FLwa &lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;fileBasename&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt; --raw=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;fileBasenameNoExtension&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;.bin --lst&amp;quot;,
            &amp;quot;problemMatcher&amp;quot;: [
                &amp;quot;&lt;span class="nv"&gt;$errmatcher&lt;/span&gt;-sjasmplus&amp;quot;
            ],
            &amp;quot;group&amp;quot;: {
                &amp;quot;kind&amp;quot;: &amp;quot;build&amp;quot;,
                &amp;quot;isDefault&amp;quot;: true
            },
            &amp;quot;options&amp;quot;: {
                &amp;quot;cwd&amp;quot;: &amp;quot;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;relativeFileDirname&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&amp;quot;
            }
        },
        {
            &amp;quot;label&amp;quot;: &amp;quot;sjasmplus - Run on Mame&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;shell&amp;quot;,
            &amp;quot;command&amp;quot;: &amp;quot;mame64 vg5k -ramsize 48k -nomax -window -autoboot_delay 0 -autoboot_script vgboot.lua -debug -debugger none -natural&amp;quot;,
            &amp;quot;problemMatcher&amp;quot;: [
                &amp;quot;&lt;span class="nv"&gt;$errmatcher&lt;/span&gt;-sjasmplus&amp;quot;
            ],
            &amp;quot;dependsOn&amp;quot;: [
                &amp;quot;sjasmplus - Build&amp;quot;
            ],
            &amp;quot;options&amp;quot;: {
                &amp;quot;cwd&amp;quot;: &amp;quot;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;relativeFileDirname&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&amp;quot;
            }
        },
        {
            &amp;quot;label&amp;quot;: &amp;quot;sjasmplus - Debug on Mame&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;shell&amp;quot;,
            &amp;quot;command&amp;quot;: &amp;quot;mame64 vg5k -ramsize 48k -nomax -window -autoboot_delay 0 -autoboot_script vgboot.lua -debug -debugger qt -natural&amp;quot;,
            &amp;quot;problemMatcher&amp;quot;: [
                &amp;quot;&lt;span class="nv"&gt;$errmatcher&lt;/span&gt;-sjasmplus&amp;quot;
            ],
            &amp;quot;dependsOn&amp;quot;: [
                &amp;quot;sjasmplus - Build&amp;quot;
            ],
            &amp;quot;options&amp;quot;: {
                &amp;quot;cwd&amp;quot;: &amp;quot;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;relativeFileDirname&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&amp;quot;
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;La suite&lt;/h2&gt;
&lt;p&gt;Les environnements pour des machines connues vont encore plus loin, avec par exemple de l'intégration de debugger directement dans &lt;strong&gt;Visual Studio Code&lt;/strong&gt;. Il y a aussi un support de tests unitaires, qui me plaît bien. Reste qu'il faut faire quelques branchements pour que cela fonctionne pour un VG5000µ. Je ne sais pas encore si j'irai vers là.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Émulation"></category><category term="Debug"></category><category term="Outils"></category><category term="Automatisation"></category></entry><entry><title>VG5000µ, Set Point assembleur depuis le BASIC</title><link href="https://www.triceraprog.fr/vg5000m-set-point-assembleur-depuis-le-basic.html" rel="alternate"></link><published>2020-12-16T00:00:00+01:00</published><updated>2020-12-16T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-12-16:/vg5000m-set-point-assembleur-depuis-le-basic.html</id><summary type="html">&lt;p&gt;Cet article est la suite de deux précédents articles. Le &lt;strong&gt;premier&lt;/strong&gt;, en plusieurs parties, était l'implémentation de &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-afficher-le-point.html"&gt;l'affichage d'un « gros pixel »&lt;/a&gt; sur l'écran du VG5000µ. Le &lt;strong&gt;second&lt;/strong&gt; était celui sur la possibilité (&lt;a href="https://www.triceraprog.fr/vg5000m-ajouter-des-instructions-au-basic.html"&gt;ou plutôt la difficulté&lt;/a&gt;) d'ajouter des commandes au BASIC du VG5000µ.&lt;/p&gt;
&lt;p&gt;Il existe cependant une façon d'ajouter des commandes au BASIC... ou presque. Cette possibilité est évoquée brièvement dans le livre &lt;strong&gt;« Clefs pour VG5000 »&lt;/strong&gt; page 98. À charge au lecteur de se débrouiller.&lt;/p&gt;
&lt;p&gt;Cette méthode, indiquée dans le livre, est à vrai dire celle qui est utilisée par l'implémentation BASIC de la machine. Chaque routine d'instruction démarre avec &lt;code&gt;HL&lt;/code&gt; qui pointe dans le buffer du texte BASIC sur l'octet suivant le token d'instruction, et donc sur ses éventuels paramètres.&lt;/p&gt;
&lt;p&gt;C'est donc le cas, comme les autres, de l'instruction &lt;code&gt;CALL&lt;/code&gt;. La routine de l'instruction se charge de lire l'adresse puis de l'appeler. Par lecture de ce paramètre, &lt;code&gt;HL&lt;/code&gt; a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Cet article est la suite de deux précédents articles. Le &lt;strong&gt;premier&lt;/strong&gt;, en plusieurs parties, était l'implémentation de &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-afficher-le-point.html"&gt;l'affichage d'un « gros pixel »&lt;/a&gt; sur l'écran du VG5000µ. Le &lt;strong&gt;second&lt;/strong&gt; était celui sur la possibilité (&lt;a href="https://www.triceraprog.fr/vg5000m-ajouter-des-instructions-au-basic.html"&gt;ou plutôt la difficulté&lt;/a&gt;) d'ajouter des commandes au BASIC du VG5000µ.&lt;/p&gt;
&lt;p&gt;Il existe cependant une façon d'ajouter des commandes au BASIC... ou presque. Cette possibilité est évoquée brièvement dans le livre &lt;strong&gt;« Clefs pour VG5000 »&lt;/strong&gt; page 98. À charge au lecteur de se débrouiller.&lt;/p&gt;
&lt;p&gt;Cette méthode, indiquée dans le livre, est à vrai dire celle qui est utilisée par l'implémentation BASIC de la machine. Chaque routine d'instruction démarre avec &lt;code&gt;HL&lt;/code&gt; qui pointe dans le buffer du texte BASIC sur l'octet suivant le token d'instruction, et donc sur ses éventuels paramètres.&lt;/p&gt;
&lt;p&gt;C'est donc le cas, comme les autres, de l'instruction &lt;code&gt;CALL&lt;/code&gt;. La routine de l'instruction se charge de lire l'adresse puis de l'appeler. Par lecture de ce paramètre, &lt;code&gt;HL&lt;/code&gt; a été positionné après celui-ci et c'est donc dans cet état que la routine utilisateur est appelée.&lt;/p&gt;
&lt;h2&gt;Exemple&lt;/h2&gt;
&lt;p&gt;Voici un exemple rapide d'une commande qui peut s'appeler par &lt;code&gt;CALL &amp;amp;"7000",X,Y&lt;/code&gt;, X et Y étant les coordonnées du point à afficher. La routine &lt;code&gt;setpoint&lt;/code&gt; est celle de l'article cité au début.&lt;/p&gt;
&lt;p&gt;L'idée derrière le premier &lt;code&gt;jp&lt;/code&gt; est de commencer par une série de &lt;code&gt;jp&lt;/code&gt; qui amène aux différentes routines qui seront donc &lt;code&gt;CALL &amp;amp;"7000"&lt;/code&gt;, &lt;code&gt;CALL &amp;amp;"7003"&lt;/code&gt;, &lt;code&gt;CALL &amp;amp;"7006"&lt;/code&gt;,...&lt;/p&gt;
&lt;p&gt;On peut même aller jusqu'à mettre l'adresse dans une variable pour obtenir quelque chose comme &lt;code&gt;CALL SP,X,Y&lt;/code&gt; (les variables ont deux caractères maximum significatif sur VG5000µ).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chkchr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;getbyt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0086&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;entry:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;call_setpoint&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;call_setpoint:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde des registres, sauf HL, dont on a besoin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;chkchr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Il doit y avoir une virgule, ou c&amp;#39;est une erreur de syntaxe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;getbyt&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Puis une expression 8 bits entière pour la première coordonnée X dans A et (D)E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Sauve cette valeur sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;chkchr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Il doit y avoir une virgule, ou c&amp;#39;est une erreur de syntaxe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;getbyt&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Puis une expression 8 bits entière pour la seconde coordonnée Y dans A et (D)E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Récupère la coordonnée X (dans L) en échange du pointeur sur le texte BASIC&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Place la coordonnée Y dans H&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;setpoint&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Appel l&amp;#39;affichage du point avec les coordonnées dans HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Restaure les registres, dont HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;D'autres choses ?&lt;/h2&gt;
&lt;p&gt;Le livre indique aussi la possibilité d'utiliser &lt;code&gt;deint ($0083)&lt;/code&gt;. Ce n'est cependant pas possible directement. Cette fonction prend ce qui est dans l'accumulateur flottant et le place en tant qu'entier dans &lt;code&gt;DE&lt;/code&gt;. Mais il faut donc au préalable charger l'accumulateur flottant.&lt;/p&gt;
&lt;p&gt;C'est possible avec &lt;code&gt;eval_num_ex ($284d)&lt;/code&gt;, qui doit donc être appelé au préalable, car c'est cette routine qui analyse l'expression et vérifie qu'elle est numérique.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Grâce à cette méthode, il est donc possible de créer une petite bibliothèques de routines assembleurs appelable avec des paramètres depuis le BASIC.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Affichage des résultats de tests dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202012/VG5000-Square-SetPoint-ASM.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category><category term="BASIC"></category></entry><entry><title>VG5000µ, le commentaire de la ROM</title><link href="https://www.triceraprog.fr/vg5000m-le-commentaire-de-la-rom.html" rel="alternate"></link><published>2020-12-12T00:00:00+01:00</published><updated>2020-12-12T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-12-12:/vg5000m-le-commentaire-de-la-rom.html</id><summary type="html">&lt;p&gt;Le 8 avril 2017, un message sur le forum &lt;a href="https://forum.system-cfg.com/viewtopic.php?f=1&amp;amp;t=7979"&gt;system-cfg&lt;/a&gt; posait la question de l'existence d'un &lt;strong&gt;commentaire extensif&lt;/strong&gt; de la &lt;strong&gt;ROM&lt;/strong&gt; du VG5000µ. J'y répondais que j'avais quelques notes.&lt;/p&gt;
&lt;p&gt;Depuis, sur ce site, j'ai &lt;strong&gt;décortiqué&lt;/strong&gt; un certain nombre de parties, par curiosité personnelle, ou pour répondre à des questions qui se posaient sur le même forum. Au fur et à mesure, je me suis embarqué dans le commentaire exhaustif de la ROM.&lt;/p&gt;
&lt;h2&gt;Le commentaire&lt;/h2&gt;
&lt;p&gt;Ce fut long, &lt;strong&gt;plutôt long&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et je &lt;strong&gt;publie&lt;/strong&gt; le résultat &lt;strong&gt;aujourd'hui&lt;/strong&gt;. Ce résultat prend la forme principale de deux fichiers de commentaires, l'un pour la &lt;strong&gt;ROM 1.0&lt;/strong&gt; et l'autre pour la &lt;strong&gt;ROM 1.1&lt;/strong&gt;. Le tout est disponible &lt;a href="https://github.com/Triceraprog/vg5000_rom_comments"&gt;ici sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce que je ne publie pas aujourd'hui est l'outil qui permet de prend la ROM d'un côté, le fichier de commentaires de l'autre et qui génère un listing assembleur commenté qui peut-être assemblé à …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Le 8 avril 2017, un message sur le forum &lt;a href="https://forum.system-cfg.com/viewtopic.php?f=1&amp;amp;t=7979"&gt;system-cfg&lt;/a&gt; posait la question de l'existence d'un &lt;strong&gt;commentaire extensif&lt;/strong&gt; de la &lt;strong&gt;ROM&lt;/strong&gt; du VG5000µ. J'y répondais que j'avais quelques notes.&lt;/p&gt;
&lt;p&gt;Depuis, sur ce site, j'ai &lt;strong&gt;décortiqué&lt;/strong&gt; un certain nombre de parties, par curiosité personnelle, ou pour répondre à des questions qui se posaient sur le même forum. Au fur et à mesure, je me suis embarqué dans le commentaire exhaustif de la ROM.&lt;/p&gt;
&lt;h2&gt;Le commentaire&lt;/h2&gt;
&lt;p&gt;Ce fut long, &lt;strong&gt;plutôt long&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et je &lt;strong&gt;publie&lt;/strong&gt; le résultat &lt;strong&gt;aujourd'hui&lt;/strong&gt;. Ce résultat prend la forme principale de deux fichiers de commentaires, l'un pour la &lt;strong&gt;ROM 1.0&lt;/strong&gt; et l'autre pour la &lt;strong&gt;ROM 1.1&lt;/strong&gt;. Le tout est disponible &lt;a href="https://github.com/Triceraprog/vg5000_rom_comments"&gt;ici sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce que je ne publie pas aujourd'hui est l'outil qui permet de prend la ROM d'un côté, le fichier de commentaires de l'autre et qui génère un listing assembleur commenté qui peut-être assemblé à nouveau. Cet outil, que j'ai développé en parallèle, nécessite un bon coup de nettoyage avant publication. Peut-être que je le publierai avant son nettoyage complet, mais je dois au moins effectuer une relecture de sécurité.&lt;/p&gt;
&lt;h2&gt;Terminé ?&lt;/h2&gt;
&lt;p&gt;Les commentaires ayant été écrits sur une durée de &lt;strong&gt;trois ans&lt;/strong&gt;, et malgré une passe de &lt;strong&gt;relecture&lt;/strong&gt; récente, il reste probablement des &lt;strong&gt;incohérences&lt;/strong&gt; de nommage, et peut-être aussi quelques fautes de frappe ou d'orthographe par-ci par-là. Il est tout à fait possible de me les mentionner.&lt;/p&gt;
&lt;p&gt;Dans le futur, en fonction d'autres développement autour du &lt;strong&gt;VG5000µ&lt;/strong&gt;, il est possible que je revienne dessus et que je corrige ou que j'augmente les informations.&lt;/p&gt;
&lt;p&gt;Il y a aussi parfois des noms d'&lt;strong&gt;articles entre crochets&lt;/strong&gt;. Il s'agit d'articles que j'ai prévu de faire, s'ils ne le sont pas déjà, sur ce site. On verra...&lt;/p&gt;
&lt;h2&gt;C'est en français !&lt;/h2&gt;
&lt;p&gt;Oui. C'est en &lt;strong&gt;français&lt;/strong&gt;. Comme la machine. J'ai hésite à taper les commentaires en anglais ou en français. Au final, je suis parti pour le français en essayant de ne pas utiliser trop d'anglicismes, à part les évidents du domaine.&lt;/p&gt;
&lt;p&gt;Si quelqu'un veut se lancer dans une traduction dans une autre langue, la licence est « Attribution - Partage dans les Mêmes Conditions 4.0 International » (CC BY-SA 4.0). Allez-y !&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>VG5000µ, Schémas de principe mis à jour</title><link href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour.html" rel="alternate"></link><published>2020-11-17T00:00:00+01:00</published><updated>2020-11-17T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-11-17:/vg5000m-schemas-de-principe-mis-a-jour.html</id><content type="html">&lt;p&gt;Il y a deux ans, &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe.html"&gt;je publiais ici&lt;/a&gt; une remise au propre du &lt;strong&gt;schéma de principe&lt;/strong&gt; de la documentation du VG5000µ.&lt;/p&gt;
&lt;p&gt;Alors que je finalise le commentaire de la ROM, je me suis aperçu qu'il y avait une erreur au niveau du décodage des entrées sorties. C'est à présent corrigé (ainsi que sur l'article original).&lt;/p&gt;
&lt;p&gt;Au niveau de &lt;strong&gt;7807&lt;/strong&gt;, j'avais inversé les entrées &lt;code&gt;\RD&lt;/code&gt; et &lt;code&gt;\WR&lt;/code&gt;, ce qui n'avait pas de sens pour l'entrée &lt;code&gt;C&lt;/code&gt; du &lt;strong&gt;74LS138&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;J'en ai profité pour améliorer la nomenclature des signaux au niveau de ce même composant, en cohérence avec le datasheet.&lt;/p&gt;
&lt;h4&gt;La platine principale&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 17 nov. 2020)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/202011/VG5000-Schema-v1.3.png"&gt;&lt;img alt="Platine principale" src="https://www.triceraprog.fr/images/202011/VG5000-Schema-v1.3-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;La platine K7/Son&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2.png"&gt;&lt;img alt="Platine K7/Son" src="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;Le schéma a été mis à jour dans &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v15.html"&gt;un nouvel article&lt;/a&gt;.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Schéma"></category></entry><entry><title>VG5000µ, deux mises à jour sur MAME</title><link href="https://www.triceraprog.fr/vg5000m-deux-mises-a-jour-sur-mame.html" rel="alternate"></link><published>2020-09-06T00:00:00+02:00</published><updated>2020-09-06T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-09-06:/vg5000m-deux-mises-a-jour-sur-mame.html</id><summary type="html">&lt;p&gt;Lors du commentaire systématique de la ROM du &lt;strong&gt;VG5000µ&lt;/strong&gt;, je suis arrivé sur les routines de &lt;strong&gt;lecture&lt;/strong&gt; et &lt;strong&gt;écriture&lt;/strong&gt; sur &lt;strong&gt;cassette&lt;/strong&gt;. Comme d'habitude, afin de vérifier le fonctionnement de la machine, je fais des tests. Si je fais parfois des tests sur le matériel réel, la plupart du temps, un test sur émulateur suffit, voire est beaucoup plus simple, permettant de dérouler une routine et la suivre avec des données bien choisies.&lt;/p&gt;
&lt;p&gt;J'utilise essentiellement &lt;a href="https://github.com/mamedev/mame"&gt;&lt;strong&gt;MAME&lt;/strong&gt;&lt;/a&gt; pour cela, qui est muni d'un debuggeur qui répond à mes attentes. J'utilise parfois &lt;a href="http://dcvg5k.free.fr/"&gt;&lt;strong&gt;dcvg5k&lt;/strong&gt;&lt;/a&gt;, qui est plus orienté sur une utilisation de la machine simple et pratique.&lt;/p&gt;
&lt;p&gt;Cependant, pour la cassette, &lt;strong&gt;aucun des deux&lt;/strong&gt; ne convenait. Les deux émulateurs ne savent lire que le format &lt;code&gt;K7&lt;/code&gt;, qui a le mérite d'être &lt;strong&gt;extrêmement simple&lt;/strong&gt; et &lt;strong&gt;facilement lisible&lt;/strong&gt;, mais qui a l'inconvénient d'être inadéquat au bon déroulement des routines de lecture et d'écriture.&lt;/p&gt;
&lt;p&gt;La format &lt;code&gt;K7 …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Lors du commentaire systématique de la ROM du &lt;strong&gt;VG5000µ&lt;/strong&gt;, je suis arrivé sur les routines de &lt;strong&gt;lecture&lt;/strong&gt; et &lt;strong&gt;écriture&lt;/strong&gt; sur &lt;strong&gt;cassette&lt;/strong&gt;. Comme d'habitude, afin de vérifier le fonctionnement de la machine, je fais des tests. Si je fais parfois des tests sur le matériel réel, la plupart du temps, un test sur émulateur suffit, voire est beaucoup plus simple, permettant de dérouler une routine et la suivre avec des données bien choisies.&lt;/p&gt;
&lt;p&gt;J'utilise essentiellement &lt;a href="https://github.com/mamedev/mame"&gt;&lt;strong&gt;MAME&lt;/strong&gt;&lt;/a&gt; pour cela, qui est muni d'un debuggeur qui répond à mes attentes. J'utilise parfois &lt;a href="http://dcvg5k.free.fr/"&gt;&lt;strong&gt;dcvg5k&lt;/strong&gt;&lt;/a&gt;, qui est plus orienté sur une utilisation de la machine simple et pratique.&lt;/p&gt;
&lt;p&gt;Cependant, pour la cassette, &lt;strong&gt;aucun des deux&lt;/strong&gt; ne convenait. Les deux émulateurs ne savent lire que le format &lt;code&gt;K7&lt;/code&gt;, qui a le mérite d'être &lt;strong&gt;extrêmement simple&lt;/strong&gt; et &lt;strong&gt;facilement lisible&lt;/strong&gt;, mais qui a l'inconvénient d'être inadéquat au bon déroulement des routines de lecture et d'écriture.&lt;/p&gt;
&lt;p&gt;La format &lt;code&gt;K7&lt;/code&gt; est une simple liste des octets décodés depuis un enregistrement réel. C'est un format &lt;strong&gt;pratique&lt;/strong&gt; car &lt;strong&gt;très compact&lt;/strong&gt;. L'émulateur &lt;strong&gt;dcvg5k&lt;/strong&gt; s'en sert pour injecter ou extraire les valeurs en &lt;strong&gt;court-circuitant&lt;/strong&gt; la routine de lecture et d'écriture de la &lt;strong&gt;ROM&lt;/strong&gt;. Si j'ai bien compris, l'émulateur intercepte l'exécution normale à des endroits bien choisis et prend la main pour une lecture ou écriture très rapide.&lt;/p&gt;
&lt;p&gt;C'est une idée qui se défend pour une utilisation de la machine en &lt;strong&gt;évitant&lt;/strong&gt; des &lt;strong&gt;temps d'attentes&lt;/strong&gt; associés aux cassettes.&lt;/p&gt;
&lt;p&gt;Dans mon cas d'&lt;strong&gt;étude&lt;/strong&gt; des routines, c'est par contre &lt;strong&gt;hors-jeu&lt;/strong&gt;. J'ai besoin d'un signal audio. Je me suis donc tourné vers &lt;strong&gt;MAME&lt;/strong&gt; pour voir si je pouvais ajouter le traitement d'un fichier &lt;code&gt;.WAV&lt;/code&gt; avec ma ROM 1.1 non modifiée.&lt;/p&gt;
&lt;h2&gt;Ajout de lecture/écriture audio&lt;/h2&gt;
&lt;p&gt;La première opération a été d'ajouter le support du format &lt;code&gt;.WAV&lt;/code&gt; sur &lt;strong&gt;MAME&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Comme on peut l'imaginer, la plupart des &lt;strong&gt;services de base&lt;/strong&gt; existent déjà quelque part dans &lt;strong&gt;MAME&lt;/strong&gt;. C'est l'avantage d'un tel mastodonte. Mais être un mastodonte à aussi un &lt;strong&gt;inconvénient&lt;/strong&gt; : il faut savoir &lt;strong&gt;où&lt;/strong&gt; ça se trouve et &lt;strong&gt;comment&lt;/strong&gt; ça s'utilise.&lt;/p&gt;
&lt;p&gt;Une fois trouvé, c'est assez simple. Dans le fichier &lt;code&gt;src/lib/formats/vg5k_cas.cpp&lt;/code&gt;, à côté de la déclaration du support du type de fichier &lt;code&gt;K7&lt;/code&gt;, il suffit d'ajouter la déclaration du support &lt;code&gt;.WAV&lt;/code&gt;. Toute la gestion de fichier et de magnétophone virtuel est alors pris en charge.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;CASSETTE_FORMATLIST_START&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vg5k_cassette_formats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;CASSETTE_FORMAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vg5k_k7_format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;CASSETTE_FORMAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wavfile_format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;CASSETTE_FORMATLIST_END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Premiers problèmes&lt;/h3&gt;
&lt;p&gt;Je me doutais que cela n'allait pas fonctionner directement, puisque la &lt;strong&gt;machine&lt;/strong&gt; était &lt;strong&gt;annotée&lt;/strong&gt; comme &lt;strong&gt;ne fonctionnant pas&lt;/strong&gt;, à cause d'un problème de lecture à 1200 bauds. J'avais comme deuxième objectif de corriger cela, afin de pouvoir analyser les routines complètement.&lt;/p&gt;
&lt;p&gt;Avec la prise en charge du format &lt;code&gt;.WAV&lt;/code&gt;, l'émulation réussi à lire un fichier audio sans soucis. Mais méfiance, la routine du &lt;strong&gt;VG5000µ&lt;/strong&gt; se sert de l'amorce du fichier, une suite de signaux haut/bas, pour se calibrer.&lt;/p&gt;
&lt;p&gt;Le deuxième test est donc de &lt;strong&gt;sauver&lt;/strong&gt; un fichier &lt;code&gt;.WAV&lt;/code&gt; puis de le &lt;strong&gt;recharger&lt;/strong&gt;. Et là, &lt;strong&gt;cela ne fonctionne pas&lt;/strong&gt;. Le fichier est bien sauvé, mais impossible à relire.&lt;/p&gt;
&lt;p&gt;En &lt;strong&gt;examinant&lt;/strong&gt; le fichier obtenu, je vois que les &lt;strong&gt;timings&lt;/strong&gt; sont complètement &lt;strong&gt;farfelus&lt;/strong&gt;. Ils ne correspondent pas à la théorie décrite dans le manuel technique, ils ne correspondent ni à 1200 bauds ni à 2400 bauds, et &lt;strong&gt;ils ne correspondent pas&lt;/strong&gt; à la comparaison avec des fichiers écrits par du matériel réel.&lt;/p&gt;
&lt;h3&gt;Le moteur démarre&lt;/h3&gt;
&lt;p&gt;Au passage, les manipulations sous &lt;strong&gt;MAME&lt;/strong&gt; sont pénibles, car la gestion du &lt;strong&gt;contrôle du moteur&lt;/strong&gt; du magnétophone n'est pas là. Là encore, la plus grande partie du temps passé est de comprendre comment &lt;strong&gt;MAME&lt;/strong&gt; gère le système. Au final, tout est là, il suffit de le brancher sur le bon signal envoyé sur le port I/O de la cassette.&lt;/p&gt;
&lt;p&gt;Chose faite en modifiant la fonction &lt;code&gt;void vg5k_state::cassette_w(uint8_t data)&lt;/code&gt; de &lt;code&gt;src/mame/drivers/vg5k.cpp&lt;/code&gt; et en y ajoutant cette ligne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;m_cassette&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;change_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CASSETTE_MOTOR_ENABLED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CASSETTE_MOTOR_DISABLED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CASSETTE_MASK_MOTOR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;J'en profite pour réécrire cette petite fonction pour faire ressortir un peu mieux la sémantique des données envoyées sur le port I/O.&lt;/p&gt;
&lt;p&gt;À présent, les fonctions d'accès à la cassette (&lt;code&gt;CLOAD&lt;/code&gt;, &lt;code&gt;CSAVE&lt;/code&gt; et les autres) &lt;strong&gt;contrôlent le moteur&lt;/strong&gt; simulé du lecteur dans &lt;strong&gt;MAME&lt;/strong&gt;, est c'est bien plus pratique à utiliser !&lt;/p&gt;
&lt;h3&gt;Le Z80 doit attendre&lt;/h3&gt;
&lt;p&gt;Retour sur les &lt;strong&gt;problèmes de timings&lt;/strong&gt;. Je vous évite tout le cheminement et les tests quand soudain me vient un doute. Est-ce que l'émulation tourne à la bonne vitesse ? Oui, la &lt;strong&gt;fréquence&lt;/strong&gt; déclarée pour le &lt;strong&gt;Z80&lt;/strong&gt; est la bonne (même si techniquement, elle devrait découler de celle du VDP), mais cela ne suffit pas !&lt;/p&gt;
&lt;p&gt;En effet, le &lt;strong&gt;VG5000µ&lt;/strong&gt; insère un état &lt;code&gt;WAIT&lt;/code&gt; supplémentaire pendant sa phase M1 (fetch). Et ça change tout.&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;petit détour&lt;/strong&gt; par le &lt;strong&gt;Z80&lt;/strong&gt; ici. Lors de la phase M1 (opcode fetch), qui s'opère en 4 cycles d'horloge, le 2 premiers cycles placent l'adresse du &lt;code&gt;PC&lt;/code&gt; sur le bus d'adresse puis signalent une requête de lecture mémoire. Lors du cycle 3 (&lt;strong&gt;T3&lt;/strong&gt;), la valeur de l'instruction est lue depuis le bus de données. Les cycles &lt;strong&gt;T3&lt;/strong&gt; et &lt;strong&gt;T4&lt;/strong&gt; conjointement servent pour le rafraîchissement des mémoires dynamiques, laissons ça de côté.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;Z80&lt;/strong&gt; prévoit que le &lt;strong&gt;matériel&lt;/strong&gt; puisse ne pas être prêt à temps pour &lt;strong&gt;livrer&lt;/strong&gt; sur le &lt;strong&gt;bus de données&lt;/strong&gt; l'instruction lue en cycle &lt;strong&gt;T3&lt;/strong&gt;. La ligne &lt;code&gt;WAIT&lt;/code&gt; est donc vérifiée à la fin de &lt;strong&gt;T2&lt;/strong&gt;. Si la ligne est validée, alors le &lt;strong&gt;Z80&lt;/strong&gt; passe en mode &lt;code&gt;WAIT&lt;/code&gt; en ajoutant des cycles supplémentaires d'attente, jusqu'à ce que la ligne &lt;code&gt;WAIT&lt;/code&gt; soit relâchée.&lt;/p&gt;
&lt;p&gt;Et le driver &lt;strong&gt;MAME&lt;/strong&gt; ne respecte pas ça.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;VG5000µ&lt;/strong&gt; tourne trop vite ! Les timings sont faux et l'écriture sur cassette ne fonctionne pas. Reste à savoir comment corriger ça.&lt;/p&gt;
&lt;h3&gt;À la recherche du cycle en plus&lt;/h3&gt;
&lt;p&gt;Une &lt;strong&gt;première piste&lt;/strong&gt; est d'aller voir comment est gérée cette fonctionnalité dans l'émulation Z80 de &lt;strong&gt;MAME&lt;/strong&gt;. Mauvaise nouvelle, &lt;strong&gt;elle ne l'est pas&lt;/strong&gt;. Ou plutôt, la ligne &lt;code&gt;WAIT&lt;/code&gt; est bien émulée, mais uniquement entre les instructions. Cela est bien assez nécessaire, il semblerait, pour l'émulation de son utilisation par des &lt;strong&gt;périphériques&lt;/strong&gt; qui demandent au &lt;strong&gt;Z80&lt;/strong&gt; d'attendre.&lt;/p&gt;
&lt;p&gt;Mais la détection au cycle &lt;strong&gt;T2&lt;/strong&gt; de la phase &lt;strong&gt;M1&lt;/strong&gt; n'est pas là. C'est d'ailleurs indiqué dans les commentaires comme une amélioration possible... Que je ne me sens pas d'ajouter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deuxième piste&lt;/strong&gt; : allez voir ce que font les autres. Côté &lt;strong&gt;Amstrad CPC&lt;/strong&gt; et &lt;strong&gt;MSX&lt;/strong&gt;, les tables de timings d'opcode sont &lt;strong&gt;ajustées&lt;/strong&gt;. Il semblerait qu'il y ait d'&lt;strong&gt;autres raisons&lt;/strong&gt; que ce seul état d'attente, même si c'est une des raisons. Les &lt;strong&gt;réutiliser&lt;/strong&gt; seraient une option... pourvu qu'elles soient utilisables, ce que je trouve un peu lourd à vérifier.&lt;/p&gt;
&lt;p&gt;Reste que cela m'ennuie car ce n'est pas vraiment ce qu'il se passe dans la machine. Je fouille encore. Je trouve un driver qui annonce que faute d'avoir trouvé comment faire, la machine est trop rapide...&lt;/p&gt;
&lt;p&gt;Et enfin, je trouve &lt;strong&gt;une solution&lt;/strong&gt; qui &lt;strong&gt;me plaît&lt;/strong&gt;, utilisée par un autre driver. Utiliser une fonction de rappel sur le rafraîchissement des mémoires dynamiques, qui, étonnamment, est émulée par &lt;strong&gt;MAME&lt;/strong&gt;. Il suffit alors, dans cette fonction de rappel, de dire à l'émulateur du &lt;strong&gt;Z80&lt;/strong&gt; qu'il devra exécuter un cycle de plus.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vg5k_state::z80_m1_w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;m_maincpu&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;adjust_icount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Ça fonctionne !&lt;/h3&gt;
&lt;p&gt;Et tout à coup, &lt;strong&gt;tous les timings cassette&lt;/strong&gt; que je surveillais &lt;strong&gt;sont corrects&lt;/strong&gt; ! La sauvegarde génère un fichier audio qui ressemble à quelque chose (même s'il est bien trop carré pour être pris pour un vrai signal sorti d'une machine réelle, mais ce n'est pas bien grave), et surtout, ce &lt;strong&gt;fichier est relu&lt;/strong&gt; sans problème par l'émulateur.&lt;/p&gt;
&lt;p&gt;Et ceci est à &lt;strong&gt;2400 bauds&lt;/strong&gt; comme à &lt;strong&gt;1200 bauds&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Les fichiers sont aussi compris par l'utilitaire de transformation en format &lt;code&gt;K7&lt;/code&gt; qui accompagne &lt;strong&gt;dcvg5k&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Des fichiers audio écrits depuis un vrai &lt;strong&gt;VG5000µ&lt;/strong&gt; sont lus aussi. Il me reste le dernier test : lire sur du vrai matériel un fichier audio écrit par &lt;strong&gt;MAME&lt;/strong&gt;. J'ai bon espoir que cela fonctionne, mais faute d'avoir effectué de vrais tests, le driver reste en &lt;em&gt;non fonctionnel&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Support de la touche DELTA&lt;/h2&gt;
&lt;p&gt;Le &lt;strong&gt;VG5000µ&lt;/strong&gt; possède sur son clavier cette touche non nommée qui est juste désignée par un &lt;strong&gt;triangle&lt;/strong&gt; dans la documentation, connue aussi sous le nom de touche &lt;strong&gt;DELTA&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Puisque j'étais dans &lt;strong&gt;MAME&lt;/strong&gt;, pourquoi pas &lt;strong&gt;ajouter cette fonctionnalité&lt;/strong&gt; ? En effet, le &lt;strong&gt;soft reset&lt;/strong&gt; qui consiste à remettre le &lt;code&gt;PC&lt;/code&gt; à 0, ce que fait &lt;strong&gt;MAME&lt;/strong&gt; par défaut, ne permet pas de simuler le soft reset tel qu'implémenté sur la machine à travers la touche &lt;strong&gt;DELTA&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Or, ce &lt;strong&gt;soft reset&lt;/strong&gt; peut-être &lt;strong&gt;routé&lt;/strong&gt; vers une &lt;strong&gt;routine utilisateur&lt;/strong&gt; pour d'autres usages, comme par exemple, relancer directement un programme.&lt;/p&gt;
&lt;h3&gt;Une touche à part&lt;/h3&gt;
&lt;p&gt;Cette touche est à part dans sa connexion au système. Chaque touche du clavier forme une matrice qui est lue à travers le bus d'entrée/sortie du &lt;strong&gt;Z80&lt;/strong&gt;. Mais pas celle-ci.&lt;/p&gt;
&lt;p&gt;La touche &lt;strong&gt;DELTA&lt;/strong&gt; est (presque) directement &lt;strong&gt;branchée&lt;/strong&gt; à la ligne &lt;code&gt;NMI&lt;/code&gt; du &lt;strong&gt;Z80&lt;/strong&gt;. Autrement dit, appuyer sur la touche provoque une &lt;strong&gt;interruption non masquable&lt;/strong&gt; dans le &lt;strong&gt;Z80&lt;/strong&gt;. Par défaut, cette interruption appelle une routine qui vérifie si la touche &lt;strong&gt;CTRL&lt;/strong&gt; est aussi appuyée et dans ce cas, provoque un soft reset. Tout ceci après avoir appelé une potentielle &lt;strong&gt;routine utilisateur&lt;/strong&gt; qui, de base, ne fait rien.&lt;/p&gt;
&lt;p&gt;Comme d'habitude, tout cela est bien entendu pris en charge par &lt;strong&gt;MAME&lt;/strong&gt;, reste à savoir comment. Je suis allé voir du côté d'ancien matériels, où les &lt;strong&gt;switchs&lt;/strong&gt; étaient branchés directement sur des fonctions, sans vraiment constituer un &lt;em&gt;clavier&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;solution&lt;/strong&gt; trouvée est la suivante. Tout d'abord, déclarer un nouveau port d'entrée/sortie qui associe au &lt;strong&gt;changement d'état&lt;/strong&gt; d'une touche (j'ai choisi la touche &lt;strong&gt;End/Fin&lt;/strong&gt; du clavier, mais c'est configurable par l'utilisateur) une &lt;strong&gt;fonction de rappel&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    &lt;span class="n"&gt;PORT_START&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;direct&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;PORT_BIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IP_ACTIVE_LOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IPT_KEYBOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="n"&gt;PORT_CODE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KEYCODE_END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                              &lt;span class="n"&gt;PORT_NAME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DELTA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="n"&gt;PORT_CHANGED_MEMBER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEVICE_SELF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vg5k_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delta_button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La fonction de rappel signale tout simplement la ligne &lt;code&gt;NMI&lt;/code&gt; du &lt;strong&gt;Z80&lt;/strong&gt; pendant un bref instant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;INPUT_CHANGED_MEMBER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vg5k_state&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;delta_button&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;newval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;m_maincpu&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pulse_input_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INPUT_LINE_NMI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;attotime&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà. La touche &lt;strong&gt;DELTA&lt;/strong&gt; est émulée. On peut vérifier le fonctionnement des routines utilisateur sur &lt;strong&gt;CTRL+DELTA&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;, elle ne l'est que lorsque le clavier est en more &lt;em&gt;réel&lt;/em&gt; dans &lt;strong&gt;MAME&lt;/strong&gt;, et non en mode &lt;em&gt;naturel&lt;/em&gt;, ce dernier mode cherchant une correspondance &lt;em&gt;naturelle&lt;/em&gt; entre le clavier de l'hôte et la machine émulée.&lt;/p&gt;
&lt;h2&gt;C'est où ?&lt;/h2&gt;
&lt;p&gt;Les &lt;strong&gt;deux patchs&lt;/strong&gt; ont été &lt;strong&gt;intégrés&lt;/strong&gt; dans la &lt;strong&gt;branche principale&lt;/strong&gt; de &lt;strong&gt;MAME&lt;/strong&gt;, c'est donc dès à présent disponible sur &lt;a href="https://github.com/mamedev/mame"&gt;le dépôt&lt;/a&gt;, ou bien dans une future version officielle de &lt;strong&gt;MAME&lt;/strong&gt;.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="MAME"></category><category term="Émulation"></category></entry><entry><title>VG5000µ, deux routines (quasi) identiques</title><link href="https://www.triceraprog.fr/vg5000m-deux-routines-quasi-identiques.html" rel="alternate"></link><published>2020-08-16T00:00:00+02:00</published><updated>2020-08-16T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-08-16:/vg5000m-deux-routines-quasi-identiques.html</id><summary type="html">&lt;p&gt;Hier, en continuant le &lt;strong&gt;commentaire&lt;/strong&gt; systématique de la &lt;strong&gt;ROM&lt;/strong&gt; du &lt;strong&gt;VG5000µ&lt;/strong&gt;, j'ai eu une impression de déjà-vu. Il me semblait bien avoir déjà commenté la partie « redéfinir un caractère étendu » (commandes &lt;code&gt;SETE&lt;/code&gt; et &lt;code&gt;SETG&lt;/code&gt; en BASIC).&lt;/p&gt;
&lt;p&gt;L'impression persiste, voire s’accroît, au fur et à mesure et je me décide à aller voir dans ce que j'ai déjà commenté. J'ai commencé, lentement, ce commentaire en août 2017, avec moult pauses, mais aussi du « butinage ». Il y a donc des parties que je ne me rappelle plus avoir déjà traitées.&lt;/p&gt;
&lt;p&gt;Et effectivement, un peu plus loin, je vois des &lt;strong&gt;commentaires similaires&lt;/strong&gt; à ceux que je suis en train d'écrire. Les termes sont un peu différents, car au fil des commentaires, j'ai fait évoluer certains termes ou la manière de commenter, mais en regardant de plus près, oui, c'est évident, il y a &lt;strong&gt;deux fois la même routine&lt;/strong&gt; dans la ROM.&lt;/p&gt;
&lt;p&gt;Je …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hier, en continuant le &lt;strong&gt;commentaire&lt;/strong&gt; systématique de la &lt;strong&gt;ROM&lt;/strong&gt; du &lt;strong&gt;VG5000µ&lt;/strong&gt;, j'ai eu une impression de déjà-vu. Il me semblait bien avoir déjà commenté la partie « redéfinir un caractère étendu » (commandes &lt;code&gt;SETE&lt;/code&gt; et &lt;code&gt;SETG&lt;/code&gt; en BASIC).&lt;/p&gt;
&lt;p&gt;L'impression persiste, voire s’accroît, au fur et à mesure et je me décide à aller voir dans ce que j'ai déjà commenté. J'ai commencé, lentement, ce commentaire en août 2017, avec moult pauses, mais aussi du « butinage ». Il y a donc des parties que je ne me rappelle plus avoir déjà traitées.&lt;/p&gt;
&lt;p&gt;Et effectivement, un peu plus loin, je vois des &lt;strong&gt;commentaires similaires&lt;/strong&gt; à ceux que je suis en train d'écrire. Les termes sont un peu différents, car au fil des commentaires, j'ai fait évoluer certains termes ou la manière de commenter, mais en regardant de plus près, oui, c'est évident, il y a &lt;strong&gt;deux fois la même routine&lt;/strong&gt; dans la ROM.&lt;/p&gt;
&lt;p&gt;Je ne sais pas si c'est quelque chose de connu, alors voici mes commentaires.&lt;/p&gt;
&lt;h3&gt;Le VDP&lt;/h3&gt;
&lt;p&gt;Le &lt;strong&gt;Video Display Processor&lt;/strong&gt; du VG5000µ, un &lt;strong&gt;EF9345&lt;/strong&gt;, est utilisé par le BASIC de manière généralement indirecte. Les commandes comme les changement de couleur, de type de caractères ou encore de position du curseur, modifient des &lt;em&gt;registres&lt;/em&gt; internes en RAM. Ces &lt;em&gt;registres&lt;/em&gt; sont juste des emplacements réservés dans la RAM principale, celle accessible au Z80, ils n'ont rien de spécial.&lt;/p&gt;
&lt;p&gt;Ces registres se trouvent à partir de &lt;code&gt;$47fa&lt;/code&gt; et pointés en tout temps par le registre IX.&lt;/p&gt;
&lt;p&gt;Le BASIC maintient aussi une &lt;strong&gt;représentation de l'écran&lt;/strong&gt;, en &lt;code&gt;$4000&lt;/code&gt;, et afficher quelque chose en BASIC revient à modifier cette représentation d'écran, en se basant sur les registres BASIC.&lt;/p&gt;
&lt;p&gt;À chaque &lt;strong&gt;rafraîchissement&lt;/strong&gt; demandé par le VDP, via l'IRQ du Z80 et si le BASIC considère qu'il est temps de mettre à jour l'affichage, un &lt;strong&gt;transfert des données&lt;/strong&gt; est fait vers le VDP.&lt;/p&gt;
&lt;p&gt;C'est le fonctionnement de base.&lt;/p&gt;
&lt;p&gt;Cependant, la ROM contient aussi des routines qui s'adressent directement au VDP. On peut &lt;strong&gt;envoyer un caractère&lt;/strong&gt; dans la mémoire écran du VDP sans passer par la représentation maintenue par le BASIC. Bien évidemment, si on laisse faire le rafraîchissement du BASIC, cette donnée sera écrasée rapidement. On peut aussi &lt;strong&gt;lire un caractère&lt;/strong&gt; depuis la mémoire écran du VDP.&lt;/p&gt;
&lt;p&gt;Ces quatre routines, &lt;code&gt;putahl&lt;/code&gt;, &lt;code&gt;putici&lt;/code&gt;, &lt;code&gt;getahl&lt;/code&gt; et &lt;code&gt;getici&lt;/code&gt; ne sont &lt;strong&gt;jamais utilisées&lt;/strong&gt; par la ROM. Ce sont des routines mises à disposition pour l'utilisateur à une adresse fixe, dont le seul code est un branchement à l'implémentation.&lt;/p&gt;
&lt;p&gt;Une autre routine mise à disposition est &lt;code&gt;setext&lt;/code&gt;, qui s'occupe de la &lt;strong&gt;redéfinition d'un caractère&lt;/strong&gt; texte ou graphique dans le VDP. Le VDP est en effet configuré par défaut pour offrir 4 « polices de caractères », dont 2 en ROM, et 2 en RAM (celle accessible directement par le VDP). Les deux en RAM peuvent être modifiées via cette routine &lt;code&gt;setext&lt;/code&gt; en fournissant le numéro du caractère à changer et 10 octets qui représentent les 10 lignes d'affichage du caractère.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;setext&lt;/code&gt; se trouve en &lt;code&gt;$001b&lt;/code&gt; et branche immédiatement sur son implémentation en &lt;code&gt;$0d85&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;setext vs. SETE(T/G)&lt;/h3&gt;
&lt;p&gt;Le &lt;strong&gt;BASIC&lt;/strong&gt; offre deux commandes pour redéfinir les caractères : &lt;code&gt;SETET&lt;/code&gt;, pour &lt;strong&gt;redéfinir un caractère&lt;/strong&gt; &lt;em&gt;texte&lt;/em&gt;, et &lt;code&gt;SETEG&lt;/code&gt;, pour &lt;strong&gt;redéfinir un caractère&lt;/strong&gt; &lt;em&gt;graphique&lt;/em&gt;. La différence entre caractère texte et graphique sort du périmètre de cet article.&lt;/p&gt;
&lt;p&gt;Du point de vue de l'interpréteur BASIC, il n'y a qu'&lt;strong&gt;une seule commande&lt;/strong&gt; &lt;code&gt;SETE&lt;/code&gt;, qui vérifie si le caractère suivant est &lt;code&gt;T&lt;/code&gt; ou &lt;code&gt;G&lt;/code&gt;. On pourrait dire que la dernière lettre de la commande est vue par l'interpréteur comme son premier paramètre.&lt;/p&gt;
&lt;p&gt;L'exécution de &lt;code&gt;SETE&lt;/code&gt; se trouve en &lt;code&gt;$0ced&lt;/code&gt; dans la ROM BASIC.&lt;/p&gt;
&lt;p&gt;On pourrait s'attendre à ce que &lt;code&gt;SETE&lt;/code&gt; utilise la routine &lt;code&gt;setext&lt;/code&gt;. Ou bien que les deux routines aient une partie commune. &lt;em&gt;Ce n'est pas le cas&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Des 141 octets de l'implémentation de &lt;code&gt;setext&lt;/code&gt;, environ 100 (à la louche) sont strictement identiques dans &lt;code&gt;SETE&lt;/code&gt;, routine qui elle pèse 160 octets (en incluant sa routine annexe, qu'elle est la seule à appeler).&lt;/p&gt;
&lt;h3&gt;Différences&lt;/h3&gt;
&lt;p&gt;Les deux routines font la même chose, dans le même ordre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Couper le rafraîchissement&lt;/strong&gt; de l'écran depuis sa représentation RAM,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Déterminer&lt;/strong&gt; si on veut un caractère graphique ou texte,&lt;/li&gt;
&lt;li&gt;Récupérer le &lt;strong&gt;numéro du caractère&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;Envoyer les &lt;strong&gt;commandes&lt;/strong&gt; au VDP pour préparer la définition,&lt;/li&gt;
&lt;li&gt;Envoyer les &lt;strong&gt;10 lignes&lt;/strong&gt; au VDP,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rétablir le rafraîchissement&lt;/strong&gt; de l'écran.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour &lt;code&gt;setext&lt;/code&gt;, c'est très simple, les informations sont dans le registre &lt;code&gt;A&lt;/code&gt; pour le caractère et son type, et &lt;code&gt;HL&lt;/code&gt; pointe vers les données.&lt;/p&gt;
&lt;p&gt;Pour &lt;code&gt;SETE&lt;/code&gt;, c'est un peu plus complexe. Le type de caractère est déterminé par la présence de &lt;code&gt;T&lt;/code&gt; ou &lt;code&gt;G&lt;/code&gt;, il y a une vérification de la validité du premier paramètre de la commande (numéro de caractère), puis la chaîne de caractères de description, suite de nombres hexadécimaux en ASCII, doit être décodée. C'est la raison pour laquelle la routine est plus longue.&lt;/p&gt;
&lt;p&gt;Cependant, le &lt;strong&gt;corps de la routine&lt;/strong&gt; qui envoie toutes les commandes est &lt;strong&gt;identique&lt;/strong&gt;, à la récupération de la donnée prêt. Et bien que les deux routines utilisent bien les mêmes appels pour envoyer une commande au VDP ou attendre que celui-ci soit prêt à recevoir une commande, il doit bien y avoir une centaine d'octets pouvant être mis en commun.&lt;/p&gt;
&lt;h3&gt;Pourquoi ?&lt;/h3&gt;
&lt;p&gt;Je n'ai pas d'explication à la duplication de cette routine. Il reste un peu de place inutilisé dans la ROM, et peut être qu'il n'était plus nécessaire d'optimiser la place prise et que c'est juste resté « comme ça ».&lt;/p&gt;
&lt;p&gt;Ce n'est pas, à mon avis, une question de performances avec &lt;code&gt;setext&lt;/code&gt; qui serait plus rapide. Elle l'est, en effet, mais pourrait l'être encore plus. En effet, &lt;code&gt;setext&lt;/code&gt; garde de &lt;code&gt;SETE&lt;/code&gt; le fait de « retourner » chaque octet des descriptions de ligne pour les passer d'une visualisation humaine au format demandé par le VDP. La suite de commandes à envoyer pourraient aussi être rendue plus rapide à l'aide d'un buffer de commandes et l'utilisation de la routine &lt;code&gt;regst&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Amélioration ?&lt;/h3&gt;
&lt;p&gt;Une amélioration possible de la ROM serait de &lt;strong&gt;réécrire ces deux routines&lt;/strong&gt;. Il y aurait peut-être même moyen de profiter de la place gagnée pour caser deux commandes &lt;code&gt;PSET&lt;/code&gt; et &lt;code&gt;PRESET&lt;/code&gt;, qui font cruellement défaut sur le VG5000µ.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="Affichage"></category></entry><entry><title>Considérations sur le langage LOGO</title><link href="https://www.triceraprog.fr/considerations-sur-le-langage-logo.html" rel="alternate"></link><published>2020-08-15T00:00:00+02:00</published><updated>2020-08-15T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-08-15:/considerations-sur-le-langage-logo.html</id><summary type="html">&lt;p&gt;Quand je vois passer des mentions du langage &lt;strong&gt;LOGO&lt;/strong&gt;, elles sont généralement peu flatteuses. C'est compréhensible, la plupart des personnes qui se souviennent de ce langage de programmation y ont été exposées pendant leurs jeunes années d'études, lors du &lt;strong&gt;Plan Informatique pour Tous&lt;/strong&gt;. Peu sont ceux qui ont creusé plus tard ce qu'ils avaient découverts au moyen d'ordinateurs poussifs et de cours pas toujours maîtrisés par des enseignants pas toujours bien convaincus.&lt;/p&gt;
&lt;p&gt;Mes quelques &lt;strong&gt;souvenirs&lt;/strong&gt; de séances en salle informatiques sont plutôt sur des activités de manipulation du crayon optique sur « Colorpaint ». Je ne sais plus si j'ai fait du &lt;strong&gt;LOGO&lt;/strong&gt; en classe, mais c'est probable. Je me souviens cependant avec netteté la rencontre avec un professeur, lors de la fréquentation d'un « &lt;strong&gt;club informatique&lt;/strong&gt; » pendant des vacances, qui pour une raison ou une autre (mon intérêt enthousiaste à la programmation ?) m'a donné quelques cours de &lt;strong&gt;LOGO&lt;/strong&gt;. Et lors d'une conversation …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Quand je vois passer des mentions du langage &lt;strong&gt;LOGO&lt;/strong&gt;, elles sont généralement peu flatteuses. C'est compréhensible, la plupart des personnes qui se souviennent de ce langage de programmation y ont été exposées pendant leurs jeunes années d'études, lors du &lt;strong&gt;Plan Informatique pour Tous&lt;/strong&gt;. Peu sont ceux qui ont creusé plus tard ce qu'ils avaient découverts au moyen d'ordinateurs poussifs et de cours pas toujours maîtrisés par des enseignants pas toujours bien convaincus.&lt;/p&gt;
&lt;p&gt;Mes quelques &lt;strong&gt;souvenirs&lt;/strong&gt; de séances en salle informatiques sont plutôt sur des activités de manipulation du crayon optique sur « Colorpaint ». Je ne sais plus si j'ai fait du &lt;strong&gt;LOGO&lt;/strong&gt; en classe, mais c'est probable. Je me souviens cependant avec netteté la rencontre avec un professeur, lors de la fréquentation d'un « &lt;strong&gt;club informatique&lt;/strong&gt; » pendant des vacances, qui pour une raison ou une autre (mon intérêt enthousiaste à la programmation ?) m'a donné quelques cours de &lt;strong&gt;LOGO&lt;/strong&gt;. Et lors d'une conversation dans laquelle j'avais du mentionner que je programmais en BASIC, il m'a dit cette phrase qui est restée gravée dans ma mémoire « &lt;em&gt;le LOGO est bien plus puissant que le BASIC&lt;/em&gt; ».&lt;/p&gt;
&lt;p&gt;Je me souviens que cette phrase m'avait &lt;strong&gt;intriguée&lt;/strong&gt;, mais pas forcément &lt;strong&gt;convaincue&lt;/strong&gt;. Et de retour chez moi, j'ai continué mes aventures en &lt;strong&gt;BASIC&lt;/strong&gt;. J'ai croisé &lt;strong&gt;LOGO&lt;/strong&gt; quelques autres fois, de loin, sans m'y attarder.&lt;/p&gt;
&lt;p&gt;Ce n'est que beaucoup plus tard, quand j'ai commencé à faire de la programmation mon métier, que j'ai repensé à cette phrase. J'ai regardé ce qu'était LOGO de manière plus expérimentée et j'ai compris. J'ai compris la justesse de l'assertion. LOGO était bien autrement plus puissant que le BASIC. Mais d'une manière que je ne pouvais pas comprendre auparavant.&lt;/p&gt;
&lt;p&gt;C'est que la notion de « &lt;strong&gt;puissance&lt;/strong&gt; » appliquée à un langage, ainsi qu'à son environnement, revêt de nombreux aspects. Cela peut être la &lt;strong&gt;vitesse d'exécution&lt;/strong&gt; du programme, la &lt;strong&gt;facilité d'écriture&lt;/strong&gt;, les &lt;strong&gt;possibilités d'interactivité&lt;/strong&gt; avec la machine, la diversité des &lt;strong&gt;structures&lt;/strong&gt; de &lt;strong&gt;code&lt;/strong&gt; et de &lt;strong&gt;données&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sur des ordinateurs 8 bits, la &lt;strong&gt;vitesse d'exécution&lt;/strong&gt; du BASIC l'emporte haut la main, même sur des BASIC interprétés comme ils l'étaient en majorité.&lt;/p&gt;
&lt;p&gt;Sur la &lt;strong&gt;facilité d'écriture&lt;/strong&gt;, le BASIC est aussi très simple. C'était son but initial. LOGO n'est pas particulièrement complexe à écrire, mais comporte quelques étrangetés syntaxiques et pièges dont je parlerai dans un autre article. Et LOGO est aussi un peu plus verbeux.&lt;/p&gt;
&lt;p&gt;En &lt;strong&gt;possibilité d'interaction&lt;/strong&gt; avec la machine, BASIC l'emporte probablement. Tous les LOGO ne se valent pas, mais l'orientation pédagogique sur les machines 8 bits poussaient les concepteurs à offrir essentiellement des manipulations de l'écran via la tortue, et quelques sons. BASIC, en tant que porte d'entrée de la machine, était souvent dotés des instructions nécessaires pour en démontrer ses capacités. Avec de notables exceptions cependant, mais ceci est une autre histoire.&lt;/p&gt;
&lt;p&gt;Vient ensuite la &lt;strong&gt;structure de code et de données&lt;/strong&gt;. Et c'est là que LOGO renverse BASIC d'une pichenette. Le BASIC de l'époque est très linéaire, son édition se fait encore par numéro de lignes, sans labels. La structuration est possible bien entendu, mais les outils sont maigres. Niveau structure de donnée, le BASIC connaît le tableau multidimensionnel de taille fixe... et c'est tout.&lt;/p&gt;
&lt;p&gt;LOGO arrive avec ses &lt;strong&gt;fonctions&lt;/strong&gt; qui supportent la &lt;strong&gt;récursivité&lt;/strong&gt;, avec des &lt;strong&gt;contextes locaux&lt;/strong&gt;, un &lt;strong&gt;nommage&lt;/strong&gt; des procédures et une &lt;strong&gt;édition&lt;/strong&gt; sans numéro de lignes, qui facilite les mises au point.&lt;/p&gt;
&lt;p&gt;Côté données, LOGO connaît la liste. Et avec une &lt;strong&gt;liste dynamique&lt;/strong&gt;, de nouveaux horizons s'étendent. Des listes de nombres, des listes de mots, des listes de listes, des listes de commandes à exécuter...&lt;/p&gt;
&lt;p&gt;L'&lt;strong&gt;expressivité&lt;/strong&gt; du langage est beaucoup plus intéressante, et les programmes plus &lt;strong&gt;concis&lt;/strong&gt;, plus &lt;strong&gt;clairs&lt;/strong&gt;. C'est en ce sens que LOGO était bien plus puissant.&lt;/p&gt;
&lt;p&gt;Mais tout ceci nécessite de la puissance de calcul et de la mémoire que les machines familiales de l'époque n'ont pas. Et cette malheureuse empreinte qui va rester principalement : &lt;em&gt;on ne fait rien de bien sérieux avec LOGO&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pour donner un petit aperçu de LOGO et de son évolution, j'ai réalisé une petite &lt;strong&gt;vidéo&lt;/strong&gt; (moins de 10 minutes) que vous pouvez voir ici.&lt;/p&gt;
&lt;div class="embed-yt text-center" data-video-id="1AeJQU_jibE" style="width: 560; height:315"&gt;
    &lt;div class="embed-yt-play"&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;(billet posté aussi sur &lt;a href="https://www.puupuu.org/dotclear/index.php?post/2020/08/15/Consid%C3%A9rations-sur-le-langage-LOGO"&gt;mon blog perso&lt;/a&gt;).&lt;/p&gt;</content><category term="Langages"></category><category term="Logo"></category><category term="Programmation"></category></entry><entry><title>Récréation 3D, Cartouche Atari 800</title><link href="https://www.triceraprog.fr/recreation-3d-cartouche-atari-800.html" rel="alternate"></link><published>2020-06-08T00:00:00+02:00</published><updated>2020-06-08T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-06-08:/recreation-3d-cartouche-atari-800.html</id><content type="html">&lt;p&gt;J'avais une cartouche « Atari Writer » qui traînait sur le bureau depuis quelques temps, et je voulais faire un exercice rapide de modélisation avec &lt;a href="https://www.blender.org/"&gt;Blender&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cela donne cette image, assez simple, mais qui a été un bon exercice.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tortue Jeulin T2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202006/20200606-Cartouche-Atari-AtariWriter-750.png"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Atari"></category><category term="Atari 800"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>VG5000µ, nombres aléatoires</title><link href="https://www.triceraprog.fr/vg5000m-nombres-aleatoires.html" rel="alternate"></link><published>2020-05-10T00:00:00+02:00</published><updated>2020-05-10T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-05-10:/vg5000m-nombres-aleatoires.html</id><summary type="html">&lt;p&gt;Comment donc les &lt;strong&gt;nombres aléatoires&lt;/strong&gt; sont-ils générés sur un &lt;strong&gt;VG5000µ&lt;/strong&gt;. C'est ce que je vous propose de suivre aujourd'hui en décortiquant le code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Afin de suivre&lt;/strong&gt;, il est important de comprendre comment les nombres sont stockés sur VG5000µ, et je vous propose pour cela un petit détour par &lt;a href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html"&gt;cet article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Petit rappel avant de commencer&lt;/strong&gt; : un générateur de nombres &lt;em&gt;aléatoires&lt;/em&gt; est une procédure qui émet une suite de nombres sur un intervalle, cette suite tentant d'avoir des propriétés intéressantes qui donnent l'&lt;strong&gt;illusion&lt;/strong&gt; de l'aléatoire. La suite est cependant parfaitement définie, même si pas toujours simple à suivre, et c'est ce que nous allons voir par la suite.&lt;/p&gt;
&lt;h3&gt;L'initialisation&lt;/h3&gt;
&lt;p&gt;Tout commence très tôt pour le générateur de nombres aléatoires. Dès &lt;strong&gt;l’initialisation&lt;/strong&gt; de la machine, une série de valeurs est copiée depuis la ROM vers les variables systèmes. Cela se passe en &lt;code&gt;$1071&lt;/code&gt;, juste après l'initialisation de l'affichage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Comment donc les &lt;strong&gt;nombres aléatoires&lt;/strong&gt; sont-ils générés sur un &lt;strong&gt;VG5000µ&lt;/strong&gt;. C'est ce que je vous propose de suivre aujourd'hui en décortiquant le code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Afin de suivre&lt;/strong&gt;, il est important de comprendre comment les nombres sont stockés sur VG5000µ, et je vous propose pour cela un petit détour par &lt;a href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html"&gt;cet article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Petit rappel avant de commencer&lt;/strong&gt; : un générateur de nombres &lt;em&gt;aléatoires&lt;/em&gt; est une procédure qui émet une suite de nombres sur un intervalle, cette suite tentant d'avoir des propriétés intéressantes qui donnent l'&lt;strong&gt;illusion&lt;/strong&gt; de l'aléatoire. La suite est cependant parfaitement définie, même si pas toujours simple à suivre, et c'est ce que nous allons voir par la suite.&lt;/p&gt;
&lt;h3&gt;L'initialisation&lt;/h3&gt;
&lt;p&gt;Tout commence très tôt pour le générateur de nombres aléatoires. Dès &lt;strong&gt;l’initialisation&lt;/strong&gt; de la machine, une série de valeurs est copiée depuis la ROM vers les variables systèmes. Cela se passe en &lt;code&gt;$1071&lt;/code&gt;, juste après l'initialisation de l'affichage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;initvalues&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0065&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;ramlow&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ldir&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il y a donc 101 valeurs ($65) copiées depuis &lt;code&gt;initvalues&lt;/code&gt; (&lt;code&gt;$1194&lt;/code&gt;) vers &lt;code&gt;ramlow&lt;/code&gt; ($4830). Parmi celles-ci, les suivantes sont copiés vers &lt;code&gt;$4844&lt;/code&gt; et nous intéressent aujourd'hui.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les &lt;strong&gt;trois premiers octets&lt;/strong&gt; sont les &lt;strong&gt;trois index&lt;/strong&gt; avec lesquels le générateur va jouer. Nous les appellerons les trois &lt;strong&gt;seeds&lt;/strong&gt;. Suivent 8 nombres plutôt grands, positifs et négatifs (le premier vaut &lt;code&gt;-26514538&lt;/code&gt;). Et enfin vient le nombre d'origine, qui vaut &lt;code&gt;0.8116351366043091&lt;/code&gt;, que vous pouvez retrouver sous sa forme arrondie en tapant &lt;code&gt;PRINT RND(0)&lt;/code&gt; dès l'allumage du VG5000µ.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tête sur VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202005/20200510-VG5000-RND-Boot.png"&gt;&lt;/p&gt;
&lt;p&gt;Cette table n'est pas la seule qui va être utilisée par le générateur. Il en existe &lt;strong&gt;une autre&lt;/strong&gt;, qui sera utilisée depuis la ROM, en &lt;code&gt;$093d&lt;/code&gt;, d'une longueur de 3.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;L'instruction RND&lt;/h3&gt;
&lt;p&gt;L'instruction &lt;code&gt;RND&lt;/code&gt; commence en &lt;code&gt;$090d&lt;/code&gt; par un petit &lt;strong&gt;préambule&lt;/strong&gt; qui vérifie l'argument passé à la fonction. Cet argument est disponible dans &lt;code&gt;FAC&lt;/code&gt;, l'accumulateur flottant (voir &lt;a href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html"&gt;précédemment&lt;/a&gt;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;inst_rnd:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;getsign&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_seed_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;reseed&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_gen&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl_to_fac&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_seed_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce préambule teste en premier lieu le &lt;strong&gt;signe de l'argument&lt;/strong&gt;. S'il est &lt;strong&gt;négatif&lt;/strong&gt;, la routine branche vers &lt;code&gt;reseed&lt;/code&gt;, que nous verrons &lt;strong&gt;plus loin&lt;/strong&gt;. C'est au passage un comportement qui n'est indiqué ni dans le manuel d'utilisation du VG5000µ, ni dans les « Clés pour VG5000 », qui donnent de fausses informations (je vous laisse regarder).&lt;/p&gt;
&lt;p&gt;Dans le cas du branchement, &lt;code&gt;HL&lt;/code&gt; point vers la &lt;strong&gt;seed 2&lt;/strong&gt; (et je ne vois aucun intérêt à ce que cela ne soit pas fait après le branchement...)&lt;/p&gt;
&lt;p&gt;Si l'argument est &lt;strong&gt;nul&lt;/strong&gt; ou &lt;strong&gt;positif&lt;/strong&gt;, alors la nombre pointé par &lt;code&gt;HL&lt;/code&gt;, qui est la variable système du dernier nombre généré ,est copié dans &lt;code&gt;FAC&lt;/code&gt;. Souvenez-vous, c'est à cette adresse qu'a été placé à l'initialisation le nombre &lt;code&gt;0.8116351&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On refait pointer &lt;code&gt;HL&lt;/code&gt; vers la &lt;strong&gt;seed 2&lt;/strong&gt; puis, si l’argument était &lt;code&gt;0&lt;/code&gt;, on sort de la routine immédiatement (le flag &lt;code&gt;Z&lt;/code&gt;éro a été conservé depuis &lt;code&gt;rst getsign&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;Le calcul&lt;/h4&gt;
&lt;p&gt;Puisqu'on est à présent dans le cas où l’&lt;strong&gt;argument est positif&lt;/strong&gt;, il convient de &lt;strong&gt;générer un nouveau nombre&lt;/strong&gt;. Ce nouveau nombre est basé sur, d'une part, le nombre généré précédemment, et d'autre part, les trois index qui avaient été initialisés à zéro (voir ci-dessus).&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;Première étape&lt;/strong&gt;&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl_to_bcde&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;fp_mul&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La &lt;strong&gt;première section&lt;/strong&gt; du code précédent récupère l'index &lt;strong&gt;seed 2&lt;/strong&gt; en l'incrémentant de 1. En effet, &lt;code&gt;A&lt;/code&gt; contient 1 depuis l'appel à &lt;code&gt;getsign&lt;/code&gt;. Le résultat est pris modulo 8 et remonté en RAM.&lt;/p&gt;
&lt;p&gt;Au passage, &lt;code&gt;B&lt;/code&gt; est initialisé à &lt;code&gt;0&lt;/code&gt; pour que &lt;code&gt;BC&lt;/code&gt; puisse servir d'index, et &lt;code&gt;HL&lt;/code&gt; va pointer un cran plus loin, sur le début de la table des coefficients initialisés au boot (la table des 8 valeurs).&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;seconde section&lt;/strong&gt; calcul le pointeur dans cette table en quadruplant &lt;code&gt;A&lt;/code&gt;, qui est l'index, en format &lt;code&gt;BC&lt;/code&gt; comme index à ajouter au pointeur de base &lt;code&gt;HL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L'appel &lt;code&gt;hl_to_bcde&lt;/code&gt; copie le nombre pointé dans la table vers &lt;code&gt;BCDE&lt;/code&gt;, puis l'appel à &lt;code&gt;fp_mul&lt;/code&gt; effectue la multiplication avec le contenu de &lt;code&gt;FAC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;cette première étape est donc une multiplication du précédent nombre généré par un autre nombre, fixe, pris dans une table dans 8 valeurs tour à tour&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Le tout premier appel à RND(1) va multiplier &lt;code&gt;16129081&lt;/code&gt; (&lt;code&gt;$98 $76 $1c $39) avec&lt;/code&gt;0.8116351366043091&lt;code&gt;(&lt;/code&gt;$80 $4f $c7 $52`).&lt;/p&gt;
&lt;p&gt;Cela donne &lt;code&gt;13090929&lt;/code&gt; (&lt;code&gt;$98 $47$c0 $71&lt;/code&gt;). Cela peut se vérifier dans &lt;code&gt;FAC&lt;/code&gt; (&lt;code&gt;$49e6&lt;/code&gt;). Attention, le nombre est octet par octet dans le sens inverse à celui que j'utilise ici.&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;Seconde étape&lt;/strong&gt;&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;rnd_seed_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;adc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rnd_seed_1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;fp_add_hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;afterreseed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;fac_to_bcde&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La &lt;strong&gt;seconde étape&lt;/strong&gt; se divise elle aussi en &lt;strong&gt;deux sections&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Dans la &lt;strong&gt;première section&lt;/strong&gt;, on récupère la &lt;strong&gt;seed 1&lt;/strong&gt;, qui est incrémentée de 1 et modulo 4. Cependant, la valeur 0 est interdite. Par une comparaison avec 1 et un ajout à 0 (via &lt;code&gt;B&lt;/code&gt;) avec retenue, si l'index était à 0, alors il est poussé à 1.&lt;/p&gt;
&lt;p&gt;C'est donc en fait un index &lt;strong&gt;modulo 3&lt;/strong&gt; que l'on obtient.&lt;/p&gt;
&lt;p&gt;Et cet index forme un pointeur via &lt;code&gt;HL&lt;/code&gt; de manière similaire à l'étape précédente, dans la &lt;strong&gt;table de trois valeurs&lt;/strong&gt; de la &lt;code&gt;ROM&lt;/code&gt; mentionné au début de l'article.&lt;/p&gt;
&lt;p&gt;Cette valeur est alors &lt;strong&gt;ajoutée&lt;/strong&gt; à &lt;code&gt;FAC&lt;/code&gt;. L'appel à &lt;code&gt;fp_add_hl&lt;/code&gt; se charge de l'étape intermédiaire de chargement de la valeur dans &lt;code&gt;BCDE&lt;/code&gt;. Puis le résultat est ramené dans &lt;code&gt;BCDE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le label est un branchement venant du &lt;code&gt;reseed&lt;/code&gt; que nous verrons plus loin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;cette seconde étape est une addition du nombre obtenue à la première étape avec un des trois nombres pris dans la deuxième table, pris tour à tour&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Le tout premier appel additionne &lt;code&gt;13090929&lt;/code&gt; (&lt;code&gt;$98 $47 $c0 $71&lt;/code&gt; ) avec &lt;code&gt;4.626181e-08&lt;/code&gt; (&lt;code&gt;$68 $b1 $46 $68&lt;/code&gt;). Ce second nombre est bien trop petit par rapport au premier. Cette addition ne change rien... dans ce cas-ci. Nous verrons plus tard à quoi cette addition peut servir.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Troisième étape&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dans cette &lt;strong&gt;troisième étape&lt;/strong&gt;, le générateur fait des &lt;strong&gt;mélanges&lt;/strong&gt;. Les 8 bits de poids les plus faibles sont mis de côté et les 8 bits de poids fort sont placés dans les 8 bits de poids faible.&lt;/p&gt;
&lt;p&gt;Les 8 bits mis de côté sont &lt;code&gt;XOR&lt;/code&gt;és avec &lt;code&gt;b01001111&lt;/code&gt;. Ce qui signifie que certains bits sont inversés. Puis le résultat est placé dans les 8 bits de poids fort.&lt;/p&gt;
&lt;p&gt;Cette opération ne me semble pas avoir de sens arithmétique. Cela semble être juste un mélange. Peut-être pour amener de l'entropie dans les bits de poids faible... Peut-être.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;cet étape mélange les parties de la mantisse et change quelques bits&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Le nombre est à présent &lt;code&gt;12501063&lt;/code&gt; (&lt;code&gt;$98 $3e $c0 $47&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Étape intermédiaire&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette étape profite que &lt;code&gt;HL&lt;/code&gt; pointe actuellement (depuis la récupération de &lt;code&gt;FAC&lt;/code&gt; dans &lt;code&gt;BCDE&lt;/code&gt;) sur l'octet après &lt;code&gt;FAC&lt;/code&gt; pour &lt;strong&gt;préparer le terrain&lt;/strong&gt; pour plus tard. Cet octet contient le complément à 1 du bit de signe du nombre de &lt;code&gt;FAC&lt;/code&gt;. En mettant cet octet à &lt;code&gt;$80&lt;/code&gt;, on force la &lt;strong&gt;valeur&lt;/strong&gt; à être &lt;strong&gt;positive&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HL&lt;/code&gt; pointe ensuite sur l'&lt;strong&gt;octet précédent&lt;/strong&gt;, l'exposant, et met celui-ci à &lt;code&gt;$80&lt;/code&gt;, c'est-à-dire $2^ 0$ (voir l'article sur les nombres, toujours).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;le nombre final sera un nombre positif et l'exposant est fixé à $2^0 = 1$&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pas d’influence, pour le moment sur le nombre tenu dans &lt;code&gt;BCDE&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Quatrième étape&lt;/strong&gt;*&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_seed_0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_cnt&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;C'est la &lt;strong&gt;dernière étape&lt;/strong&gt; du calcul. Dans la &lt;strong&gt;première partie&lt;/strong&gt;, la &lt;strong&gt;seed 0&lt;/strong&gt; est incrémentée et récupérée dans &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si la soustraction par &lt;code&gt;171&lt;/code&gt; (&lt;code&gt;$ab&lt;/code&gt;) n'est pas nulle, on branche plus loin à l'étape finale. Sinon, le résultat (&lt;code&gt;0&lt;/code&gt;) est replacé dans la &lt;strong&gt;seed 0&lt;/strong&gt;. C'est donc un compteur jusqu'à &lt;code&gt;171&lt;/code&gt; qui, lorsqu'il atteint cette valeur, &lt;strong&gt;modifie légèrement&lt;/strong&gt; la mantisse.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;premier&lt;/strong&gt; et le &lt;strong&gt;troisième&lt;/strong&gt; octets de la mantisse sont &lt;strong&gt;incrémentés&lt;/strong&gt;, celui du &lt;strong&gt;milieu décrémenté&lt;/strong&gt;, sans se soucier de débordements éventuels.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;une fois tous les 171 tirages, la mantisse est modifiée légèrement&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Comme ici, c'est le premier tirage, il ne se passe rien.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Étape finale&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;rnd_cnt:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bcde_norm&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;rnd_gen&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;cpy_faclsb_hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La &lt;strong&gt;mantisse&lt;/strong&gt; a été &lt;strong&gt;générée&lt;/strong&gt;, l'&lt;strong&gt;exposant&lt;/strong&gt; est &lt;strong&gt;là&lt;/strong&gt;. Mais tout nombre dans &lt;code&gt;FAC&lt;/code&gt; en sorti de routine doit être normalisé.&lt;/p&gt;
&lt;p&gt;Comme indiqué dans l'article précédent sur la représentation des nombres, cela signifie que la mantisse et l'exposant vont être modifiée afin d'obtenir une mantisse avec un premier bit à 1 implicite, lui-même remplacé par le bit de signe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MAIS&lt;/strong&gt; ! Il y a un twist ! La routine &lt;code&gt;bcde_norm&lt;/code&gt; n'attend pas en entrée un nombre &lt;code&gt;BCDE&lt;/code&gt;, mais une mantisse 32 bits &lt;code&gt;CDEB&lt;/code&gt;. L'exposant du nombre actuel va donc se retrouver... en partie la moins significative du nombre, afin de nourrir, en quelque sorte, la partie droite de la mantisse lors de l'éventuel décalage vers la gauche.&lt;/p&gt;
&lt;p&gt;C'est peut-être un peu obscure : je donne un exemple dans le résumé.&lt;/p&gt;
&lt;p&gt;En sortie de normalisation, le nombre est bien dans &lt;code&gt;FAC&lt;/code&gt;. Le contenu de &lt;code&gt;FAC&lt;/code&gt; est alors copié à l'emplacement du dernier nombre généré.&lt;/p&gt;
&lt;p&gt;C'est terminé !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Résumé&lt;/strong&gt; : &lt;em&gt;mise en forme du nombre, à la fois dans &lt;code&gt;FAC&lt;/code&gt; comme résultat de la fonction, et de côté pour servir de base au prochain nombre généré (ou pour être retourné en case de &lt;code&gt;RND(0)&lt;/code&gt;)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Nous en étions à &lt;code&gt;$98 $3e $c0 $47&lt;/code&gt;. Mais la normalisation s'attend à une mantisse 32 bits, et c'est donc comme ça que va être perçue la mantisse : &lt;code&gt;$3e $c0 $47 $98&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La normalisation doit &lt;strong&gt;déplacer la mantisse à gauche&lt;/strong&gt; jusqu'à ce que le bit de &lt;strong&gt;poids fort&lt;/strong&gt; soit à &lt;code&gt;1&lt;/code&gt;. Il va falloir deux étapes pour cela :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;de &lt;code&gt;$3ec04798&lt;/code&gt; à &lt;code&gt;$7d808f30&lt;/code&gt;, puis&lt;/li&gt;
&lt;li&gt;de &lt;code&gt;$7d808f30&lt;/code&gt; à &lt;code&gt;$fb011e60&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comme le bit de poids fort du dernier octet n'est pas à 1, il n'y a pas d'arrondi. Cet octet est abandonné, le bit de signe et l'exposant corrigé par le nombre d'étapes ($80 - 2 donne $7e).&lt;/p&gt;
&lt;p&gt;Au final, nous avons obtenu : &lt;code&gt;$7e $7b $01 $1e&lt;/code&gt;, soit &lt;code&gt;0.245121&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tête sur VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202005/20200510-VG5000-RND-Next.png"&gt;&lt;/p&gt;
&lt;h3&gt;Suppléments&lt;/h3&gt;
&lt;h4&gt;Re-seed&lt;/h4&gt;
&lt;p&gt;Si l'&lt;strong&gt;argument&lt;/strong&gt; de &lt;code&gt;RND()&lt;/code&gt; est &lt;strong&gt;négatif&lt;/strong&gt;, alors un branchement a lieu sur une routine de réinitialisation du générateur.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;reseed:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;afterreseed&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À l'arrivée dans cette partie, &lt;code&gt;HL&lt;/code&gt; pointe sur &lt;strong&gt;seed 2&lt;/strong&gt; et &lt;code&gt;A&lt;/code&gt; est égal à &lt;code&gt;$FF&lt;/code&gt;. Ce qui a pour résultat de mettre les trois octets à &lt;code&gt;$FF&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le branchement ramène dans le générateur à la &lt;strong&gt;fin de la seconde étape&lt;/strong&gt;, c'est-à-dire après la multiplication et l'addition. Ce qui est dans &lt;code&gt;FAC&lt;/code&gt; (l'argument négatif de &lt;code&gt;RND()&lt;/code&gt;) est ramené dans &lt;code&gt;BCDE&lt;/code&gt; et le reste des étapes est effectué.&lt;/p&gt;
&lt;p&gt;C'est donc une &lt;strong&gt;nouvelle séquence&lt;/strong&gt; qui démarre, dépendante de l'argument passé à &lt;code&gt;RND()&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Cas de l'addition&lt;/h4&gt;
&lt;p&gt;Revenons sur la &lt;strong&gt;seconde étape&lt;/strong&gt;, l'addition avec un nombre tout petit. Dans l'exemple que nous avons suivi pendant l'article, l'addition ne servait à rien, car la différence entre les exposants était trop grand et donc le nombre à addition non significatif.&lt;/p&gt;
&lt;p&gt;La question à se poser est donc : &lt;em&gt;dans quels cas ces nombres deviennent-ils significatifs ?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Le plus petit d'entre eux est : &lt;code&gt;$68 $46 $b1 $68&lt;/code&gt; qui a pour exposant &lt;code&gt;$68&lt;/code&gt;. C'est-à-dire &lt;code&gt;$80&lt;/code&gt; - 24.&lt;/p&gt;
&lt;p&gt;Il faut donc un nombre strictement inférieur à &lt;code&gt;$00 $00 $00 $80&lt;/code&gt; (&lt;code&gt;0.5&lt;/code&gt;) pour que l'addition soit intéressante.&lt;/p&gt;
&lt;p&gt;Sauf que... juste avant l'addition, la &lt;strong&gt;multiplication&lt;/strong&gt; a été faite avec un nombre dont l'&lt;strong&gt;exposant&lt;/strong&gt; était au minimum &lt;code&gt;$98&lt;/code&gt;. Puisque dans une multiplication, les exposants s'ajoutent, cela implique que seuls des nombres avec un exposants à '$68' initialement vont être assez petits après la multiplication et être modifiés par l'addition.&lt;/p&gt;
&lt;p&gt;C'est quelque chose de facile à déclencher en modifiant à la main le dernier nombre généré en mémoire. Mais est-ce que cela se passe si on laisse le générateur se dérouler normalement ?&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;expérience&lt;/strong&gt; simple avec un &lt;strong&gt;debuggeur&lt;/strong&gt; en mettant un point d'arrêt dans le code d'addition et en faisant tourner le générateur montre que... &lt;strong&gt;non&lt;/strong&gt;. Cela n'arrive pas. Ou alors assez rarement pour résister à l'expérience.&lt;/p&gt;
&lt;p&gt;Il est temps de se poser la question des &lt;strong&gt;bornes maximales&lt;/strong&gt; et &lt;strong&gt;minimales&lt;/strong&gt; des nombres générés.&lt;/p&gt;
&lt;p&gt;Mais vu la longueur de l'article, ce sera pour le prochain...&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="BASIC"></category><category term="ROM"></category><category term="Nombres"></category></entry><entry><title>VG5000µ, jouer avec les nombres</title><link href="https://www.triceraprog.fr/vg5000m-jouer-avec-les-nombres.html" rel="alternate"></link><published>2020-05-09T00:00:00+02:00</published><updated>2020-05-09T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-05-09:/vg5000m-jouer-avec-les-nombres.html</id><summary type="html">&lt;p&gt;Suite à l'&lt;a href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html"&gt;article précédent&lt;/a&gt;, j'ai mis sur le dépôt &lt;a href="https://github.com/Triceraprog/vg5000_tools"&gt;GitHub&lt;/a&gt; un petit &lt;strong&gt;utilitaire Python&lt;/strong&gt; qui reproduit les conversions entre la valeur du nombre et son codage en 4 octets.&lt;/p&gt;
&lt;p&gt;Parfois, voir du code est plus simple qu'un long discours.&lt;/p&gt;
&lt;p&gt;Et parce qu'on ne sait jamais trop quel sera la vie future du dépôt, voici le code des deux principales fonctions de l'outil.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Takes the current number, and returns the next byte encoding it with the reminder of the number to encode. &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Gets a number, returns it&amp;#39;s encoded four bytes (memory layout, so exponent at the end).&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="c1"&gt;# If the number is zero, the encoding is immediate.&lt;/span&gt;
    &lt;span class="c1"&gt;# In fact, only the exponent has to be 0.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Gets the sign from the number for later encoding …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Suite à l'&lt;a href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html"&gt;article précédent&lt;/a&gt;, j'ai mis sur le dépôt &lt;a href="https://github.com/Triceraprog/vg5000_tools"&gt;GitHub&lt;/a&gt; un petit &lt;strong&gt;utilitaire Python&lt;/strong&gt; qui reproduit les conversions entre la valeur du nombre et son codage en 4 octets.&lt;/p&gt;
&lt;p&gt;Parfois, voir du code est plus simple qu'un long discours.&lt;/p&gt;
&lt;p&gt;Et parce qu'on ne sait jamais trop quel sera la vie future du dépôt, voici le code des deux principales fonctions de l'outil.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Takes the current number, and returns the next byte encoding it with the reminder of the number to encode. &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Gets a number, returns it&amp;#39;s encoded four bytes (memory layout, so exponent at the end).&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="c1"&gt;# If the number is zero, the encoding is immediate.&lt;/span&gt;
    &lt;span class="c1"&gt;# In fact, only the exponent has to be 0.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Gets the sign from the number for later encoding&lt;/span&gt;
    &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x80&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# We encode only positive numbers&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Shift the number so that the first fractional part bit&lt;/span&gt;
    &lt;span class="c1"&gt;# of the mantissa is 1 (0.1 binary is 0.5 decimal)&lt;/span&gt;
    &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Gets the three bytes encoding the mantissa&lt;/span&gt;
    &lt;span class="n"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;o3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Clears the most significant bit&lt;/span&gt;
    &lt;span class="c1"&gt;# and replace it by the sign bit&lt;/span&gt;
    &lt;span class="n"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;=&lt;/span&gt; &lt;span class="mh"&gt;0x7F&lt;/span&gt;
    &lt;span class="n"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;sign&lt;/span&gt;

    &lt;span class="c1"&gt;# Encode exponent&lt;/span&gt;
    &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;

    &lt;span class="c1"&gt;# Returns an array (Z80 memory layout)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Takes four encoded bytes in the memory layout, and returns the decoded value. &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="c1"&gt;# Gets the exponent&lt;/span&gt;
    &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# If it&amp;#39;s 0, we&amp;#39;re done. The value is 0.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# Extract value from the exponent&lt;/span&gt;
    &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;

    &lt;span class="c1"&gt;# Extract the sign bit from MSB&lt;/span&gt;
    &lt;span class="n"&gt;sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x80&lt;/span&gt;

    &lt;span class="c1"&gt;# Sets the most significant bit implied 1 in the mantissa&lt;/span&gt;
    &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mh"&gt;0x80&lt;/span&gt;

    &lt;span class="c1"&gt;# Reconstruct the mantissa&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Divide the number by the mantissa, corrected&lt;/span&gt;
    &lt;span class="c1"&gt;# by the 24 bits we just shifted while reconstructing it&lt;/span&gt;
    &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Apply the sign to the whole value&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mantissa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mantissa&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mantissa&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="BASIC"></category><category term="Nombres"></category><category term="Python"></category></entry><entry><title>VG5000µ, traitement des nombres</title><link href="https://www.triceraprog.fr/vg5000m-traitement-des-nombres.html" rel="alternate"></link><published>2020-05-08T00:00:00+02:00</published><updated>2020-05-08T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-05-08:/vg5000m-traitement-des-nombres.html</id><summary type="html">&lt;p&gt;Lors d'une discussion sur le forum &lt;strong&gt;system-cfg&lt;/strong&gt; à propos de la fonction &lt;code&gt;RND&lt;/code&gt; une question a été posée sur le format des nombres dans le VG5000µ. C'est une question qui revient et que je voulais documenter pour mémoire, me posant régulièrement la question et oubliant juste après...&lt;/p&gt;
&lt;h3&gt;Différents formats&lt;/h3&gt;
&lt;p&gt;Distinguons déjà deux choses : les nombres manipulés par le &lt;strong&gt;système&lt;/strong&gt;, et les nombres manipulés par le &lt;strong&gt;BASIC&lt;/strong&gt;. Les premiers sont de diverses formes en fonction des besoins, de type entier, signé ou pas, sur 8 ou 16 bits la plupart du temps. Il n'y a pas grand chose à dire sur eux.&lt;/p&gt;
&lt;p&gt;Les seconds sont ceux &lt;strong&gt;manipulés par le BASIC&lt;/strong&gt;, qui est un BASIC Microsoft sur VG5000µ, et ce qui sera valide dans cet article le sera pour d'autres machines avec &lt;strong&gt;BASIC Microsoft&lt;/strong&gt; et un processeur &lt;strong&gt;Z80&lt;/strong&gt;. Au moins dans les grandes lignes, mais pour ce que j'ai vu en comparant …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Lors d'une discussion sur le forum &lt;strong&gt;system-cfg&lt;/strong&gt; à propos de la fonction &lt;code&gt;RND&lt;/code&gt; une question a été posée sur le format des nombres dans le VG5000µ. C'est une question qui revient et que je voulais documenter pour mémoire, me posant régulièrement la question et oubliant juste après...&lt;/p&gt;
&lt;h3&gt;Différents formats&lt;/h3&gt;
&lt;p&gt;Distinguons déjà deux choses : les nombres manipulés par le &lt;strong&gt;système&lt;/strong&gt;, et les nombres manipulés par le &lt;strong&gt;BASIC&lt;/strong&gt;. Les premiers sont de diverses formes en fonction des besoins, de type entier, signé ou pas, sur 8 ou 16 bits la plupart du temps. Il n'y a pas grand chose à dire sur eux.&lt;/p&gt;
&lt;p&gt;Les seconds sont ceux &lt;strong&gt;manipulés par le BASIC&lt;/strong&gt;, qui est un BASIC Microsoft sur VG5000µ, et ce qui sera valide dans cet article le sera pour d'autres machines avec &lt;strong&gt;BASIC Microsoft&lt;/strong&gt; et un processeur &lt;strong&gt;Z80&lt;/strong&gt;. Au moins dans les grandes lignes, mais pour ce que j'ai vu en comparant une paire d'entre eux, souvent jusque dans les détails. Ces BASIC ne différent que de petites modifications ici ou là, de l'ordre de l'optimisation.&lt;/p&gt;
&lt;p&gt;Le BASIC lui-même traite plusieurs types de nombres. On a déjà vu la manière dont il traitant de manière particulière les &lt;strong&gt;numéros de lignes&lt;/strong&gt; après un &lt;code&gt;GOTO&lt;/code&gt; ou un &lt;code&gt;GOSUB&lt;/code&gt; dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-un-listing-en-basic.html"&gt;article sur l'arrangement des lignes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le format qui nous intéresse aujourd'hui est celui &lt;strong&gt;utilisé pour les calculs&lt;/strong&gt;, ainsi que celui utilisé dans les &lt;strong&gt;variables numériques&lt;/strong&gt;. Dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-les-variables-en-memoire.html"&gt;article sur les variables&lt;/a&gt;, j'étudiais comment les variables étaient créées, avec leur nom suivis de 4 octets. Mais que contiennent ces 4 octets ?&lt;/p&gt;
&lt;h3&gt;Le format flottant&lt;/h3&gt;
&lt;p&gt;Tous les nombres traités par le BASIC VG5000µ pour les calculs et les variables sont dans un format a &lt;strong&gt;virgule flottante&lt;/strong&gt;. C'était déjà le cas avec le BASIC créé initialement à &lt;strong&gt;Dartmouth&lt;/strong&gt;. L'idée était que les utilisateurs n'avaient pas à se poser de question sur le format interne, et pouvaient utiliser les nombres &lt;strong&gt;naturellement&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Plus tard, pour des raisons de performance (vitesse et consommation mémoire), des versions de BASIC ont ajouté un typage sur ces nombres. Comme le suffit &lt;code&gt;%&lt;/code&gt; des variables numériques qui indiquent que la variable contient un nombre entier.&lt;/p&gt;
&lt;p&gt;Sur le VG5000µ, &lt;strong&gt;pas de typage de nombre&lt;/strong&gt;. Tout est au même format. Je nommerai ce format le format &lt;code&gt;BCDE&lt;/code&gt; par la suite. &lt;code&gt;BCDE&lt;/code&gt; car il est manipulé la plupart du temps à travers cette paire de registres (&lt;code&gt;BC&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt;). &lt;code&gt;BCDE&lt;/code&gt; désigne donc aussi &lt;strong&gt;l'emplacement du nombre&lt;/strong&gt; traité dans certaines situations.&lt;/p&gt;
&lt;p&gt;Pour les calculs, le BASIC utilise un &lt;strong&gt;accumulateur flottant&lt;/strong&gt;, que je nommerai &lt;code&gt;FAC&lt;/code&gt; par la suite (&lt;strong&gt;Floating point ACumulator&lt;/strong&gt;). L'essentiel du format est le même que lorsqu'il est au format &lt;code&gt;BCDE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L'accumulateur &lt;code&gt;FAC&lt;/code&gt; est l'endroit où se situe « le nombre en cours ». À la sortie d'une fonction, le résultat s'y trouve et est donc disponible pour les calculs ou fonctions suivants.&lt;/p&gt;
&lt;p&gt;Ainsi, dans une expression comme &lt;code&gt;INT(4 * 0.2)&lt;/code&gt;, le &lt;code&gt;FAC&lt;/code&gt; va d'abord contenir &lt;code&gt;4&lt;/code&gt;, puis après la multiplication &lt;code&gt;0.8&lt;/code&gt;, puis après &lt;code&gt;INT()&lt;/code&gt;, contiendra &lt;code&gt;0&lt;/code&gt;. Des instructions comme &lt;code&gt;PRINT&lt;/code&gt; ou &lt;code&gt;LET&lt;/code&gt; (explicite ou implicite), iront chercher cette valeur pour la traiter.&lt;/p&gt;
&lt;h3&gt;Les mouvements&lt;/h3&gt;
&lt;p&gt;Puisque &lt;code&gt;BCDE&lt;/code&gt; et &lt;code&gt;FAC&lt;/code&gt; sont étroitement liés, il existe des fonctions pour transférer le contenu de &lt;code&gt;BCDE&lt;/code&gt; vers &lt;code&gt;FAC&lt;/code&gt; (&lt;code&gt;\$05d2&lt;/code&gt;) et inversement (&lt;code&gt;\$05dd&lt;/code&gt;). Il est possible aussi de récupérer dans &lt;code&gt;BCDE&lt;/code&gt; un nombre pointé par &lt;code&gt;HL&lt;/code&gt; (&lt;code&gt;\$05e0&lt;/code&gt;), et de monter dans &lt;code&gt;FAC&lt;/code&gt; un nombre pointé par &lt;code&gt;HL&lt;/code&gt; (&lt;code&gt;\$05cf&lt;/code&gt;), en utilisant &lt;code&gt;BCDE&lt;/code&gt; au passage.&lt;/p&gt;
&lt;h3&gt;Le format&lt;/h3&gt;
&lt;p&gt;Voici en premier lieu un tableau auquel je vais me référer pour expliquer le format.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;E&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exp.&lt;/td&gt;
&lt;td&gt;S|MSB&lt;/td&gt;
&lt;td&gt;Milieu&lt;/td&gt;
&lt;td&gt;LSB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$49e9&lt;/td&gt;
&lt;td&gt;$49e8&lt;/td&gt;
&lt;td&gt;$49e7&lt;/td&gt;
&lt;td&gt;$49e6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exp.&lt;/strong&gt; est l'exposant du nombre (la puissance de 2 par laquelle est multipliée la mantisse).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MSB&lt;/strong&gt; (Most Significant Byte), Milieu et &lt;strong&gt;LSB&lt;/strong&gt; (Least Significant Byte) forment la &lt;strong&gt;mantisse&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S&lt;/strong&gt; est le bit de signe et se trouve en bit 7 du &lt;strong&gt;MSB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Les adresses représentent les positions dans &lt;code&gt;FAC&lt;/code&gt; l'accumulateur flottant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt; : les adresses indiquées partent de la plus haute à la place basse. Lorsque vous inspectez la mémoire octet par octet, que ce soit dans &lt;code&gt;FAC&lt;/code&gt; ou pour une valeur de variable, le nombre est donc dans l'autre sens &lt;code&gt;EDCB&lt;/code&gt;, avec l'exposant en dernière position.&lt;/p&gt;
&lt;h4&gt;La mantisse&lt;/h4&gt;
&lt;p&gt;La &lt;strong&gt;mantisse&lt;/strong&gt; couvre donc &lt;strong&gt;23 bits&lt;/strong&gt;. Le 24ième bit, le plus significatif, est implicitement à 1. Dans le format codé, il est donc remplacé par un &lt;strong&gt;bit de signe&lt;/strong&gt;. Un bit à 1 indique un nombre négatif, positif sinon.&lt;/p&gt;
&lt;p&gt;La mantisse est lue comme &lt;code&gt;0.1xxxxxx xxxxxxxx xxxxxxxx&lt;/code&gt; en binaire. Les &lt;code&gt;x&lt;/code&gt; étant pris dans les 23 bits formés par MSB, Milieu et LSB.&lt;/p&gt;
&lt;h4&gt;L'exposant&lt;/h4&gt;
&lt;p&gt;L'&lt;strong&gt;exposant&lt;/strong&gt; est centré sur 128 (ou $80 en hexadécimal). Cela signifie que &lt;strong&gt;128&lt;/strong&gt; est l'exposant nul. Pour 129 l'exposant est 1, 127, et pour l'exposant est -1.&lt;/p&gt;
&lt;p&gt;La valeur 0 ($00) pour l'exposant est &lt;strong&gt;spéciale&lt;/strong&gt; : elle représente le &lt;strong&gt;nombre 0&lt;/strong&gt;. Peu importe les autres octets, la valeur est nulle. Dans certains codage de nombre flottants, cet exposant zéro est utilisé pour représenter des valeurs particulières qui viennent compléter celles accessibles depuis un exposant non nul. Ici, ce n'est pas le cas. Un exposant à 0 signifie le nombre 0.&lt;/p&gt;
&lt;h4&gt;La valeur du nombre&lt;/h4&gt;
&lt;p&gt;La valeur du &lt;strong&gt;nombre représenté&lt;/strong&gt; est égal à : $-1 . signe . 2^{exp.} . mantisse$.&lt;/p&gt;
&lt;p&gt;Ceci mérite quelques exemples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exemple 1&lt;/strong&gt; : &lt;code&gt;0&lt;/code&gt;, codé &lt;code&gt;00 xx xx xx&lt;/code&gt;. Comme je l'ai écrit ci-dessus, peut importe la valeur des autres octets. Si l'exposant est à 0, c'est le nombre 0.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exemple 2&lt;/strong&gt; : &lt;code&gt;1&lt;/code&gt;, codé &lt;code&gt;81 00 00 00&lt;/code&gt;. En effet, 1 est égal à $b0.1 . 2^1$ (je préfixe les nombres en binaire par &lt;code&gt;b&lt;/code&gt;, pour faire la différence avec les nombres en base 10 que je ne préfixe pas).&lt;/p&gt;
&lt;p&gt;L'exposant est donc 1, codé en 128 + 1 = 129, \$81 en hexadécimal. La mantisse est 'b0.1', codé en &lt;code&gt;00 00 00&lt;/code&gt; puisque le premier &lt;code&gt;1&lt;/code&gt; est implicite dans le codage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt; : &lt;code&gt;2&lt;/code&gt;, codé &lt;code&gt;82 00 00 00&lt;/code&gt;. Sur le même principe, 2 est égal à $b0.1 . 2^2$. Donc exposant 2 donne \$82 et la mantisse est là aussi 0 puisque b0.1 est implicite.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exemple 4&lt;/strong&gt; : &lt;code&gt;-2&lt;/code&gt;, codé &lt;code&gt;82 80 00 00&lt;/code&gt;. Le code est similaire à celui de &lt;code&gt;2&lt;/code&gt;, mais le bit de signe négatif est placé sur le 7ième bit de l'octet le plus significatif de la mantisse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exemple 5&lt;/strong&gt; : &lt;code&gt;0.1', code ``7d 4c cc cc&lt;/code&gt;. Là, c'est un peu plus compliqué. &lt;code&gt;0.1&lt;/code&gt; n'est pas une valeur qui tombe juste en binaire. Puisque la précision est limitée, il faut bien s'arrêter quelque part ; il faut bien comprendre que le nombre 'retenu' n'est pas vraiment &lt;code&gt;0.1&lt;/code&gt;, juste un nombre approchant.&lt;/p&gt;
&lt;p&gt;Le nombre s'écrit $2^{-3} . b0.110011001100110011001100$... ; 128 - 3 donne \$7d en hex. Une fois enlevé le premier bit de la mantisse, le reste s'écrit comme indiqué.&lt;/p&gt;
&lt;h4&gt;Aparté 1&lt;/h4&gt;
&lt;p&gt;Il est possible d'écrire&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;LET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;
&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et le nombre affiché sera bien &lt;code&gt;0.1&lt;/code&gt;. Pourtant, ce n'est pas le nombre encodé, qui est plus quelque chose comme : 0.09999999403953552&lt;/p&gt;
&lt;p&gt;Mais ce nombre est arrondi lors de l'affichage.&lt;/p&gt;
&lt;h4&gt;Aparté 2&lt;/h4&gt;
&lt;p&gt;À noter aussi que chaque opération effectuée par le BASIC, qui en interne utilise 32 bits, se termine par un encodage du nombre, qui est arrondi aux 24 bits disponibles. Si les calculs ont besoins de plus de 24 bits significatifs, alors les résultats ne seront pas exacts. Il faut se méfier des nombres flottants.&lt;/p&gt;
&lt;h4&gt;Aparté 3&lt;/h4&gt;
&lt;p&gt;Rappelez-vous qu'en lisant la mémoire octet par octet, les nombres codés vont apparaître dans l'autre sens. Ainsi, si vous assignez à une variable le nombre &lt;code&gt;1&lt;/code&gt; et que vous regardez dans la section de variable la valeur suivant le nom, vous y verrez &lt;code&gt;00 00 00 81&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Aparté 4&lt;/h4&gt;
&lt;p&gt;En examinant la mémoire de &lt;code&gt;FAC&lt;/code&gt; et en traçant les opérations, vous pourrez constater que l'octet suivant (&lt;code&gt;\$49ea&lt;/code&gt;) bouge aussi. Il s'agit d'un octet utilisé pour stocker le signe des opérations. En effet, afin de faire des opérations sur les mantisses, il faut en extraire le bit de signe et y remettre le bit implicite. Un bit de signe est stocké à cet endroit (attention, il s'agit de son complément).&lt;/p&gt;
&lt;h3&gt;Une opération&lt;/h3&gt;
&lt;p&gt;Pour se faire une idée de comment sont traités les nombres, je vous &lt;strong&gt;invite&lt;/strong&gt; à suivre le &lt;strong&gt;processus d'addition&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tout commence en &lt;code&gt;$0705&lt;/code&gt; par la récupération sur la pile du nombre qui vient d'être décodé depuis la ligne du BASIC. Dans &lt;code&gt;FAC&lt;/code&gt; est déjà positionnée l'opérande précédente de l'opération.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;eval_add:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;fp_bcde_add&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La nouvelle opérande est maintenance dans &lt;code&gt;BCDE&lt;/code&gt; dans le format expliqué dans les paragraphes précédents. Il faut donc maintenant ajouter &lt;code&gt;BCDE&lt;/code&gt; et &lt;code&gt;FAC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En &lt;code&gt;$0310&lt;/code&gt;, la routine commence par un test. Si l'exposant, qui est initialement dans &lt;code&gt;B&lt;/code&gt;, est égal à &lt;code&gt;0&lt;/code&gt;, on peut &lt;strong&gt;s’arrêter là&lt;/strong&gt;. Ajouter &lt;code&gt;0&lt;/code&gt; à &lt;code&gt;FAC&lt;/code&gt; signifie ne pas le modifier. Le &lt;strong&gt;retour est immédiat&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;fp_bcde_add:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Deuxième cas simple, si la valeur de l'exposant de &lt;code&gt;FAC&lt;/code&gt; est 0, le résultat est le nombre présent dans &lt;code&gt;BCDE&lt;/code&gt;, il suffit donc de le &lt;strong&gt;transférer&lt;/strong&gt; dans &lt;code&gt;FAC&lt;/code&gt; et c'est &lt;strong&gt;terminé&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;fac_exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bcde_to_fac&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;L'étape suivante est de s'assurer que le nombre dans &lt;code&gt;FAC&lt;/code&gt; a un &lt;strong&gt;exposant plus grand&lt;/strong&gt; que celui de &lt;code&gt;BCDE&lt;/code&gt;. Si ça le cas, c'est parfait, sinon, on échange les deux nombres. L'opération utilise la pile temporairement. &lt;code&gt;A&lt;/code&gt; qui contient la &lt;strong&gt;différence&lt;/strong&gt; entre les deux &lt;strong&gt;exposants&lt;/strong&gt;, prend la valeur de son &lt;strong&gt;opposée&lt;/strong&gt;, pour rester cohérente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_swap&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cpl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;fac_to_stck&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bcde_to_fac&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À ce niveau, on a :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dans &lt;code&gt;FAC&lt;/code&gt; le nombre dont l'exposant est le plus grand,&lt;/li&gt;
&lt;li&gt;dans &lt;code&gt;BCDE&lt;/code&gt;, le nombre dont l'exposant est le plus petit,&lt;/li&gt;
&lt;li&gt;dans &lt;code&gt;A&lt;/code&gt;, la différence entre ces deux exposants.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si le nombre d'exposant le plus petit est &lt;strong&gt;insignifiant&lt;/strong&gt; par rapport au plus grand, on peut &lt;strong&gt;s'arrêter là&lt;/strong&gt;, le résultat de l'addition sera le plus grand des grands nombres. Puisque les nombres sont codés sur 24 bits significatifs, si la différences entre les exposants est de 25 ou plus, on peut sortir de la fonction :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;no_swap:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À présent que les &lt;strong&gt;nombres&lt;/strong&gt; sont &lt;strong&gt;en place&lt;/strong&gt; et qu'il est &lt;strong&gt;intéressant&lt;/strong&gt; de les &lt;strong&gt;additionner&lt;/strong&gt;, il faut les &lt;strong&gt;préparer&lt;/strong&gt;. Pour le moment, le &lt;strong&gt;bit de signe&lt;/strong&gt; est toujours codé dans les deux nombres. Ils sont aussi potentiellement à des exposants différents. Deux raisons pour lesquelles on ne peut pas additionner les mantisses pour le moment.&lt;/p&gt;
&lt;p&gt;La première opération est d'&lt;strong&gt;extraire les signes&lt;/strong&gt; et de renvoyer une indication sur l'opération à faire. Plus d'explication sur cette indication juste après.&lt;/p&gt;
&lt;p&gt;Puis d'aligner les deux mantisses sur l'exposant le plus grand.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;ext_sign&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;div_mant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Je n'entre pas dans la routine &lt;code&gt;ext_sign&lt;/code&gt;, mais voici ce qu'elle fait. Elle prend le &lt;strong&gt;bit 7&lt;/strong&gt; de l'octet le plus significatif de &lt;code&gt;FAC&lt;/code&gt; et le remplace par le 1 implicite de la mantisse codée. Le bit de signe est inversé et est &lt;strong&gt;mis de côté&lt;/strong&gt;, dans l'octet suivant l'exposant de &lt;code&gt;FAC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Puis la &lt;strong&gt;même opération&lt;/strong&gt; est faite sur &lt;code&gt;BCDE&lt;/code&gt; : extraction de signe, remplacement par 1. Le signe n'est pas mis de côté, mais est utilisé pour &lt;strong&gt;renvoyer&lt;/strong&gt; dans &lt;code&gt;A&lt;/code&gt; une indication : &lt;code&gt;0&lt;/code&gt; si les signes étaient &lt;strong&gt;identiques&lt;/strong&gt;, &lt;code&gt;1&lt;/code&gt; s'ils étaient &lt;strong&gt;opposés&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Cette indication, qui est sauvée dans &lt;code&gt;H&lt;/code&gt; pour pouvoir récupérer la valeur de &lt;code&gt;AF&lt;/code&gt; sauvée sur la pile (&lt;code&gt;A&lt;/code&gt; contient la différence entre les exposants), servira bientôt.&lt;/p&gt;
&lt;p&gt;L'opération &lt;code&gt;div_mant&lt;/code&gt; &lt;strong&gt;décale vers la droite&lt;/strong&gt; la mantisse de &lt;code&gt;BCDE&lt;/code&gt; d'autant de positions qu'indiquées par &lt;code&gt;A&lt;/code&gt;. &lt;strong&gt;Attention&lt;/strong&gt; : en sortie de cette fonction, la mantisse est disponible sur &lt;code&gt;CDEB&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En effet, l'exposant n'est plus nécessaire, puisqu'il est identique à celui de &lt;code&gt;FAC&lt;/code&gt;. On peut donc réutiliser &lt;code&gt;B&lt;/code&gt; pour &lt;strong&gt;récupérer&lt;/strong&gt; les bits &lt;strong&gt;résultants&lt;/strong&gt; du décalage à droite et éviter de perdre trop de précision. La mantisse est &lt;strong&gt;temporairement sur 32 bits&lt;/strong&gt; (même si seuls 24 sont toujours significatifs, puisque issus du nombre initial).&lt;/p&gt;
&lt;p&gt;Il reste donc à passer à l'addition... enfin presque.&lt;/p&gt;
&lt;p&gt;Dans la partie suivante, on récupère dans &lt;code&gt;A&lt;/code&gt; l'indicateur donné précédemment par les signes. Si les signes étaient identiques, on passe à la suite. S'ils étaient différents, c'est une soustraction qui sera faite, en allant vers &lt;code&gt;min_bcde&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;fac_lsb&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;min_bcde&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pourquoi cette &lt;strong&gt;différence de traitement&lt;/strong&gt; en fonction des signes ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si les signes des deux nombres sont &lt;strong&gt;positifs&lt;/strong&gt;, il faut additionner les mantisses et le nombre sera &lt;strong&gt;positif&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Si les signes des deux nombres sont &lt;strong&gt;négatifs&lt;/strong&gt;, on peut aussi additionner les mantisses comme des nombres &lt;strong&gt;positifs&lt;/strong&gt;, et pendre l'opposée du tout. $(-a) + (-b)$ est la même chose que $-(a+b)$.&lt;/li&gt;
&lt;li&gt;Si les signes des deux nombres sont &lt;strong&gt;opposés&lt;/strong&gt;, on peut soustraire les mantisses et corriger le signe du résultat. En effet $a + (-b)$ est la même chose que $(a - b)$ et $(-a + b)$ est la même chose que $-(a-b)$.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le cas de l'&lt;strong&gt;addition des mantisses&lt;/strong&gt; est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;add_bcde&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;round&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;overflow&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;shft_right&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;round&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Après l'appel à &lt;code&gt;add_bcde&lt;/code&gt; qui ajoute la mantisse &lt;code&gt;CDE&lt;/code&gt; avec celle de &lt;code&gt;FAC&lt;/code&gt; octet par octet, un test est fait sur la &lt;strong&gt;retenue&lt;/strong&gt;. Si l'addition n'a pas générée de retenue, alors on va vers la &lt;strong&gt;routine d'arrondi&lt;/strong&gt; de &lt;code&gt;FAC&lt;/code&gt;, qui terminera l'opération.&lt;/p&gt;
&lt;p&gt;S'il y a eu une &lt;strong&gt;retenue&lt;/strong&gt;, il faut augmenter l'&lt;strong&gt;exposant&lt;/strong&gt; de 1, ce qui est fait en pointant &lt;code&gt;HL&lt;/code&gt; un cran plus loin que la mantisse et &lt;strong&gt;augmentant&lt;/strong&gt; la valeur de l'exposant qui s'y trouve. Si cette incrémentation a ramené l'exposant à &lt;code&gt;0&lt;/code&gt;, c'est qu'il était déjà à son maximum. Le nombre est trop grand, une &lt;strong&gt;erreur de dépassement&lt;/strong&gt; de capacité est lancée.&lt;/p&gt;
&lt;p&gt;Sinon, il faut corriger la mantisse avec un décalage vers la droite de 1 bit (paramètre indiqué par &lt;code&gt;L&lt;/code&gt;) puis brancher vers la routine d'arrondi.&lt;/p&gt;
&lt;p&gt;Le cas de la &lt;strong&gt;soustraction des mantisses&lt;/strong&gt; est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;min_bcde:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;compl2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Toute la première partie, jusqu'au &lt;code&gt;call&lt;/code&gt;, est la &lt;strong&gt;soustraction de la mantisse&lt;/strong&gt; de 'FAC' par la mantisse 'CDEB' octet par octet. Le résultat se trouve dans 'CDE'. L'exposant du nombre final est toujours celui de &lt;code&gt;FAC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si le &lt;strong&gt;résultat&lt;/strong&gt; de la soustraction est &lt;strong&gt;positif&lt;/strong&gt;, alors il ne se passe rien de plus. Si une &lt;strong&gt;retenue&lt;/strong&gt; a eue lieu pendant la soustraction, alors on prend son &lt;strong&gt;opposée&lt;/strong&gt; en appelant &lt;code&gt;compl2&lt;/code&gt;, afin de rendre la &lt;strong&gt;mantisse positive&lt;/strong&gt;. Cette routine &lt;strong&gt;inverse&lt;/strong&gt; aussi le &lt;strong&gt;bit de signe&lt;/strong&gt; qui avait était extrait dans l'octet suivant &lt;code&gt;FAC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La routine qui suit dans le code étant la normalisation et arrondi d'un nombre, pas besoin de brancher, c'est terminée.&lt;/p&gt;
&lt;h4&gt;Oui mais le signe ?&lt;/h4&gt;
&lt;p&gt;Les opérations pour obtenir le signe du résultat final ne sont pas forcément évidente à suivre. Voici ce qu'il se passe :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dans le cas où on a utilisé l'&lt;strong&gt;addition des mantisses&lt;/strong&gt;, le signe de &lt;code&gt;FAC&lt;/code&gt; a été &lt;strong&gt;extrait&lt;/strong&gt; de la &lt;strong&gt;première opérande&lt;/strong&gt;.&lt;ul&gt;
&lt;li&gt;Dans le cas $a + b$, $a$ était positif, et le résultat est positif.&lt;/li&gt;
&lt;li&gt;Dans le cas $-a-b$ qui est devenu $-(a+b)$, $a$ était négatif, et ce signe négatif sera hérité par le résultat. Transformant $a+b$ en $-(a+b)$.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dans le cas où on a utilisé la &lt;strong&gt;soustraction des mantisses&lt;/strong&gt;, là encore, le signe de &lt;code&gt;FAC&lt;/code&gt; a été &lt;strong&gt;extrait de la première opérande&lt;/strong&gt;.&lt;ul&gt;
&lt;li&gt;Dans le cas $a - b$, le signe du résultat dépend de cette opération. Si $a &amp;gt; b$, &lt;code&gt;compl2&lt;/code&gt; n'a pas été appelé et le résultat est positif. Dans le cas contraire, &lt;code&gt;compl2&lt;/code&gt; a changé le bit de signe et le résultat est bien négatif, puisque la mantisse est positive.&lt;/li&gt;
&lt;li&gt;Dans le cas $-a+b$, qui a été exécutée comme $-(a-b)$, initialement, le signe de &lt;code&gt;FAC&lt;/code&gt; portait l'indication &lt;strong&gt;négatif&lt;/strong&gt;, et le résultat de la soustraction l'aura, en fonction des deux cas, laissé comme tel, ou inversé.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Re-codage final&lt;/h3&gt;
&lt;p&gt;La routine qui suit, de &lt;strong&gt;normalisation&lt;/strong&gt;, s'assure que le &lt;strong&gt;bit de poids&lt;/strong&gt; fort est &lt;strong&gt;toujours 1&lt;/strong&gt; (si ce n'est pas possible, c'est que le nombre est 0) et &lt;strong&gt;ajuste&lt;/strong&gt; l'&lt;strong&gt;exposant&lt;/strong&gt; en conséquence, puis &lt;strong&gt;arrondi&lt;/strong&gt; le nombre. L'arrondi peut générer un &lt;strong&gt;dépassement de capacité&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'addition n'a &lt;strong&gt;pas besoin&lt;/strong&gt; de normalisation. Le résultat de l'addition des mantisses &lt;strong&gt;assure toujours&lt;/strong&gt; que le bit de poids fort est 1 (au moins l'un des deux nombres était normalisé avec un bit de poids fort à 1, et si les deux l'étaient, alors cela a provoqué l'augmentation de l'exposant et le bit de poids fort est toujours 1, la retenu de 1 + 1 en binaire).&lt;/p&gt;
&lt;p&gt;Le résultat de l'addition est à présent dans &lt;code&gt;FAC&lt;/code&gt;, place à la suite des opérations...&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category><category term="Nombres"></category></entry><entry><title>Récréation 3D, Tortue Jeulin</title><link href="https://www.triceraprog.fr/recreation-3d-tortue-jeulin.html" rel="alternate"></link><published>2020-01-29T00:00:00+01:00</published><updated>2020-01-29T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2020-01-29:/recreation-3d-tortue-jeulin.html</id><content type="html">&lt;p&gt;Depuis quelques temps, je planche à mes heures perdues sur ma prochaine vidéo. Et le sujet est le langage de programmation &lt;strong&gt;Logo&lt;/strong&gt;. Après avoir survolé le BASIC, cela me semblait une suite logique.&lt;/p&gt;
&lt;p&gt;En me plongeant dans l'univers Logo, j'ai cherché à mieux connaître le robot qui y est associé : la &lt;strong&gt;tortue Jeulin&lt;/strong&gt;. Et j'ai été très étonné de voir aussi peu de ressources dessus. Et pourtant, il semble qu'elle ne soit pas si rare chez les collectionneurs.&lt;/p&gt;
&lt;p&gt;Grâce à l'aide de photographie envoyées sur le forum &lt;strong&gt;system-cfg&lt;/strong&gt; par Fool-DupleX (merci à lui), j'ai tenté une modélisation. Ça m'a pris... un certain temps.&lt;/p&gt;
&lt;p&gt;Le résultat n'est pas correct au milimètre, mais donne une relativement bonne idée.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tortue Jeulin T2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202001/20200127-Chassis-750.png"&gt;
&lt;img alt="Tortue Jeulin T2" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/202001/20200129-Chassis-750.png"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Tortue"></category><category term="Logo"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>VG5000µ, les hooks d'entrées/sorties</title><link href="https://www.triceraprog.fr/vg5000m-les-hooks-dentreessorties.html" rel="alternate"></link><published>2019-09-22T00:00:00+02:00</published><updated>2019-09-22T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-09-22:/vg5000m-les-hooks-dentreessorties.html</id><summary type="html">&lt;p&gt;Pour ces quatre nouveaux hooks, je ne suis pas très inspirés. Il s'agit de hook destiné au traitement des entrées sorties. Trois d'entre eux sont appelés lors d'une impression de caractères, le quatrième pour de l'acquisition.&lt;/p&gt;
&lt;h3&gt;Routines en sorties&lt;/h3&gt;
&lt;p&gt;Voici les trois premières :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$47DF, &lt;code&gt;prthk&lt;/code&gt; : début de commande PRINT.&lt;ul&gt;
&lt;li&gt;Est appelé en tant que première instruction de l'exécution de l'instruction &lt;code&gt;PRINT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;À ce moment là, &lt;code&gt;HL&lt;/code&gt; pointe vers les arguments de &lt;code&gt;PRINT&lt;/code&gt; et le flag &lt;code&gt;Z&lt;/code&gt; est à 1 s'il n'y a rien dans ces arguments.&lt;/li&gt;
&lt;li&gt;Si vous rendez la main à la routine, elle déroulement l'affichage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;$47E2, &lt;code&gt;outhk&lt;/code&gt; : début d'impression de caractère -&amp;gt; pour rerouter vers de nouvelles sorties&lt;ul&gt;
&lt;li&gt;Est appelé pour chaque caractère envoyé sur un périphérique de sortie (en &lt;code&gt;$3bd0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;La variable système &lt;code&gt;(prtflg)&lt;/code&gt; désigne le périphérique.&lt;/li&gt;
&lt;li&gt;Le caractère à afficher est dans le registre &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Attention, ce caractère est à comprendre par rapport aux modes d'affichage : est-ce …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Pour ces quatre nouveaux hooks, je ne suis pas très inspirés. Il s'agit de hook destiné au traitement des entrées sorties. Trois d'entre eux sont appelés lors d'une impression de caractères, le quatrième pour de l'acquisition.&lt;/p&gt;
&lt;h3&gt;Routines en sorties&lt;/h3&gt;
&lt;p&gt;Voici les trois premières :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$47DF, &lt;code&gt;prthk&lt;/code&gt; : début de commande PRINT.&lt;ul&gt;
&lt;li&gt;Est appelé en tant que première instruction de l'exécution de l'instruction &lt;code&gt;PRINT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;À ce moment là, &lt;code&gt;HL&lt;/code&gt; pointe vers les arguments de &lt;code&gt;PRINT&lt;/code&gt; et le flag &lt;code&gt;Z&lt;/code&gt; est à 1 s'il n'y a rien dans ces arguments.&lt;/li&gt;
&lt;li&gt;Si vous rendez la main à la routine, elle déroulement l'affichage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;$47E2, &lt;code&gt;outhk&lt;/code&gt; : début d'impression de caractère -&amp;gt; pour rerouter vers de nouvelles sorties&lt;ul&gt;
&lt;li&gt;Est appelé pour chaque caractère envoyé sur un périphérique de sortie (en &lt;code&gt;$3bd0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;La variable système &lt;code&gt;(prtflg)&lt;/code&gt; désigne le périphérique.&lt;/li&gt;
&lt;li&gt;Le caractère à afficher est dans le registre &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Attention, ce caractère est à comprendre par rapport aux modes d'affichage : est-ce qu'on est en caractères normaux ? semi-graphiques ? redéfinis par l'utilisateur ?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;$47E5, &lt;code&gt;crdhk&lt;/code&gt; : début de retour chariot -&amp;gt; pour rerouter vers de nouvelles sorties&lt;ul&gt;
&lt;li&gt;Est appelé par chaque demande de retour à la ligne lors de l'émission des caractères sur le périphérique (en &lt;code&gt;$3c57&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;N'est pas appelé lors d'un retour chariot dans l'éditeur par contre.&lt;/li&gt;
&lt;li&gt;La variable système &lt;code&gt;(prtflg)&lt;/code&gt; désigne le périphérique.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La variable système (prtflg) désigne le périphérique en sortie selon les valeurs suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 - L'écran&lt;/li&gt;
&lt;li&gt;1 - L'imprimante&lt;/li&gt;
&lt;li&gt;255 - La cassette (en écriture)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les &lt;strong&gt;appels aux hooks&lt;/strong&gt; se situent avant le tri vers les trois routines. La &lt;strong&gt;sélection&lt;/strong&gt; ne se fait &lt;strong&gt;pas&lt;/strong&gt; systématiquement &lt;strong&gt;dans le même ordre&lt;/strong&gt;, ce qui signifie que les valeurs 2 à 254 n'envoient pas au même endroit pour les différentes fonctions.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;retour chariot&lt;/strong&gt; enverra sur l'imprimante et la sortie de caractère sur la cassette. &lt;code&gt;PRINT&lt;/code&gt; ne considère que deux cas, l'imprimante et l'écran, et s'occupera de la position du chariot ou du curseur suivant le cas. Pour &lt;strong&gt;l'affichage&lt;/strong&gt; en lui-même, c'est la routine d'envoi de caractère et de retour chariot qui sont utilisés.&lt;/p&gt;
&lt;p&gt;Ainsi, si vous voulez supporter un &lt;strong&gt;nouveau périphérique&lt;/strong&gt; en sortie, il faudra probablement effectuer un premier traitement au niveau du &lt;code&gt;PRINT&lt;/code&gt; suivant si vous voulez être traité comme un écran ou une imprimante ; puis rendre la main, ou bien tout faire seul et jeter la première adresse de retour de la pile.&lt;/p&gt;
&lt;p&gt;Du côté de la &lt;strong&gt;sortie de caractère&lt;/strong&gt; et du &lt;strong&gt;retour chariot&lt;/strong&gt;, il vous faudra prendre la main et jeter la première adresse de retour de la pile quoi qu'il arrive.&lt;/p&gt;
&lt;p&gt;N'ayant pas de périphérique à tester (on pourrait imaginer une sortie série), je n'ai pas essayé.&lt;/p&gt;
&lt;h4&gt;Précautions&lt;/h4&gt;
&lt;p&gt;Pendant l'exécution d'une routine de sortie, n'appelez-pas les routines de la ROM qui elles-mêmes font de l'affichage. Vous vous appelleriez vous-même...&lt;/p&gt;
&lt;p&gt;De toute façon, les routines d'affichages ne sont &lt;strong&gt;pas ré-entrantes&lt;/strong&gt; et ne supportent pas d'être exécutées dans deux contextes simultanément. Cela explique pourquoi, si vous avez essayé comment moi d'utiliser des routines d'affichage pendant l'interruption d'affichage, des choses étranges se produisent.&lt;/p&gt;
&lt;p&gt;En effet, si l'interruption à lieu pendant que la ROM est en train d'exécuter une de ces routines (un &lt;code&gt;PRINT&lt;/code&gt; tout simplement), il y a de bonnes chances que cela se passe mal. Même si vous sauvez tous les registres. Le contexte est beaucoup plus gros que ça, avec des buffers de constructions de chaînes.&lt;/p&gt;
&lt;p&gt;Mieux vaut avoir vos routines d'affichages spécialisées.&lt;/p&gt;
&lt;h3&gt;Routine en entrée&lt;/h3&gt;
&lt;p&gt;Pour l'entrée, il n'y a qu'un hook, celui de l'instruction &lt;code&gt;INPUT&lt;/code&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$47EB, &lt;code&gt;inphk&lt;/code&gt; : début de commande INPUT&lt;ul&gt;
&lt;li&gt;Appelé en second lors de l'exécution de l'instruction BASIC &lt;code&gt;INPUT&lt;/code&gt;, la première instruction étant la vérification que &lt;code&gt;INPUT&lt;/code&gt; n'a pas été appelée en direct, hors programme.&lt;/li&gt;
&lt;li&gt;Comme pour &lt;code&gt;PRINT&lt;/code&gt;, &lt;code&gt;HL&lt;/code&gt; pointe sur les arguments.&lt;/li&gt;
&lt;li&gt;La variable système &lt;code&gt;(getflg)&lt;/code&gt; désigne le périphérique en entrée. &lt;code&gt;0&lt;/code&gt; pour le clavier, &lt;code&gt;255&lt;/code&gt; pour la cassette. Il n'y a pas de périphérique écran en entrée...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il est donc possible d'aller router l'&lt;code&gt;INPUT&lt;/code&gt; vers un nouveau périphérique externe.&lt;/p&gt;
&lt;h3&gt;Le manque d'idée...&lt;/h3&gt;
&lt;p&gt;Oui... décidément, comme je n'ai pas de nouveau périphérique à router, je manque d'idée. Le programme que j'écris se contente donc de compter les appels aux différents &lt;strong&gt;hooks&lt;/strong&gt; puis d'offrir une routine pour afficher les compteurs.&lt;/p&gt;
&lt;h4&gt;Installation&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0726&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4805&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;prthk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;df&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;outhk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;e2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;crdhk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;e5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;inphk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;eb&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;inthk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;D0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;A00&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Spécification de l&amp;#39;adresse mémoire d&amp;#39;implentation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde des registres sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;call_text&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Affichage du CALL pour la routine d&amp;#39;Affichage&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;call_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;C3&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Mise en place des JP&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prthk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;outhk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;crdhk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inphk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;prt_routine&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Mise en place des adresses de saut&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prthk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;out_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;outhk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;cr_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;crdhk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;inp_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inphk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Restauration des registres depuis la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Retour au programme appelant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;call_text:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CALL &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dans cette première partie, on effectue comme d'habitude l'installation des routines. Comme il y a &lt;strong&gt;quatre routines&lt;/strong&gt; à mettre en place, on me d'un coup les quatre &lt;code&gt;JP&lt;/code&gt; , puis dans la foulée les quatre adresses.&lt;/p&gt;
&lt;p&gt;Mais auparavant, on affiche à l'écran un message indiquant l'instruction &lt;code&gt;CALL&lt;/code&gt; à lancer pour provoquer l'affichage des compteurs.&lt;/p&gt;
&lt;p&gt;Comme indiqué ci-dessus, appeler les &lt;strong&gt;routines d'affichages&lt;/strong&gt; textes et nombres pendant une &lt;strong&gt;interruption&lt;/strong&gt; ne &lt;strong&gt;fonctionne pas&lt;/strong&gt; sans de nombreuses précautions. J'ai donc préféré offrir une &lt;strong&gt;routine&lt;/strong&gt; qui &lt;strong&gt;affiche les compteurs&lt;/strong&gt; sur un appel &lt;strong&gt;explicite&lt;/strong&gt;. Et plutôt que de placer cet appel à une adresse fixe, elle est à la suite des autres routines. Son adresse étant variable en fonction des modifications des autres routines, je m'aide en affichant l'adresse à appeler.&lt;/p&gt;
&lt;h4&gt;Comptage&lt;/h4&gt;
&lt;p&gt;Le comptage se résume à quatre fois la même routine, à l'adresse de la variable de comptage près.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;prt_count:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;out_count:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;cr_count:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;inp_count:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;prt_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prt_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prt_count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;out_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out_count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;cr_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cr_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cr_count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;inp_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inp_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inp_count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Au tout début, je réserve quatre emplacements de 16 bits pour les compteurs. Puis viennent les quatre routines qui chacune va augmenter le compteur associer lors d'un appel.&lt;/p&gt;
&lt;p&gt;Prenons &lt;code&gt;prt_routine&lt;/code&gt;. Tout d'abord, &lt;code&gt;HL&lt;/code&gt; est &lt;strong&gt;sauvegardé&lt;/strong&gt;. Comme d'habitude au début d'une instruction, ce registre &lt;strong&gt;pointe&lt;/strong&gt; vers la &lt;strong&gt;ligne&lt;/strong&gt; en train d'être &lt;strong&gt;exécutée&lt;/strong&gt;, il est essentiel de préserver sa valeur.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HL&lt;/code&gt; est ensuite &lt;strong&gt;chargé&lt;/strong&gt; avec la &lt;strong&gt;valeur&lt;/strong&gt; de compteur, cette valeur est &lt;strong&gt;incrémentée&lt;/strong&gt; puis &lt;strong&gt;replacée&lt;/strong&gt; dans le compteur.&lt;/p&gt;
&lt;p&gt;On restaure &lt;code&gt;HL&lt;/code&gt; et on revient. Vraiment simple.&lt;/p&gt;
&lt;h4&gt;L'affichage des compteurs&lt;/h4&gt;
&lt;p&gt;La dernière partie est une routine qui sera appelée explicitement par un &lt;code&gt;CALL&lt;/code&gt; pour afficher la valeur des compteurs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;call_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0020&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prt_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0120&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0220&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cr_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0320&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inp_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;xcursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Vu qu'on appelle &lt;code&gt;out_number&lt;/code&gt;, mieux vaut &lt;strong&gt;sauver&lt;/strong&gt; pour commencer tous &lt;strong&gt;les registres&lt;/strong&gt; (sauf IX et IY, mais ces registres sont particuliers pour la ROM). On les restaure en fin de routine.&lt;/p&gt;
&lt;p&gt;Puis on &lt;strong&gt;récupère les coordonnées&lt;/strong&gt; du curseur dans &lt;code&gt;HL&lt;/code&gt;. Attention ici, l'adresse &lt;code&gt;xcursor&lt;/code&gt; contient une valeur sur 8 bits. Elle est suivi par &lt;code&gt;ycursor&lt;/code&gt; qui contient aussi une valeur sur 8 bits. Grâce au &lt;code&gt;LD HL, (xcursor)&lt;/code&gt;, c'est donc les coordonnées &lt;code&gt;X&lt;/code&gt; et &lt;code&gt;Y&lt;/code&gt; qui sont chargées dans &lt;code&gt;HL&lt;/code&gt; en une seule instruction.&lt;/p&gt;
&lt;p&gt;Ces coordonnées seront elles-aussi restaurées en fin de routine. Pour remettre le curseur là où il se situait avant le &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Vient ensuite une répétition de quatre fois la même séquence, aux valeurs près.&lt;/p&gt;
&lt;p&gt;Tout d'abord, &lt;code&gt;HL&lt;/code&gt; prend les coordonnées d'affichages du nombre que l'on va écrire. Dans la valeur sur 16 bits, &lt;code&gt;Y&lt;/code&gt; arrive en premier, suivi de &lt;code&gt;X&lt;/code&gt;. Ainsi &lt;code&gt;$0020&lt;/code&gt; signifie ligne 0, colonne 32.&lt;/p&gt;
&lt;p&gt;Cette &lt;strong&gt;position&lt;/strong&gt; est placée dans la &lt;strong&gt;variable système&lt;/strong&gt; &lt;code&gt;(xcursor)&lt;/code&gt;. &lt;code&gt;HL&lt;/code&gt; prend ensuite la valeur du &lt;strong&gt;compteur&lt;/strong&gt; à afficher, et enfin &lt;code&gt;CALL out_number&lt;/code&gt; se charger d'&lt;strong&gt;afficher&lt;/strong&gt; le nombre entier contenu dans &lt;code&gt;HL&lt;/code&gt; à la &lt;strong&gt;position courante&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;BASIC&lt;/h3&gt;
&lt;p&gt;Voici un programme BASIC qui va monter la routine en mémoire. Suivi d'un &lt;code&gt;RUN&lt;/code&gt; pour l'exécuter puis du &lt;code&gt;CALL&lt;/code&gt; pour lancer le hook.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;79FF&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;READ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FIN&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;VAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;70&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;30&lt;/span&gt;
&lt;span class="nl"&gt;300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;AA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;6&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;DF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;
&lt;span class="nl"&gt;310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;E2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;EB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;
&lt;span class="nl"&gt;320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;EC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;
&lt;span class="nl"&gt;330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;
&lt;span class="nl"&gt;340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;
&lt;span class="nl"&gt;350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;
&lt;span class="nl"&gt;360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;26&lt;/span&gt;
&lt;span class="nl"&gt;370&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;380&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;
&lt;span class="nl"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;FIN&lt;/span&gt;
&lt;span class="kr"&gt;RUN&lt;/span&gt;
&lt;span class="kr"&gt;CALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour éviter d'avoir à tout rentrer au clavier, voici le &lt;a href="https://www.triceraprog.fr/files/201909/hk_io.k7"&gt;fichier .k7&lt;/a&gt;. À charger avec &lt;code&gt;CLOAD&lt;/code&gt;, suivi d'un &lt;code&gt;RUN&lt;/code&gt; et du &lt;code&gt;CALL &amp;amp;"7A00"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Une fois le programme chargé et les routines installées via le &lt;code&gt;CALL&lt;/code&gt;, vous pouvez regarder les effets sur les compteurs avec un programme similaire à celui qui suit (pensez à faire un &lt;code&gt;NEW&lt;/code&gt; pour partir à vide) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;xxxxx&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HELLO&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;INPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;INPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;xxxxx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En remplaçant bien entendu les &lt;code&gt;xxxxx&lt;/code&gt; par la valeur indiquée lors du &lt;code&gt;CALL &amp;amp;"7A00"&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Le résultat&lt;/h3&gt;
&lt;p&gt;Et voici le résultat d'une session comme indiquée ci-dessus.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un CALL avec paramètres" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201909/VG5000-Hook-IO.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category><category term="Hooks"></category></entry><entry><title>VG5000µ, les hooks d'appel</title><link href="https://www.triceraprog.fr/vg5000m-les-hooks-dappel.html" rel="alternate"></link><published>2019-09-09T00:00:00+02:00</published><updated>2019-09-09T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-09-09:/vg5000m-les-hooks-dappel.html</id><summary type="html">&lt;p&gt;Dans la série des &lt;a href="https://www.triceraprog.fr/tag/hooks.html"&gt;hooks&lt;/a&gt; sur &lt;a href="https://www.triceraprog.fr/tag/vg5000.html"&gt;VG5000µ&lt;/a&gt;, voyons en cette fois la paire probablement la plus simple. Ça sera donc rapide.&lt;/p&gt;
&lt;h3&gt;Le hook &lt;em&gt;CALL&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;Du nom de &lt;code&gt;calhk&lt;/code&gt; et d'adresse &lt;code&gt;$47D3&lt;/code&gt;, ce hook est utilisé en interne par la commande BASIC &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le code de cette instruction est extrêmement &lt;strong&gt;simple&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;inst_call:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;eval_num_ex&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;deint_impl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En premier, l'argument passé à &lt;code&gt;CALL&lt;/code&gt; est évalué, puis est ensuite &lt;strong&gt;transformé&lt;/strong&gt; en entier sur 16 bits.&lt;/p&gt;
&lt;p&gt;Cette adresse, précédée par l'opcode pour &lt;code&gt;JP&lt;/code&gt; à une &lt;strong&gt;adresse absolue&lt;/strong&gt; 16 bits est placée dans le hook &lt;code&gt;calhk&lt;/code&gt;. La routine saute enfin vers cette adresse, qui agit comme un tremplin vers l'adresse indiquée à l'instruction &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Comme c'est le &lt;code&gt;RET&lt;/code&gt; de la routine appelée qui fera office de &lt;code&gt;RET&lt;/code&gt; pour l'ensemble de l'instruction &lt;code&gt;CALL&lt;/code&gt;, la préservation de l'environnement est à la charge de la routine …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans la série des &lt;a href="https://www.triceraprog.fr/tag/hooks.html"&gt;hooks&lt;/a&gt; sur &lt;a href="https://www.triceraprog.fr/tag/vg5000.html"&gt;VG5000µ&lt;/a&gt;, voyons en cette fois la paire probablement la plus simple. Ça sera donc rapide.&lt;/p&gt;
&lt;h3&gt;Le hook &lt;em&gt;CALL&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;Du nom de &lt;code&gt;calhk&lt;/code&gt; et d'adresse &lt;code&gt;$47D3&lt;/code&gt;, ce hook est utilisé en interne par la commande BASIC &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le code de cette instruction est extrêmement &lt;strong&gt;simple&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;inst_call:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;eval_num_ex&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;deint_impl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;calhk&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En premier, l'argument passé à &lt;code&gt;CALL&lt;/code&gt; est évalué, puis est ensuite &lt;strong&gt;transformé&lt;/strong&gt; en entier sur 16 bits.&lt;/p&gt;
&lt;p&gt;Cette adresse, précédée par l'opcode pour &lt;code&gt;JP&lt;/code&gt; à une &lt;strong&gt;adresse absolue&lt;/strong&gt; 16 bits est placée dans le hook &lt;code&gt;calhk&lt;/code&gt;. La routine saute enfin vers cette adresse, qui agit comme un tremplin vers l'adresse indiquée à l'instruction &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Comme c'est le &lt;code&gt;RET&lt;/code&gt; de la routine appelée qui fera office de &lt;code&gt;RET&lt;/code&gt; pour l'ensemble de l'instruction &lt;code&gt;CALL&lt;/code&gt;, la préservation de l'environnement est à la charge de la routine appelée. Essentiellement, il vous faut préserver &lt;code&gt;HL&lt;/code&gt;, qui pointe sur la fin de l'instruction. Si vous ne le faite pas, il y a de bonnes chances que vous obteniez un &lt;code&gt;Erreur de Syntaxe&lt;/code&gt; en retour d'instruction.&lt;/p&gt;
&lt;p&gt;Pour un exemple d'utilisation, voyez les &lt;a href="https://www.triceraprog.fr/tag/hooks.html"&gt;articles précédents&lt;/a&gt;, qui montent une routine assembleur en mémoire puis l’appellent.&lt;/p&gt;
&lt;h4&gt;Récupérer des paramètres&lt;/h4&gt;
&lt;p&gt;Que HL pointe juste après le &lt;code&gt;CALL&lt;/code&gt; se révèle &lt;strong&gt;pratique&lt;/strong&gt; pour récupérer des &lt;strong&gt;arguments&lt;/strong&gt; potentiels. Dans l'article sur les &lt;a href="https://www.triceraprog.fr/vg5000m-les-hooks-de-peripheriques.html"&gt;hooks de périphériques&lt;/a&gt;, j'étais allé chercher un argument de type chaîne de caractères. Cette fois, je vais aller chercher &lt;strong&gt;trois arguments&lt;/strong&gt; de type nombre. Le premier entier sur &lt;strong&gt;8 bits&lt;/strong&gt;, le second sur &lt;strong&gt;16 bits&lt;/strong&gt;, et le troisième un nombre quelconque (dans les limites du VG5000µ).&lt;/p&gt;
&lt;p&gt;Les deux premiers arguments seront &lt;strong&gt;obligatoires&lt;/strong&gt;, le troisième &lt;strong&gt;optionnel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Grâce à ça, il est possible d'ajouter des commandes au BASIC, sans leur donner un nom cependant.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0726&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_fp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0731&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;deint_impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2552&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eval_num_ex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;284&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;type_eq_num&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2850&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2861&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;getbyt_impl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;aa5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;A00&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Spécification de l&amp;#39;adresse mémoire d’implantation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;cmd_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Vérification obligatoire du caractère qui suit&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;getbyt_impl&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Récupération d&amp;#39;un entier 8 bits dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde du premier paramètre dans C&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; BC contient le premier paramètre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Vérification obligatoire du caractère qui suit&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; La virgule de séparation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BC&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde du premier paramètre dans la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eval_num_ex&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;deint_impl&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Lecture d&amp;#39;un entier signé 16 bits dans DE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;DE&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde du second paramètre dans la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la parenthèse ouvrante&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;SP&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du deuxième paramètre, sauvegarde du pointeur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Affiche le contenu de HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la virgule&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;SP&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du premier paramètre, sauvegarde du pointeur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_number&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Affiche le contenu de HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du pointeur d&amp;#39;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Lecture du caractère suivant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_third&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Fin de la ligne, il n&amp;#39;y a pas de troisième paramètre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sinon, on revient en arrière pour vérifier le caractère suivant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Qui doit être une virgule&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la virgule&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_expr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Lecture du troisième paramètre comme une expression&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde du pointeur d’exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;type_eq_num&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Vérification du type de paramètre (numérique)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_fp&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Construction de la chaîne de caractères correspondant au nombre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la chaîne&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Restauration du pointeur d’exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;no_third:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la parenthèse fermante&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;C'est &lt;strong&gt;assez long&lt;/strong&gt;, il y a peut-être plus optimisé, le principal ici est que la suite d'instructions soit &lt;strong&gt;lisible&lt;/strong&gt; et que les morceaux différents allant chercher les arguments puissent être pris &lt;strong&gt;indépendamment&lt;/strong&gt; pour &lt;strong&gt;réutilisation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le code est commenté, mais nécessite peut-être quelques autres éclaircissement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rst $08&lt;/code&gt; &lt;strong&gt;vérifie&lt;/strong&gt; que le caractère codé juste après le &lt;code&gt;RST&lt;/code&gt; est pointé par &lt;code&gt;HL&lt;/code&gt;. Si ce n'est pas le cas, une erreur de syntaxe est levée. Le &lt;code&gt;DEFB&lt;/code&gt; qui suit le &lt;code&gt;RST&lt;/code&gt; est bien entendu sauté, le retour de la routine se fait juste après. La ROM se sert beaucoup de cette séquence pour vérifier la syntaxe de commandes et d'expressions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rst $18&lt;/code&gt; &lt;strong&gt;affiche&lt;/strong&gt; le caractère présent dans A.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read_expr&lt;/code&gt; &lt;strong&gt;évalue&lt;/strong&gt; une &lt;strong&gt;expression&lt;/strong&gt; de n'importe quel type et met le résultat dans l'accumulateur flottant.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eval_num_ex&lt;/code&gt; lire une expression (via &lt;code&gt;read_expr&lt;/code&gt;) et vérifie dans la foulée si elle est &lt;strong&gt;numérique&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getbyt_impl&lt;/code&gt; appelle &lt;code&gt;eval_num_ex&lt;/code&gt;, la converti en &lt;strong&gt;entier&lt;/strong&gt;, et vérifie que le résultat tient sur &lt;strong&gt;8 bits&lt;/strong&gt;. Le résultat est dans A.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deint_impl&lt;/code&gt; effectue une troncature entière sur &lt;strong&gt;16 bits&lt;/strong&gt; du nombre présent dans l'accumulateur flottant. Le résultat est dans DE.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;out_number&lt;/code&gt; &lt;strong&gt;affiche&lt;/strong&gt; le nombre (entier positif) présent dans HL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;out_fp&lt;/code&gt; écrit dans un buffer temporaire une chaîne représentant le &lt;strong&gt;nombre&lt;/strong&gt; présent dans l'&lt;strong&gt;accumulateur flottant&lt;/strong&gt;. Le pointeur vers la chaîne est renvoyé dans &lt;code&gt;HL&lt;/code&gt; et la chaîne se termine par &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;out_str&lt;/code&gt; &lt;strong&gt;affiche&lt;/strong&gt; la chaîne pointée par &lt;code&gt;HL&lt;/code&gt; se terminant par &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On notera au passage que lors de l'affichage, les deux premiers paramètres sont inversés... c'était juste plus simple à écrire.&lt;/p&gt;
&lt;h3&gt;Le hook &lt;code&gt;RST&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Le second hook d'appel est &lt;code&gt;rsthk&lt;/code&gt;, à l'adresse &lt;code&gt;$47DC&lt;/code&gt;. Son fonctionnement n'est pas atteignable depuis le BASIC.&lt;/p&gt;
&lt;p&gt;La fonction &lt;code&gt;RST&lt;/code&gt; du Z80 est une sorte de &lt;code&gt;CALL&lt;/code&gt; sur 1 octet. Il permet de brancher à une série de 8 adresses prédéfinies : $0000, $0008, $0010, $0018, $0020, $0028, $0030, $0038. Suivant la syntaxe de l'assembleur, soit l'adresse, soit le numéro du &lt;em&gt;restart&lt;/em&gt; (entre 0 et 7) est accepté.&lt;/p&gt;
&lt;p&gt;Toutes ces adresses sont allouées à des &lt;strong&gt;fonctions souvent appelées&lt;/strong&gt;, cela permet de gagner de la place. Comme il n'y a pas beaucoup d'instructions possibles entre deux adresses de &lt;em&gt;restart&lt;/em&gt;, la routine est souvent placée ailleurs, et certains emplacements sont remplis avec des données.&lt;/p&gt;
&lt;p&gt;Par exemple, entre &lt;code&gt;RST $00&lt;/code&gt;, qui fait un démarrage complet de la machine et &lt;code&gt;RST $08&lt;/code&gt;, qui fait un test de syntaxe, se situe la chaîne ".1.1" pour la ROM 1.1. C'est cette chaîne qui est affichée au démarrage de la machine.&lt;/p&gt;
&lt;h4&gt;Les différents RST&lt;/h4&gt;
&lt;p&gt;Puisqu'on y est, voici les différents RST sur VG5000µ, brièvement.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$00 : redémarrage complet de la machine&lt;/li&gt;
&lt;li&gt;$08 : vérification de la présence d'un caractère pointé par &lt;code&gt;HL&lt;/code&gt;, ou lancement d'une erreur de syntaxe (pour vérifier une virgule entre deux arguments par exemple)&lt;/li&gt;
&lt;li&gt;$10 : acquisition d'un caractère depuis la chaîne pointée par &lt;code&gt;HL&lt;/code&gt; (avec quelques flags concernant sa nature, et en sautant les espaces)&lt;/li&gt;
&lt;li&gt;$18 : envoie d'un caractère sur le périphérique sélectionné (écran, imprimante, modem)&lt;/li&gt;
&lt;li&gt;$20 : comparaison de &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt;, qui a lieu très souvent.&lt;/li&gt;
&lt;li&gt;$28 : renvoie -!, 0 ou 1 en fonction du signe de l'accumulateur flottant&lt;/li&gt;
&lt;li&gt;$30 : libre&lt;/li&gt;
&lt;li&gt;$38 : vecteur d'interruption (utilisé par l'affichage)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Un &lt;code&gt;RST&lt;/code&gt; libre&lt;/h3&gt;
&lt;p&gt;Le &lt;em&gt;restart&lt;/em&gt; &lt;code&gt;$30&lt;/code&gt; est donc libre, et son code est le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;usrrst:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;rsthk&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Net et précis. Il suffit donc d'ajouter en &lt;code&gt;rsthk&lt;/code&gt; un &lt;code&gt;JP&lt;/code&gt; suivi d'une adresse absolue, et vous pouvez alors utiliser &lt;code&gt;RST $30&lt;/code&gt; dans vos routines pour un appel très fréquent.&lt;/p&gt;
&lt;p&gt;Cependant, il y a une limite : il n'existe qu'un seul hook libre pour tout le monde. À garder en tête si vous mélanger des routines qui veulent chacune utiliser cette instruction.&lt;/p&gt;
&lt;p&gt;À noter aussi que si &lt;code&gt;RST $30&lt;/code&gt; ne prend qu'un octet dans votre routine, le saut utilise deux indirections pour un total de 31 &lt;em&gt;T States&lt;/em&gt; contre 17 pour un &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Le résultat&lt;/h2&gt;
&lt;p&gt;Voici le résultat de l'appel de la routine via &lt;code&gt;CALL&lt;/code&gt; avec décodage de paramètre.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un CALL avec paramètres" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201909/VG5000-Call-Params.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category><category term="Hooks"></category></entry><entry><title>VG5000µ, les hooks de périphériques</title><link href="https://www.triceraprog.fr/vg5000m-les-hooks-de-peripheriques.html" rel="alternate"></link><published>2019-09-05T00:00:00+02:00</published><updated>2019-09-05T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-09-05:/vg5000m-les-hooks-de-peripheriques.html</id><summary type="html">&lt;p&gt;L'&lt;a href="https://www.triceraprog.fr/vg5000m-les-hooks.html"&gt;article précédent&lt;/a&gt; présentait un &lt;em&gt;accrochage&lt;/em&gt; sur un &lt;em&gt;hook&lt;/em&gt; d'interruption. Dans cet article, je vais regarder du côté des hooks de commandes de &lt;strong&gt;périphériques&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ces &lt;strong&gt;hooks&lt;/strong&gt; sont initialisés différements des 10 premiers, selon le code qui suit :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_lpen&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_disk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_modem&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_device&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;L'instruction placée au début de chaque vecteur de redirection est un &lt;code&gt;JP&lt;/code&gt; et l'adresse par défaut est celle d'une routine indiquant que le &lt;strong&gt;périphérique&lt;/strong&gt; n'est &lt;strong&gt;pas géré&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il s'agit d'une &lt;strong&gt;extension de commandes&lt;/strong&gt; mise à disposition par le VG5000µ, permettant de traiter les commandes &lt;code&gt;LPEN&lt;/code&gt;, &lt;code&gt;MODEM&lt;/code&gt; et &lt;code&gt;DISK&lt;/code&gt;. Il est d'ailleurs amusant de voir que dans le &lt;strong&gt;manuel d'utilisation&lt;/strong&gt;, ces trois commandes sont mentionnées dans le rappel des instructions reconnues, mais qu'elles ne sont pas décrites.&lt;/p&gt;
&lt;p&gt;Dans la table des &lt;strong&gt;instructions&lt;/strong&gt;, le décodage de ces tokens …&lt;/p&gt;</summary><content type="html">&lt;p&gt;L'&lt;a href="https://www.triceraprog.fr/vg5000m-les-hooks.html"&gt;article précédent&lt;/a&gt; présentait un &lt;em&gt;accrochage&lt;/em&gt; sur un &lt;em&gt;hook&lt;/em&gt; d'interruption. Dans cet article, je vais regarder du côté des hooks de commandes de &lt;strong&gt;périphériques&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ces &lt;strong&gt;hooks&lt;/strong&gt; sont initialisés différements des 10 premiers, selon le code qui suit :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_lpen&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_disk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_modem&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_device&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;L'instruction placée au début de chaque vecteur de redirection est un &lt;code&gt;JP&lt;/code&gt; et l'adresse par défaut est celle d'une routine indiquant que le &lt;strong&gt;périphérique&lt;/strong&gt; n'est &lt;strong&gt;pas géré&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il s'agit d'une &lt;strong&gt;extension de commandes&lt;/strong&gt; mise à disposition par le VG5000µ, permettant de traiter les commandes &lt;code&gt;LPEN&lt;/code&gt;, &lt;code&gt;MODEM&lt;/code&gt; et &lt;code&gt;DISK&lt;/code&gt;. Il est d'ailleurs amusant de voir que dans le &lt;strong&gt;manuel d'utilisation&lt;/strong&gt;, ces trois commandes sont mentionnées dans le rappel des instructions reconnues, mais qu'elles ne sont pas décrites.&lt;/p&gt;
&lt;p&gt;Dans la table des &lt;strong&gt;instructions&lt;/strong&gt;, le décodage de ces tokens envoie &lt;strong&gt;directement&lt;/strong&gt; sur chacun des trois &lt;strong&gt;vecteurs&lt;/strong&gt;, sans traitement particulier. C'est donc du code de décodage de paramètres qu'il faut écrire si l'on veut traiter ces instructions.&lt;/p&gt;
&lt;h3&gt;Mise en place de la routine&lt;/h3&gt;
&lt;p&gt;Le code est &lt;strong&gt;similaire&lt;/strong&gt; à celui de la mise en place de la routine sur l'interruption. Seule l'adresse du &lt;em&gt;hook&lt;/em&gt; change.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dskhk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f4&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Adresse du hook&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;A00&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Spécification de l&amp;#39;adresse mémoire d&amp;#39;implémentation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde des registres sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;C3&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Mise en place de la routine sur le HOOK&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dskhk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Il y a normalement déjà un &amp;#39;JP&amp;#39; ici, mais on s&amp;#39;en assure&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;cmd_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dskhk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; l&amp;#39;adresse de la routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Restauration des registres depuis la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Retour au programme appelant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;cmd_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Passons donc rapidement sur la partie la plus intéressante : le traitement de l'instruction.&lt;/p&gt;
&lt;h3&gt;Traitement de l'instruction&lt;/h3&gt;
&lt;p&gt;Lorsque l'&lt;strong&gt;interpréteur&lt;/strong&gt; appelle la &lt;strong&gt;routine&lt;/strong&gt; associée à une &lt;strong&gt;instruction&lt;/strong&gt;, plusieurs choses sont mises en place. Les principales sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HL&lt;/code&gt; pointe vers la chaîne en train d'être interprétée, sur le prochain caractère à lire,&lt;/li&gt;
&lt;li&gt;Le flag "Z" est à 1 si l'on est à la fin de la chaîne,&lt;/li&gt;
&lt;li&gt;L'adresse de retour sur la pile est positionnée pour traiter l'instruction suivante.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le contrat en sortie est :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HL&lt;/code&gt; doit pointer sur le caractère après le dernier consommé par l'instruction,&lt;/li&gt;
&lt;li&gt;S'il s'agit d'une fonction, son résultat doit être dans l'accumulateur flottant (numérique, ou pointeur de chaîne).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour s'amuser avec le paramètre, je vais écrire le &lt;strong&gt;décodage&lt;/strong&gt; d'un paramètre de &lt;strong&gt;type chaîne&lt;/strong&gt;, qui sera ensuite &lt;strong&gt;affiché à l'écran&lt;/strong&gt;, suivi par un message.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;type_eq_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2851&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2861&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;ad&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;cmd_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde du pointeur d&amp;#39;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;read_expr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Lecture de l&amp;#39;expression suivant la commande&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Remplacement de la valeur du pointeur d&amp;#39;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;type_eq_str&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Vérification du type du paramètre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str1&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Affichage de la chaîne&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;answer&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out_str&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Affichage du message de la commande&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du pointeur d&amp;#39;exécution&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;answer:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;lt;-- PARAM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La structure est assez simple, car les routines nécessaires sont toutes disponibles dans la ROM.&lt;/p&gt;
&lt;p&gt;Tout d'abord, on &lt;strong&gt;sauve&lt;/strong&gt; le pointeur vers la &lt;strong&gt;chaîne interprétée&lt;/strong&gt;. &lt;code&gt;HL&lt;/code&gt; est actuellement sur le début du paramètre de &lt;code&gt;DISK&lt;/code&gt; (en tout cas, ce qui suit).&lt;/p&gt;
&lt;p&gt;L'appel à &lt;code&gt;read_expr&lt;/code&gt; se charge de &lt;strong&gt;lire une expression valide&lt;/strong&gt; (ou échouer avec une erreur). À la sortie de la routine, &lt;code&gt;HL&lt;/code&gt; est positionné à la fin de ce qui a été consommé par l'expression.&lt;/p&gt;
&lt;p&gt;Ce pointeur est celui qu'il faudra &lt;strong&gt;conserver&lt;/strong&gt; pour l’interpréteur. Du coup, on échange la valeur précédente de &lt;code&gt;HL&lt;/code&gt; actuellement sur la pile avec la nouvelle valeur. Hop, le tour est joué.&lt;/p&gt;
&lt;p&gt;L'appel à &lt;code&gt;type_eq_str&lt;/code&gt; vérifie si le &lt;strong&gt;type&lt;/strong&gt; de l'&lt;strong&gt;expression&lt;/strong&gt; est bien une &lt;strong&gt;chaîne&lt;/strong&gt;, et affiche un message d'erreur sinon (et dans ce cas l'interprétation est arrêtée immédiatement).&lt;/p&gt;
&lt;p&gt;Si c'est bien une chaîne, l'appel à &lt;code&gt;out_str1&lt;/code&gt; &lt;strong&gt;affiche&lt;/strong&gt; le résultat de l'expression de type chaîne de caractères qui vient d'être évaluée.&lt;/p&gt;
&lt;p&gt;L'appel à &lt;code&gt;out_str&lt;/code&gt; qui suit affiche la chaîne terminée par un &lt;code&gt;0&lt;/code&gt; définie dans le programme.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Et voilà&lt;/strong&gt;, voir le résultat à la fin de l'article.&lt;/p&gt;
&lt;h3&gt;BASIC&lt;/h3&gt;
&lt;p&gt;Voici un programme &lt;strong&gt;BASIC&lt;/strong&gt; pour charger et lancer la routine.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;79FF&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;READ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;FIN&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;34&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;VAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;70&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;30&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;C3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;F4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;28&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;AD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;CD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;AA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;C9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;20&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FIN&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="kr"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;CALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour éviter d'avoir à tout rentrer au clavier, voici le &lt;a href="https://www.triceraprog.fr/files/201909/hk_disk.k7"&gt;fichier .k7&lt;/a&gt;. À charger avec &lt;code&gt;CLOAD&lt;/code&gt;, suivi d'un &lt;code&gt;RUN&lt;/code&gt; et du &lt;code&gt;CALL &amp;amp;"7A00"&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Le résultat&lt;/h2&gt;
&lt;p&gt;&lt;img alt="La commande DISK" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201909/VG5000-Hook-Disk.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category><category term="Hooks"></category></entry><entry><title>VG5000µ, les hooks</title><link href="https://www.triceraprog.fr/vg5000m-les-hooks.html" rel="alternate"></link><published>2019-08-31T00:00:00+02:00</published><updated>2019-08-31T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-31:/vg5000m-les-hooks.html</id><summary type="html">&lt;p&gt;Pour cet article, nous allons &lt;strong&gt;laisser de côté&lt;/strong&gt; la partie BASIC-80 pour regarder du côté d'un fonctionnement spécifique au VG5000µ. Pas que le principe soit original, il est présent dans de nombreuses machines, mais que les capacités sont diverses suivant les différentes machines.&lt;/p&gt;
&lt;p&gt;Les « &lt;strong&gt;hooks&lt;/strong&gt; » (la traduction de « crochet » me semble un peu hasardeuse, une « accroche » me semble un peu meilleur) est un moyen qu'offre le système pour &lt;strong&gt;intervenir&lt;/strong&gt; lors de &lt;strong&gt;certaines opérations&lt;/strong&gt; en augmentant le fonctionnement de la ROM. En y mettant son grain de sel en quelque sorte.&lt;/p&gt;
&lt;p&gt;Plus prosaïquement, les « hooks » sont des &lt;strong&gt;appels&lt;/strong&gt; à des &lt;strong&gt;adresses précises&lt;/strong&gt;, en RAM, à des routines qui peuvent être modifiées. Il peut s'agir aussi sur d'autres machines de récupérer dans une variable système une adresse d'indirection. Sur le VG5000µ, toutes les adresses de « hooks » sont fixes.&lt;/p&gt;
&lt;p&gt;Les « hooks » sont parfois aussi appelés &lt;strong&gt;vecteurs d'indirection&lt;/strong&gt;. Ou bien tout simplement &lt;em&gt;vecteurs&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;L'initialisation …&lt;/h3&gt;</summary><content type="html">&lt;p&gt;Pour cet article, nous allons &lt;strong&gt;laisser de côté&lt;/strong&gt; la partie BASIC-80 pour regarder du côté d'un fonctionnement spécifique au VG5000µ. Pas que le principe soit original, il est présent dans de nombreuses machines, mais que les capacités sont diverses suivant les différentes machines.&lt;/p&gt;
&lt;p&gt;Les « &lt;strong&gt;hooks&lt;/strong&gt; » (la traduction de « crochet » me semble un peu hasardeuse, une « accroche » me semble un peu meilleur) est un moyen qu'offre le système pour &lt;strong&gt;intervenir&lt;/strong&gt; lors de &lt;strong&gt;certaines opérations&lt;/strong&gt; en augmentant le fonctionnement de la ROM. En y mettant son grain de sel en quelque sorte.&lt;/p&gt;
&lt;p&gt;Plus prosaïquement, les « hooks » sont des &lt;strong&gt;appels&lt;/strong&gt; à des &lt;strong&gt;adresses précises&lt;/strong&gt;, en RAM, à des routines qui peuvent être modifiées. Il peut s'agir aussi sur d'autres machines de récupérer dans une variable système une adresse d'indirection. Sur le VG5000µ, toutes les adresses de « hooks » sont fixes.&lt;/p&gt;
&lt;p&gt;Les « hooks » sont parfois aussi appelés &lt;strong&gt;vecteurs d'indirection&lt;/strong&gt;. Ou bien tout simplement &lt;em&gt;vecteurs&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;L'initialisation des « hooks »&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;L'initialisation&lt;/strong&gt; des « hooks » arrive très tôt dans l'initialisation de la machine, juste après la détection de la mémoire disponible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c9&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;inthk&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;hk_ini_lop:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hk_ini_lop&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_lpen&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_disk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inst_modem&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_device&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;f8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;resetlang&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;ef&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;nmihk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;A&lt;/code&gt; prend la valeur &lt;code&gt;C9&lt;/code&gt;, qui est le code pour l'instruction &lt;code&gt;RET&lt;/code&gt; sur Z80. &lt;code&gt;HL&lt;/code&gt; est initialisé à &lt;code&gt;inthk&lt;/code&gt;, qui est le premier hook d'une plage consécutive. Et &lt;code&gt;B&lt;/code&gt; prend &lt;code&gt;$1e&lt;/code&gt;, la taille de cette plage.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;première étape&lt;/strong&gt; est de remplir cette plage avec des &lt;code&gt;RET&lt;/code&gt;. Cette plage contient les &lt;strong&gt;10 premiers hooks, que sont les suivants&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$47D0, &lt;code&gt;inthk&lt;/code&gt; : interruption masquable&lt;/li&gt;
&lt;li&gt;$47D3, &lt;code&gt;calhk&lt;/code&gt; : vecteur &lt;code&gt;CALL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;$47D6, &lt;code&gt;sonhk&lt;/code&gt; : vecteur de générateur de son&lt;/li&gt;
&lt;li&gt;$47D9, &lt;code&gt;plyhk&lt;/code&gt; : début de commande PLAY&lt;/li&gt;
&lt;li&gt;$47DC, &lt;code&gt;rsthk&lt;/code&gt; : vecteur pour l'instruction RST utilisateur&lt;/li&gt;
&lt;li&gt;$47DF, &lt;code&gt;prthk&lt;/code&gt; : début de commande PRINT&lt;/li&gt;
&lt;li&gt;$47E2, &lt;code&gt;outhk&lt;/code&gt; : début d'impression de caractère&lt;/li&gt;
&lt;li&gt;$47E5, &lt;code&gt;crdhk&lt;/code&gt; : début de retour chariot&lt;/li&gt;
&lt;li&gt;$47E8, &lt;code&gt;inlhk&lt;/code&gt; : début de lecture d'une ligne&lt;/li&gt;
&lt;li&gt;$47EB, &lt;code&gt;inphk&lt;/code&gt; : début de commande INPUT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chaque hook fait &lt;strong&gt;3 octets de long&lt;/strong&gt;, nous verrons pourquoi plus loin. Et pour le moment tous remplis de &lt;code&gt;RET&lt;/code&gt;. Un &lt;code&gt;CALL&lt;/code&gt; à ces adresses ne fait donc rien d'autre que de &lt;strong&gt;revenir&lt;/strong&gt; à l'appelant immédiatement.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;A&lt;/code&gt; prend ensuite la valeur &lt;code&gt;C3&lt;/code&gt;, qui, suivi d'une adresse sur deux octets, est un &lt;code&gt;JP&lt;/code&gt; absolu à cette adresse. Les hooks &lt;code&gt;lpnhk&lt;/code&gt;, &lt;code&gt;dskhk&lt;/code&gt; et &lt;code&gt;modhk&lt;/code&gt; sont remplis avec ce &lt;code&gt;jp no_device&lt;/code&gt;, qui est un &lt;strong&gt;branchement&lt;/strong&gt; vers l'&lt;strong&gt;erreur&lt;/strong&gt; indiquant que le &lt;strong&gt;périphérique&lt;/strong&gt; n'est pas géré.&lt;/p&gt;
&lt;p&gt;Plus étonnant est la valeur que prend le hook &lt;code&gt;nmihk&lt;/code&gt;, qui est appelé en cas d'&lt;strong&gt;interruption non masquable&lt;/strong&gt;. Cette interruption est appelée lors de l'appui sur la touche &lt;code&gt;Delta&lt;/code&gt; du VG5000µ. La routine &lt;code&gt;resetlang&lt;/code&gt; met le système en anglais au niveau des messages et du clavier puis ressort de l'interruption. Et c'est tout.&lt;/p&gt;
&lt;p&gt;À vrai dire, cela ne dure &lt;strong&gt;qu'un instant&lt;/strong&gt;. Juste après, le VG5000µ initialise sa partie graphique puis remplace le hook par une nouvelle valeur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_reset&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;ef&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette nouvelle routine &lt;code&gt;test_reset&lt;/code&gt; vérifie si la touche &lt;code&gt;Ctrl&lt;/code&gt; est appuyée. Si ce n'est pas le cas, la routine sort immédiatement. Sinon, un reset &lt;em&gt;à chaud&lt;/em&gt; a lieu.&lt;/p&gt;
&lt;h3&gt;Mise en place d'une routine&lt;/h3&gt;
&lt;p&gt;« &lt;strong&gt;Accrocher&lt;/strong&gt; » une routine est assez facile, et demande juste quelques précautions. Afin de prendre un premier exemple, je vais accrocher une routine sur l'&lt;strong&gt;interruption&lt;/strong&gt; qui provoque l'affichage sur le VG5000µ.&lt;/p&gt;
&lt;p&gt;Rapidement, dans le VG5000µ, le &lt;strong&gt;processeur graphique&lt;/strong&gt; est la cause d'une &lt;strong&gt;interruption&lt;/strong&gt; &lt;code&gt;INT&lt;/code&gt; à chaque rafraîchissement. C'est la seule raison, de base, qui provoque cette interruption.&lt;/p&gt;
&lt;p&gt;Lors de l'interruption, le &lt;code&gt;PC&lt;/code&gt; est branché en &lt;code&gt;$0038&lt;/code&gt; et la &lt;strong&gt;première instruction&lt;/strong&gt; y est &lt;code&gt;call inthk&lt;/code&gt;. On a donc une possibilité d'agir lors de l'interruption, avant que le rafraîchissement potentiel de l'écran n'ait lieu (il n'a pas lieu à chaque fois).&lt;/p&gt;
&lt;p&gt;Le code nécessaire pour une routine de « hook » est en deux parties. La première se charge de &lt;strong&gt;modifier le branchement&lt;/strong&gt; du « hook » vers notre routine. La seconde est la &lt;strong&gt;routine elle-même&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Commençons par la &lt;strong&gt;première partie&lt;/strong&gt;. À noter que pour être propre, il faudrait effectuer un chaînage en faisant appeler à notre propre routine une routine éventuellement déjà installée. Je ne m'en occuperai pas ici.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;inthk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="nv"&gt;D0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Adresse du hook&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;A00&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Spécification de l&amp;#39;adresse mémoire d&amp;#39;implémentation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde des registres sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;C3&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Mise en place de la routine sur le HOOK&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inthk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; le &amp;#39;JP&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;int_routine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inthk&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; et l&amp;#39;adresse&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Restauration des registres depuis la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Retour au programme appelant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;int_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le programme est directement commenté. Si depuis le BASIC, ce programme est injecté et appelé, alors... il ne se passera pas grand chose de visible, mais en réalité, le &lt;code&gt;RET&lt;/code&gt; de &lt;code&gt;int_routine&lt;/code&gt; sera appelé à chaque interruption.&lt;/p&gt;
&lt;h2&gt;Une routine plus intéressante&lt;/h2&gt;
&lt;p&gt;Pour rendre les choses plus intéressantes, voici une routine à installer qui &lt;strong&gt;affiche&lt;/strong&gt; à l'écran une petite barre qui tourne.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;screen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;int_routine:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde de AF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;IX&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;no_display&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Respect du timer de rafraîchissement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde de HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Compteur du caractère à afficher&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; S&amp;#39;il est à la dernière position, on boucle&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;display&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;display:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Mise à jour du compteur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du caractère à afficher&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;screen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Affichage&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ix&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Force le ré-affichage&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HL&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Restauration des registres depuis la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;no_display:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AF&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;count:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;cursor:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Les 4 caractères qui forment l&amp;#39;animation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il faut veiller dans cette routine à bien &lt;strong&gt;préserver&lt;/strong&gt; les &lt;strong&gt;registres&lt;/strong&gt; utilisés, nous sommes ici en pleine interruption, nous n'avons aucune connaissance du contexte.&lt;/p&gt;
&lt;p&gt;La lecture de la &lt;strong&gt;variable système&lt;/strong&gt; à travers le registre &lt;code&gt;IX&lt;/code&gt; permet de savoir si le système va considérer un rafraîchissement de l'affichage. La commande &lt;code&gt;DISPLAY&lt;/code&gt; du BASIC influe directement sur une valeur de compteur qui, lorsqu'il arrive à zéro, provoque éventuellement un affichage avant de revenir à sa valeur spécifiée.&lt;/p&gt;
&lt;p&gt;L'affichage n'est cependant &lt;strong&gt;pas systématique&lt;/strong&gt;. Le bit &lt;code&gt;0&lt;/code&gt; de la variable système qui suit le compteur doit être à &lt;code&gt;1&lt;/code&gt; pour que l'affichage est vraiment lieu. Et l'on trouve parsemé dans la ROM des &lt;code&gt;ld (ix+$01),$01&lt;/code&gt; qui signifient qu'un rafraîchissement de l'écran est demandé. Ce que je fais à la fin de la routine.&lt;/p&gt;
&lt;p&gt;La partie après &lt;code&gt;PUSH HL&lt;/code&gt; est un bête &lt;strong&gt;compteur cyclique&lt;/strong&gt; de 0 à 3, qui est ensuite utilisé pour pointer dans un tableau de 4 caractères provoquant l'animation.&lt;/p&gt;
&lt;p&gt;L'&lt;strong&gt;adresse écran&lt;/strong&gt; est calculé en dur et on y place directement le caractère. Puis le contexte est restauré.&lt;/p&gt;
&lt;p&gt;Une dernière note pour comprendre l'affichage du VG5000µ dans sa ROM BASIC. La ROM maintient en &lt;code&gt;$4000&lt;/code&gt; une image logique du contenu de l'écran, et un ensemble de variables systèmes, pointées en tout temps par &lt;code&gt;IX&lt;/code&gt;. Lorsqu'un rafraîchissement à lieu, tout ce contenu est envoyé vers le processeur graphique pour une grande (et lente !) mise à jour.&lt;/p&gt;
&lt;p&gt;Il se peut donc que des modifications aient lieu en mémoire graphique côté processeur qui ne soient pas répercutées tout de suite vers le processeur graphique.&lt;/p&gt;
&lt;p&gt;Mais tout ceci est une autre histoire qui n'est pas le sujet ici.&lt;/p&gt;
&lt;h3&gt;Le test&lt;/h3&gt;
&lt;p&gt;Voici un programme BASIC qui va monter la routine en mémoire. Suivi d'un &lt;code&gt;RUN&lt;/code&gt; pour l'exécuter puis du &lt;code&gt;CALL&lt;/code&gt; pour lancer le hook.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;79FF&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;READ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FIN&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;VAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;POKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;70&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;S&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;30&lt;/span&gt;
&lt;span class="nl"&gt;300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;D1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;
&lt;span class="nl"&gt;310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;DD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;FE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;
&lt;span class="nl"&gt;320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="vg"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;6&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;DD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;CB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;E1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;C9&lt;/span&gt;
&lt;span class="nl"&gt;330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="vg"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;5&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;7&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;FIN&lt;/span&gt;
&lt;span class="kr"&gt;RUN&lt;/span&gt;
&lt;span class="kr"&gt;CALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7A00&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour éviter d'avoir à tout rentrer au clavier, voici le &lt;a href="https://www.triceraprog.fr/files/201909/hk_int.k7"&gt;fichier .k7&lt;/a&gt;. À charger avec &lt;code&gt;CLOAD&lt;/code&gt;, suivi d'un &lt;code&gt;RUN&lt;/code&gt; et du &lt;code&gt;CALL &amp;amp;"7A00"&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;La suite&lt;/h3&gt;
&lt;p&gt;Nous avons vu un exemple de mise en place de routine sur un « hook » du VG5000µ. Dans les articles suivant, j'irai examiner les autres « hook » et dans quels contextes ils sont appelés.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="ASM"></category><category term="Hooks"></category></entry><entry><title>VG5000µ, les chaînes de caractères</title><link href="https://www.triceraprog.fr/vg5000m-les-chaines-de-caracteres.html" rel="alternate"></link><published>2019-08-22T00:00:00+02:00</published><updated>2019-08-22T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-22:/vg5000m-les-chaines-de-caracteres.html</id><summary type="html">&lt;p&gt;Dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-les-variables-en-memoire.html"&gt;article précédent&lt;/a&gt;, on avait vu la &lt;strong&gt;création d'une variable&lt;/strong&gt; dans la zone principale de la mémoire. Cette variable a par défaut un contenu nul, et ne s'occupe pas de savoir si ce contenu est un nombre ou une chaîne de caractères. Les quatre octets de contenus qui suivent les deux octets du nom sont donc tous les quatre à &lt;code&gt;$00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pour qu'une valeur soit associée à une variable, il faut une &lt;strong&gt;instruction d'assignation&lt;/strong&gt;, directement via &lt;code&gt;LET&lt;/code&gt; (éventuellement de manière implicite), plus &lt;strong&gt;indirectement&lt;/strong&gt; avec une instruction &lt;code&gt;FOR&lt;/code&gt;, ou encore &lt;strong&gt;plus indirectement&lt;/strong&gt; par un couple &lt;code&gt;READ&lt;/code&gt;/&lt;code&gt;DATA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Dans tous les cas, la valeur à assigner à la variable est le résultat de l'&lt;strong&gt;évaluation d'une expression&lt;/strong&gt;, c'est-à-dire le résultat d'un calcul numérique ou d'une opération à partir de chaînes.&lt;/p&gt;
&lt;p&gt;Afin de comprendre comment sont créées et stockées les chaînes de caractères, c'est donc du côté de l'évaluation d'expression qu'il faut …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-les-variables-en-memoire.html"&gt;article précédent&lt;/a&gt;, on avait vu la &lt;strong&gt;création d'une variable&lt;/strong&gt; dans la zone principale de la mémoire. Cette variable a par défaut un contenu nul, et ne s'occupe pas de savoir si ce contenu est un nombre ou une chaîne de caractères. Les quatre octets de contenus qui suivent les deux octets du nom sont donc tous les quatre à &lt;code&gt;$00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pour qu'une valeur soit associée à une variable, il faut une &lt;strong&gt;instruction d'assignation&lt;/strong&gt;, directement via &lt;code&gt;LET&lt;/code&gt; (éventuellement de manière implicite), plus &lt;strong&gt;indirectement&lt;/strong&gt; avec une instruction &lt;code&gt;FOR&lt;/code&gt;, ou encore &lt;strong&gt;plus indirectement&lt;/strong&gt; par un couple &lt;code&gt;READ&lt;/code&gt;/&lt;code&gt;DATA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Dans tous les cas, la valeur à assigner à la variable est le résultat de l'&lt;strong&gt;évaluation d'une expression&lt;/strong&gt;, c'est-à-dire le résultat d'un calcul numérique ou d'une opération à partir de chaînes.&lt;/p&gt;
&lt;p&gt;Afin de comprendre comment sont créées et stockées les chaînes de caractères, c'est donc du côté de l'évaluation d'expression qu'il faut commencer.&lt;/p&gt;
&lt;h2&gt;Évaluation d'expression&lt;/h2&gt;
&lt;p&gt;L'évaluation d'une expression commence en &lt;code&gt;$2861&lt;/code&gt; et nous n'allons pas nous y attarder. Nous suivons la piste immédiatement vers la routine de lecture d'une valeur depuis le buffer d'entrée. Cette routine se situe en &lt;code&gt;$28d8&lt;/code&gt; et commence comme suit :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;parse_value:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;chget&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;missing_op&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_num&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_hex_dec&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a_to_z_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_var&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;parse_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_num&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_min&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;#39;NOT&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_not&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;#39;FN&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_fn&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;#39;SGN&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_func&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Voici toute une &lt;strong&gt;série de tests&lt;/strong&gt; pour déterminer ce que contient l'opérande pointée actuellement par &lt;code&gt;HL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On remarque au tout début que la valeur par défaut de l'expression en cours est mis à &lt;code&gt;0&lt;/code&gt; (c'est-à-dire : valeur numérique).&lt;/p&gt;
&lt;p&gt;Puis le premier caractère est lu et la suite de tests ressemble à ceci :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Est-ce qu'on est à la &lt;strong&gt;fin de la ligne&lt;/strong&gt; ? Alors il manque quelque chose...&lt;/li&gt;
&lt;li&gt;Est-ce que c'est un &lt;strong&gt;chiffre&lt;/strong&gt; ? Alors on commence à convertir l'entrée en nombre&lt;/li&gt;
&lt;li&gt;Est-ce que ça commence par &lt;strong&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/strong&gt; ? Alors on commence à décoder un nombre hexa&lt;/li&gt;
&lt;li&gt;Est-ce que c'est une &lt;strong&gt;lettre&lt;/strong&gt; ? Alors on va lire une variable&lt;/li&gt;
&lt;li&gt;Est-ce que c'est un &lt;strong&gt;'+'&lt;/strong&gt; ? On l'ignore et on boucle un caractère plus loin&lt;/li&gt;
&lt;li&gt;Est-ce que c'est un &lt;strong&gt;'.'&lt;/strong&gt; ? Alors on commence à convertir l'entrée en nombre&lt;/li&gt;
&lt;li&gt;Est-ce que c'est un &lt;strong&gt;'-'&lt;/strong&gt; ? Alors on démarre une sous-expression qui sera inversée&lt;/li&gt;
&lt;li&gt;Est-ce que c'est un &lt;strong&gt;'"'&lt;/strong&gt; ? Alors on décode une chaîne !&lt;/li&gt;
&lt;li&gt;Etc... (les trois derniers cas sont pour &lt;code&gt;NOT&lt;/code&gt;, une fonction utilisateur, ou une fonction prédéfinie, puis on continue avec le traitement des parenthèses)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;D'après cette liste, on part donc vers &lt;code&gt;str_to_str&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Les chaînes à la chaîne&lt;/h2&gt;
&lt;p&gt;Arrivée dans &lt;code&gt;str_to_str&lt;/code&gt;, on a &lt;code&gt;HL&lt;/code&gt;qui pointe vers une chaîne qui commence avec des guillemets. La première étape va être de &lt;strong&gt;chercher&lt;/strong&gt; la &lt;strong&gt;fin de la chaîne&lt;/strong&gt; et de &lt;strong&gt;compter&lt;/strong&gt; le nombre de caractères.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;str_to_str:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;direct_str:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;loop_str:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;create_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;create_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;loop_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;create_str:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;skipch&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette routine commence par placer le caractère guillemets dans les registres &lt;code&gt;B&lt;/code&gt; et &lt;code&gt;D&lt;/code&gt;. Les caractères présents dans &lt;code&gt;B&lt;/code&gt; et &lt;code&gt;D&lt;/code&gt; sont des &lt;strong&gt;terminateurs potentiels&lt;/strong&gt;. Cette routine est en effet appelée par un autre chemin directement en &lt;code&gt;direct_str&lt;/code&gt; avec d'autres terminateurs possibles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : ces autres terminateurs possibles sont &lt;code&gt;:&lt;/code&gt; et ',' dans le cas où la chaîne est lue par une instruction &lt;code&gt;READ&lt;/code&gt; depuis une séquence de &lt;code&gt;DATA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La suite du préambule de la routine se fait en poussant sur la pile le pointeur sur la ligne en exécution et en initialisant &lt;code&gt;C&lt;/code&gt; avec &lt;code&gt;-1&lt;/code&gt;. &lt;code&gt;C&lt;/code&gt; est le &lt;strong&gt;compteur de caractères&lt;/strong&gt;. Au passage, on peut en déduire que les chaînes de caractères auront donc comme longueur maximale 255.&lt;/p&gt;
&lt;p&gt;Puis débute la boucle &lt;code&gt;loop_str&lt;/code&gt;, qui commence par avancer le pointeur &lt;code&gt;HL&lt;/code&gt; sur le caractère suivant, récupère la valeur de ce caractère dans &lt;code&gt;A&lt;/code&gt; et incrémente le nombre de caractères.&lt;/p&gt;
&lt;p&gt;Le premier test vérifie si &lt;code&gt;A&lt;/code&gt; &lt;strong&gt;est nul&lt;/strong&gt;. Si c'est le cas, on a atteint la &lt;strong&gt;fin de la chaîne&lt;/strong&gt; et il est temps de la créer. De même que si le caractère est égal à l'un des deux terminateurs. Dans le cas contraire, la boucle est bouclée et le caractère suivant traité.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : mais et s'il y a plus de 255 caractères avant de trouver un terminateur ? Ça ne se passe pas très bien... Il n'y a pas de tests et vous pouvez vérifier (c'est un peu long) qu'il peut se passer des choses étranges.&lt;/p&gt;
&lt;p&gt;Avant de créer la chaîne, il faut mettre les choses en place. Si le dernier caractère sont des guillemets, une routine va les consommer et ignorer tout ce qui est inintéressant, pour recaler &lt;code&gt;HL&lt;/code&gt; sur la prochaine valeur ou instruction.&lt;/p&gt;
&lt;p&gt;Ce pointeur est échangé avec le haut de la pile, qui contenait le début de la chaîne. Ce début de chaîne est avancé de 1 pour ignorer les premier guillemets (le chemin &lt;code&gt;READ&lt;/code&gt; s'arrange pour mettre &lt;code&gt;HL&lt;/code&gt; au bon endroit en sachant qu'il sera incrémenté ici).&lt;/p&gt;
&lt;p&gt;Puis le pointeur de début de chaîne est transféré dans &lt;code&gt;DE&lt;/code&gt; et le nombre de caractères lus dans &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Création de la chaîne temporaire&lt;/h2&gt;
&lt;p&gt;À présent que l'on sait &lt;strong&gt;où est la chaîne&lt;/strong&gt; (pointée par &lt;code&gt;DE&lt;/code&gt;) et &lt;strong&gt;combien de caractères&lt;/strong&gt; elle contient, l'étape suivant consiste à &lt;strong&gt;l'extraire&lt;/strong&gt; dans un endroit où l'évaluation de l'expression ou l'assignation pourra la trouver.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;crt_tmp_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;cpy_to_pool:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;dsctmp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;temppt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;faclo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;cpy_detohl_4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;temppt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;error_out&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout commence par un appel à &lt;code&gt;crt_str_dsc&lt;/code&gt; qui créé un &lt;strong&gt;descripteur temporaire&lt;/strong&gt; de chaîne à l'adresse &lt;code&gt;dsctmp&lt;/code&gt; (&lt;code&gt;$499b&lt;/code&gt;). Dans ce buffer qui sert aux opérations sur les chaînes, la routine placera en premier octet la taille de la chaîne, puis rien de spécial, puis la valeur de 'DE' sur les deux derniers octets.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;descripteurs&lt;/strong&gt; de chaînes font donc &lt;strong&gt;4 octets&lt;/strong&gt;, dont le deuxième est inutilisé.&lt;/p&gt;
&lt;p&gt;Puis, &lt;code&gt;DE&lt;/code&gt; prend la valeur de &lt;code&gt;dsctmp&lt;/code&gt;, le buffer temporaire qui vient d'être initialisé, et &lt;code&gt;HL&lt;/code&gt; la valeur contenue dans la variable système &lt;code&gt;temppt&lt;/code&gt;. Ce pointeur est initialisé par le BASIC vers le buffer &lt;code&gt;tempst&lt;/code&gt;, qui est un buffer de 120 octets réservé.&lt;/p&gt;
&lt;p&gt;Ce pointeur est placé dans l'&lt;strong&gt;accumulateur flottant&lt;/strong&gt;, qui maintient en fait toute &lt;strong&gt;valeur courante&lt;/strong&gt; d'une &lt;strong&gt;expression&lt;/strong&gt;, qu'elle soit numérique (lorsque &lt;code&gt;(valtyp)&lt;/code&gt; vaut &lt;code&gt;0&lt;/code&gt;) ou chaîne (lorsque &lt;code&gt;(valtyp)&lt;/code&gt; vaut &lt;code&gt;1&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Et d'ailleurs, &lt;code&gt;(valtyp)&lt;/code&gt; passe à &lt;code&gt;1&lt;/code&gt; pour indiquer la nature du contenu de l'accumulateur flottant.&lt;/p&gt;
&lt;p&gt;L'appel suivant est une routine qui &lt;strong&gt;copie&lt;/strong&gt; 4 octets pointés par &lt;code&gt;DE&lt;/code&gt; vers ce qui est pointé par &lt;code&gt;HL&lt;/code&gt;. Autrement dit, le &lt;strong&gt;descripteur de chaîne&lt;/strong&gt; qui vient d'être créé est &lt;strong&gt;copié&lt;/strong&gt; vers le buffer temporaire pointé par &lt;code&gt;HL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Comme &lt;code&gt;dsctmp&lt;/code&gt; est placé astucieusement après le buffer &lt;code&gt;tempst&lt;/code&gt;, si jamais, après copie, &lt;code&gt;HL&lt;/code&gt; est égal &lt;code&gt;DE&lt;/code&gt;, alors c'est qu'on a atteint la fin de l'espace de travail, &lt;strong&gt;une erreur est latente&lt;/strong&gt;, traitée un peu plus loin. Comme 120 (la taille du buffer) est divisible par 4 (la taille des descripteurs) on est assuré de tomber juste, et que &lt;code&gt;HL&lt;/code&gt; ne dépasse jamais &lt;code&gt;DE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En attendant de traiter l'erreur, il s'agit de mettre les choses en ordre. La variable système &lt;code&gt;(temppt)&lt;/code&gt; est mise à jour avec la nouvelle valeur de &lt;code&gt;HL&lt;/code&gt;, puis on récupère le pointeur sur la ligne depuis la pile, et le caractère pointé par &lt;code&gt;HL&lt;/code&gt; est placé dans &lt;code&gt;A&lt;/code&gt;, tout est prêt pour continuer le décodage.&lt;/p&gt;
&lt;p&gt;Enfin, on sort de la routine si la dernière comparaison n'était pas nulle (il reste de la place dans le buffer temporaire) ou bien on saute vers une erreur indiquant à l'utilisateur que l'opération sur les chaînes de caractères était trop complexe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : il existe 30 emplacements de descripteurs de chaîne dans le buffer temporaire avant que la routine ne laisse tomber avec un message d'erreur. En sachant qu'une expression comme &lt;code&gt;PRINT "ABC" + "CDE" + "DEF"&lt;/code&gt; en consomme 2, ça laisse de la marge...&lt;/p&gt;
&lt;h2&gt;Association de la variable&lt;/h2&gt;
&lt;p&gt;Pour l'&lt;strong&gt;association&lt;/strong&gt; de la &lt;strong&gt;variable&lt;/strong&gt; avec sa &lt;strong&gt;valeur&lt;/strong&gt;, voyons le cas de l'instruction &lt;code&gt;LET&lt;/code&gt; (qui est de toute façon appelée par &lt;code&gt;FOR&lt;/code&gt; et &lt;code&gt;READ&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Passons rapidement sur le début de l'instruction &lt;code&gt;LET&lt;/code&gt; qui récupère l'adresse de la variable à gauche du signe égal selon la méthode décrite dans l'&lt;a href="filename}/Machines/20190818-VG5000-LesVariables.md"&gt;article précédent&lt;/a&gt;, appel l'évaluation de ce qui est à droite du signe égal, et vérifie que les types sont &lt;strong&gt;cohérents&lt;/strong&gt; des deux côtés (soit numérique, soit chaîne de caractères).&lt;/p&gt;
&lt;p&gt;Une fois tout ceci en place, l'association de la chaîne elle-même a lieu :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;let_string:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;faclo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;txttab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;crtstrentry&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;strend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;pop_string&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;dsctmp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;pop_string&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;crtstrentry:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc_from_tmp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;save_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;pop_string:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc_from_tmp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;cpy_detohl_4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En début de routine, &lt;code&gt;HL&lt;/code&gt; pointe vers la &lt;strong&gt;variable à gauche&lt;/strong&gt; du signe &lt;code&gt;=&lt;/code&gt;, on &lt;strong&gt;sauve cette adresse&lt;/strong&gt; sur la pile pour plus tard.&lt;/p&gt;
&lt;p&gt;Puis on récupère dans &lt;code&gt;HL&lt;/code&gt; la valeur de la dernière &lt;strong&gt;expression évaluée&lt;/strong&gt;, qui est dans l'accumulateur flottant. On pousse aussi cette valeur sur la pile et on va chercher deux octets plus loin le pointeur vers la chaîne de caractère elle-même, qui est placée dans &lt;code&gt;DE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;À présent, il s'agit de savoir où sont situés ces &lt;strong&gt;octets de chaînes&lt;/strong&gt;. Le premier cas est une comparaison avec &lt;code&gt;(txttab)&lt;/code&gt;. Si les caractères sont avant, c'est qu'ils sont dans les variables systèmes, et donc dans un &lt;strong&gt;endroit volatile&lt;/strong&gt;, il va donc falloir les &lt;strong&gt;copier ailleurs&lt;/strong&gt; et c'est ce que va faire le saut en &lt;code&gt;crtstrentry&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : si vous vous amusez avec les pointeurs de zones mémoire du BASIC pour déplacer le contenu du code, gardez en tête que pour le BASIC, une chaîne située &lt;em&gt;avant&lt;/em&gt; le code est volatile.&lt;/p&gt;
&lt;p&gt;Le second test vérifie si la chaîne se situe avant &lt;code&gt;(strend)&lt;/code&gt;. Si c'est le cas, c'est que la &lt;strong&gt;chaîne&lt;/strong&gt; se trouve dans le &lt;strong&gt;programme&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : en toute rigueur, la comparaison aurait du être faite avec &lt;code&gt;(vartab)&lt;/code&gt;, car il n'y a pas de contenu de chaînes entre &lt;code&gt;(vartab)&lt;/code&gt; et &lt;code&gt;(strend)&lt;/code&gt;. En regardant d'autres dérivés du BASIC-80, je pense qu'il s'agit d'une adaptation un peu hâtive, car d'autres BASIC-80 semblent placer leurs chaînes différemment. Même si le pointeur de comparaison n'est pas exactement le &lt;em&gt;bon&lt;/em&gt;, le test fonctionne néanmoins, et ce n'est pas plus lent.&lt;/p&gt;
&lt;p&gt;Si la &lt;strong&gt;chaîne&lt;/strong&gt; se trouve &lt;strong&gt;dans le programme&lt;/strong&gt;, on va pouvoir &lt;strong&gt;conserver&lt;/strong&gt; ce pointeur &lt;strong&gt;sans dupliquer&lt;/strong&gt; les octets ailleurs. En effet, un programme n'est pas volatile et le moindre changement dans le listing efface toutes les variables. On est donc assuré que les chaînes de caractères présentes dans le programme lorsque celui-ci tourne restent en place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : cela donne quelques contraintes si vous vous amusez à modifier le listing en cours de route depuis le programme qui tourne...&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;troisième test&lt;/strong&gt;, enfin, vérifie si le contenu de la chaîne ne serait pas par hasard dans un autre buffer temporaire, celui où l'on met le descripteur temporaire (et qui se situe juste avant &lt;code&gt;dsctmp&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : ce troisième test est &lt;strong&gt;étrange&lt;/strong&gt;. Ce buffer est situé dans les variables système et donc est déjà avant le code BASIC. Je ne vois donc pas comment on peut arriver ici. Je pense que c'est un reliquat d’adaptation du BASIC-80 où le buffer temporaire se situe après le code BASIC.&lt;/p&gt;
&lt;p&gt;Le &lt;code&gt;defb $3e&lt;/code&gt; est un instruction morte permettant d'éviter l'exécution du &lt;code&gt;POP DE&lt;/code&gt; qui suit. En effet, ce &lt;code&gt;POP DE&lt;/code&gt; pour récupérer le pointeur sur le descripteur de chaîne a déjà été fait lorsqu'on arrive par là.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;crtstrentry&lt;/code&gt; replace le pointeur HL sur les informations de la chaîne temporaire la plus récente (la plus en haut du buffer temporaire), puis cette adresse et échangée avec celle tenue dans &lt;code&gt;DE&lt;/code&gt; qui est aussi le pointeur vers ce même descripteur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : ici, je &lt;strong&gt;ne sais pas&lt;/strong&gt; dans quel cas &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt; peuvent être différent. L'idée est d'enlever le descripteur de chaîne du buffer temporaire en ajustant le pointeur sur ce buffer &lt;code&gt;(temppt)&lt;/code&gt;, le buffer temporaire étant manipulé comme une pile, la routine &lt;code&gt;bc_from_tmp&lt;/code&gt; est en quelque sorte le &lt;code&gt;pop&lt;/code&gt; de cette pile, dont la valeur part dans &lt;code&gt;BC&lt;/code&gt;, mais avec une sécurité. Si le pointeur &lt;code&gt;HL&lt;/code&gt; n'est pas celui qui était attendu &lt;code&gt;DE&lt;/code&gt; alors le &lt;code&gt;pop&lt;/code&gt; n'a pas lieu, c'est juste une récupération de la valeur en haut de la pile.&lt;/p&gt;
&lt;p&gt;Avec les informations récupérées, un appel à &lt;code&gt;save_str&lt;/code&gt; est effectué, et nous verrons ça juste après.&lt;/p&gt;
&lt;p&gt;Dans tous les cas, la description de chaîne la plus récente du &lt;strong&gt;buffer temporaire&lt;/strong&gt; est à nouveau &lt;strong&gt;récupérée&lt;/strong&gt;, l'adresse de la variable popée de la pile dans &lt;code&gt;HL&lt;/code&gt; et le descripteur temporaire &lt;strong&gt;copié&lt;/strong&gt; vers la valeur de cette &lt;strong&gt;variable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Après une remise en ordre de la pile, on rend la main, la &lt;strong&gt;variable&lt;/strong&gt; est maintenant &lt;strong&gt;associée&lt;/strong&gt; à la valeur de la chaîne.&lt;/p&gt;
&lt;h2&gt;Et la création ?&lt;/h2&gt;
&lt;p&gt;Dans le cas où la chaîne de caractères doit être sauvée quelque part, alors un appel à &lt;code&gt;save_str&lt;/code&gt; est fait.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;save_str&lt;/code&gt; se situe en &lt;code&gt;$3646&lt;/code&gt; et est comme suit :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;save_str:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;alloc_str_mem&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;crt_str_dsc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;copy_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En entrée, &lt;code&gt;HL&lt;/code&gt; pointe vers un &lt;strong&gt;descripteur de variable&lt;/strong&gt; de type chaîne. Le premier des 4 octets contient donc le nombre de caractères, qui est récupéré dans &lt;code&gt;A&lt;/code&gt;. Puis &lt;code&gt;HL&lt;/code&gt; est positionné sur le &lt;strong&gt;premier octet&lt;/strong&gt; de l'&lt;strong&gt;adresse du contenu&lt;/strong&gt; et cette adresse est poussée sur la pile.&lt;/p&gt;
&lt;p&gt;L'appel à &lt;code&gt;alloc_str_mem&lt;/code&gt; &lt;strong&gt;vérifie&lt;/strong&gt; ensuite s'il reste &lt;strong&gt;assez de place&lt;/strong&gt; dans la mémoire dédiée aux chaînes pour ajouter &lt;code&gt;A&lt;/code&gt; octets.&lt;/p&gt;
&lt;p&gt;Si la routine de vérification ressort, c'est qu'il y a de la place (une erreur aurait été immédiatement émise sinon) et une chaîne de &lt;code&gt;A&lt;/code&gt; caractères a été &lt;strong&gt;allouée&lt;/strong&gt;, &lt;code&gt;(fretop)&lt;/code&gt; ajusté, et &lt;code&gt;DE&lt;/code&gt; pointe vers cette nouvelle allocation.&lt;/p&gt;
&lt;p&gt;On récupère alors &lt;code&gt;HL&lt;/code&gt; pour obtenir dans &lt;code&gt;BC&lt;/code&gt; l'adresse actuelle du contenu de la chaîne.&lt;/p&gt;
&lt;p&gt;Un appel à &lt;code&gt;crt_str_dsc&lt;/code&gt; crée une nouveau descripteur dans le buffer temporaire avec &lt;code&gt;DE&lt;/code&gt; comme pointeur de contenu.&lt;/p&gt;
&lt;p&gt;Puis &lt;code&gt;copy_str&lt;/code&gt; est appelé après avoir sauvé le pointeur vers le nouveau descripteur dans la pile et mis la taille de la chaîne dans &lt;code&gt;L&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je ne copie pas le code de &lt;code&gt;copy_str&lt;/code&gt; ici. Il est extrêmement simple et copie &lt;code&gt;L&lt;/code&gt; caractères de la zone pointée par &lt;code&gt;BC&lt;/code&gt; vers la zone pointée par &lt;code&gt;DE&lt;/code&gt;. Autrement dit, de la &lt;strong&gt;chaîne source&lt;/strong&gt; vers l'&lt;strong&gt;emplacement nouvellement alloué&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Au retour, &lt;code&gt;DE&lt;/code&gt; prend la valeur du nouveau descripteur de chaîne, qui est actuellement dans le buffer temporaire et sera récupéré par la fin de la routine de l'instruction &lt;code&gt;LET&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ouf!&lt;/p&gt;
&lt;h3&gt;Ramasse miettes&lt;/h3&gt;
&lt;p&gt;En fait... ce n'est pas tout à fait complet. Lors de la tentative d'allocation de chaîne &lt;code&gt;alloc_str_mem&lt;/code&gt;, s'il n'y a plus de place dans la mémoire dédiée, un &lt;strong&gt;ramasse miettes&lt;/strong&gt; est lancé (garbage collection). Cette routine va compacter la mémoire des chaînes de caractères en comblant les trous des données qui ne sont plus valides, d'anciennes valeurs de chaînes qui ne sont plus pointées par aucune variable.&lt;/p&gt;
&lt;p&gt;C'est un &lt;strong&gt;gros morceau&lt;/strong&gt; qui doit parcourir les variables mais aussi les tableaux, je laisse ça de côté (pour le moment ?).&lt;/p&gt;
&lt;p&gt;À la fin de cette routine, l'allocation est tentée à nouveau. Si lors de cette nouvelle tentative, il n'y a toujours pas assez de mémoire, alors l'&lt;strong&gt;erreur&lt;/strong&gt; est &lt;strong&gt;vraiment lancée&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Un peu de BASIC&lt;/h2&gt;
&lt;p&gt;C'est un peu la tradition de ces articles, voyons maintenant un programme en BASIC qui affiche la valeur des variables. Puisque toutes les variables sont effacées au démarrage d'un programme, il est nécessaire d'en initialiser dans le programme.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ABC&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1000&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;B$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DEF&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1000&lt;/span&gt;
&lt;span class="nl"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;70&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1000&lt;/span&gt;
&lt;span class="nl"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt;
&lt;span class="nl"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;VT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49D8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49DA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;VT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;AT&lt;/span&gt;&lt;span class="il"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;6&lt;/span&gt;
&lt;span class="nl"&gt;1030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;T1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;T2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;T2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;1100&lt;/span&gt;
&lt;span class="nl"&gt;1060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;1070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;1080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$=&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;1090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;2000:&lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;34&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;
&lt;span class="nl"&gt;1200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;2000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;2000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;2010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;
&lt;span class="nl"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;2030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;
&lt;span class="nl"&gt;2040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="il"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nl"&gt;2050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;2060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Va afficher&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ABC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;A$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ABC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;B$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DEF&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;B$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DEF&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La partie du programme entre 10 et 100 s'occupe de &lt;strong&gt;manipuler des variables&lt;/strong&gt; et d'appeler l'affichage de leur contenu.&lt;/p&gt;
&lt;p&gt;La partie entre 1000 et 1200 regarde la &lt;strong&gt;liste des variables&lt;/strong&gt; comme dans l'article précédent, mais ne sélectionne que celles de types &lt;strong&gt;chaînes de caractères&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La partie à partir de 2000 va chercher le nombre de caractères et le pointeur vers les données pour &lt;strong&gt;afficher le tout&lt;/strong&gt;, caractère par caractère.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="BASIC-80"></category></entry><entry><title>VG5000µ, les variables en mémoire</title><link href="https://www.triceraprog.fr/vg5000m-les-variables-en-memoire.html" rel="alternate"></link><published>2019-08-22T00:00:00+02:00</published><updated>2019-08-22T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-22:/vg5000m-les-variables-en-memoire.html</id><summary type="html">&lt;p&gt;Pour terminer cette série sur la gestion de la mémoire par le BASIC sur VG5000µ, j'aborde la manière dont sont stockées les variables en mémoire.&lt;/p&gt;
&lt;h3&gt;Les variables systèmes&lt;/h3&gt;
&lt;p&gt;On l'a vu dans l'article sur la &lt;strong&gt;cartographie&lt;/strong&gt; de la mémoire, il y a six variables systèmes intéressantes sur ce sujet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;(vartab)&lt;/strong&gt; est la première adresse d'une variable. C'est ici que sont stockés les noms des variables numériques (avec leur valeur) ou chaînes (avec un pointeur vers leur contenu),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(arytab)&lt;/strong&gt; est la première adresse de stockage du contenu des tableaux dimensionnés par &lt;code&gt;DIM&lt;/code&gt; (ou bien les tableaux crées par défaut par le BASIC avec un &lt;code&gt;DIM&lt;/code&gt; implicite), avec leur nom, leur taille, et leur contenu (ou pointeurs),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(strend)&lt;/strong&gt; est la première adresse de la zone libre de stockage, tout ce qu'il y a à partir de cette adresse et « au-dessus » jusqu'à la pile (pointée par le registre &lt;code&gt;SP&lt;/code&gt;) est la mémoire BASIC …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Pour terminer cette série sur la gestion de la mémoire par le BASIC sur VG5000µ, j'aborde la manière dont sont stockées les variables en mémoire.&lt;/p&gt;
&lt;h3&gt;Les variables systèmes&lt;/h3&gt;
&lt;p&gt;On l'a vu dans l'article sur la &lt;strong&gt;cartographie&lt;/strong&gt; de la mémoire, il y a six variables systèmes intéressantes sur ce sujet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;(vartab)&lt;/strong&gt; est la première adresse d'une variable. C'est ici que sont stockés les noms des variables numériques (avec leur valeur) ou chaînes (avec un pointeur vers leur contenu),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(arytab)&lt;/strong&gt; est la première adresse de stockage du contenu des tableaux dimensionnés par &lt;code&gt;DIM&lt;/code&gt; (ou bien les tableaux crées par défaut par le BASIC avec un &lt;code&gt;DIM&lt;/code&gt; implicite), avec leur nom, leur taille, et leur contenu (ou pointeurs),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(strend)&lt;/strong&gt; est la première adresse de la zone libre de stockage, tout ce qu'il y a à partir de cette adresse et « au-dessus » jusqu'à la pile (pointée par le registre &lt;code&gt;SP&lt;/code&gt;) est la mémoire BASIC « libre » (ce qui n'est pas tout à fait vrai puisque la mémoire pour les chaînes de caractères est séparée).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(stktop)&lt;/strong&gt; est le haut de la pile, l'adresse un octet au-dessus est la première adresse de la zone réservée pour les chaînes de caractères.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(fretop)&lt;/strong&gt; est le pointeur de la zone libre pour les chaînes de caractères. L'adresse juste au-dessus contient le début des données de chaînes de caractères,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;(memsiz)&lt;/strong&gt; est l'adresse la plus haute adressable par le BASIC, et aussi le haut de l'espace réservée aux chaînes de caractères (inclus).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une première constatation est qu'il y a &lt;strong&gt;deux mémoires réservées&lt;/strong&gt; au BASIC, &lt;strong&gt;disjointes&lt;/strong&gt;. La première est celle qui contiendra tous les &lt;strong&gt;noms&lt;/strong&gt; des variables et les &lt;strong&gt;contenus numériques&lt;/strong&gt;. La place restante de cette zone est donnée par la fonction &lt;code&gt;FRE(0)&lt;/code&gt; (la valeur du paramètre importe peu, seul son type importe).&lt;/p&gt;
&lt;p&gt;La seconde est celle qui contiendra tout le &lt;strong&gt;contenu&lt;/strong&gt; des &lt;strong&gt;chaînes de caractères&lt;/strong&gt;, dans des variables ou dans des tableaux. L'espace restant dans cette zone est donné par la fonction &lt;code&gt;FRE(" ")&lt;/code&gt; (la encore, seul le type du paramètre compte). L'espace est fixe, de 50 octets au démarrage de la machine, et déterminé par le premier paramètre de la commande &lt;code&gt;CLEAR&lt;/code&gt;. Faire un &lt;code&gt;CLEAR 0&lt;/code&gt; est tout à fait possible, mais alors vous ne pourrez plus stocker de chaîne de caractères.&lt;/p&gt;
&lt;h3&gt;Création d'une variable&lt;/h3&gt;
&lt;h4&gt;Aparté sur la commande &lt;code&gt;LET&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Dans le BASIC tel qu'il a été créé à l'université de &lt;strong&gt;Dartmouth&lt;/strong&gt;, chaque ligne doit contenir une commande et une seule. La définition et l'assignation d'une variable se font avec la commande &lt;code&gt;LET&lt;/code&gt;. Cette &lt;strong&gt;obligation&lt;/strong&gt; de commande a un avantage sur l'analyse du programme BASIC par un compilateur ou un interpréteur : s'il n'y a pas de commande, c'est une &lt;strong&gt;erreur de syntaxe&lt;/strong&gt;, et il n'y a pas d'exception.&lt;/p&gt;
&lt;p&gt;Le BASIC de &lt;strong&gt;Microsoft&lt;/strong&gt; a relaxé cette obligation en rendant la commande &lt;code&gt;LET&lt;/code&gt; optionnelle, et cette exception a été conservée par de nombreux BASIC par la suite. Mais pas partout, sur un &lt;strong&gt;ZX81&lt;/strong&gt; par exemple, chaque nouvelle ligne demande d'entrer une instruction via la touche du clavier correspondante, et le &lt;code&gt;LET&lt;/code&gt; est obligatoire.&lt;/p&gt;
&lt;p&gt;Lorsque l'instruction &lt;code&gt;LET&lt;/code&gt; est optionnelle, le décodage du BASIC lors de la tokénisation est plus complexe : il faut vérifier que ce qui est trouvé sur la ligne ne correspond à aucune instruction et dans ce cas-ci, &lt;strong&gt;faire comme si&lt;/strong&gt; une instruction &lt;code&gt;LET&lt;/code&gt; était présente. C'est du code en plus pris dans la ROM.&lt;/p&gt;
&lt;h4&gt;Avant tout, que cherche-t-on ?&lt;/h4&gt;
&lt;p&gt;Lorsque BASIC &lt;strong&gt;rencontre&lt;/strong&gt; une variable, il lui faut toujours en premier lieu &lt;strong&gt;vérifier son existence&lt;/strong&gt;. En effet, la première assignation de valeur à une variable vaut création avec une valeur par défaut.&lt;/p&gt;
&lt;p&gt;Et pour savoir si cette variable existe, il faut en &lt;strong&gt;connaître le nom&lt;/strong&gt;. C'est la première partie de la routine qui se trouve en &lt;code&gt;$38da&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;getvar:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dimflg&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;get_id:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a_to_z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stx_err_prt&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;chget&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;idnum_trail&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a_to_z_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;id_end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;idnum_trail:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;idtrail_skp:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;chget&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;idtrail_skp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a_to_z_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;idtrail_skp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;id_end:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;num_vrble&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rrca&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;chget&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;num_vrble:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;subflg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En premier lieu, (dimflg) est mis à zéro. Cette variable sert lorsque l'on manipule un tableau. Comme on n'a pas encore cette information, la routine part sur du &lt;strong&gt;non tableau&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Note : il se peut que &lt;code&gt;A&lt;/code&gt; soit différent de &lt;code&gt;0&lt;/code&gt;, lorsque l'on arrive par l'instruction &lt;code&gt;DIM&lt;/code&gt;, qui &lt;strong&gt;saute&lt;/strong&gt; par-dessus le &lt;code&gt;XOR A,A&lt;/code&gt;, mais laissons ça de côté, le fonctionnement de &lt;code&gt;DIM&lt;/code&gt; est de l'acrobatie en assembleur Z80...&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HL&lt;/code&gt; pointe, comme souvent lors de décodage d'une ligne, sur l'emplacement de la ligne en cours d'exécution. Si on est arrivé ici, c'est que l'on s'attend à &lt;strong&gt;trouver un nom de variable&lt;/strong&gt; à cet endroit. Le premier caractère est donc lu dans &lt;code&gt;C&lt;/code&gt;, puis il est &lt;strong&gt;vérifié&lt;/strong&gt; que ce caractère est &lt;strong&gt;une lettre&lt;/strong&gt;. En effet, chaque identifiant doit commencer par une lettre.&lt;/p&gt;
&lt;p&gt;Si ce n'est pas le cas, un saut vers le traitement d'une &lt;strong&gt;erreur de syntaxe&lt;/strong&gt; est fait immédiatement.&lt;/p&gt;
&lt;p&gt;Donc le cas contraire, tout comme la routine s'initialise dans un mode &lt;strong&gt;non tableau&lt;/strong&gt;, elle part du principe que la &lt;strong&gt;variable est numérique&lt;/strong&gt;. On place donc &lt;code&gt;0&lt;/code&gt; dans (valtyp), dans lequel est tenu à jour en tout temps le type de l'expression en cours. &lt;code&gt;0&lt;/code&gt; dans (valtyp) signifie &lt;strong&gt;numérique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Par &lt;code&gt;RST CHGET&lt;/code&gt;, un potentiel &lt;strong&gt;second caractère&lt;/strong&gt; pour le nom de la variable est lu. Cette routine &lt;code&gt;chget&lt;/code&gt; renvoie le caractère lu dans &lt;code&gt;A&lt;/code&gt; et l'accompagne de quelques informations. Si le flag &lt;code&gt;Carry&lt;/code&gt; est à &lt;code&gt;1&lt;/code&gt;, cela signifie que le caractère est un chiffre. La routine en profite pour traiter ce cas en sautant plus loin, un chiffre en deuxième caractère est valide.&lt;/p&gt;
&lt;p&gt;Si ce n'était pas un chiffre, on vérifie que c'est une lettre. Note au passage : la première fonction &lt;code&gt;A_TO_Z&lt;/code&gt; lit un caractère depuis ce que pointe &lt;code&gt;HL&lt;/code&gt;, &lt;code&gt;A_TO_Z_2&lt;/code&gt; fait la même vérification mais depuis le caractère déjà présent dans &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si ce &lt;strong&gt;second caractère&lt;/strong&gt; n'est pas une lettre, alors on doit avoir le nom de l'identifiant, on passe à la suite en &lt;code&gt;id_end&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le &lt;code&gt;LD B,A&lt;/code&gt; sauve le second caractère de la variable s'il existe. &lt;code&gt;B&lt;/code&gt; avait été initialisé à &lt;code&gt;0&lt;/code&gt; peut avant.&lt;/p&gt;
&lt;p&gt;Entre &lt;code&gt;idtrail_skp&lt;/code&gt; et &lt;code&gt;id_end&lt;/code&gt; (exclu), une boucle &lt;strong&gt;saute tous les caractères&lt;/strong&gt; qui sont soit des chiffres, soit des lettres. En effet, il est tout à fait &lt;strong&gt;valide&lt;/strong&gt; d'avoir des &lt;strong&gt;noms&lt;/strong&gt; de variables &lt;strong&gt;plus long&lt;/strong&gt; que deux caractères. Même si les caractères surnuméraires sont ignorés.&lt;/p&gt;
&lt;p&gt;Arrivé en &lt;code&gt;id_end&lt;/code&gt;, on vérifie le dernier caractère lu. Est-ce un &lt;code&gt;$&lt;/code&gt;, si non, on saute plus loin en &lt;code&gt;num_vrble&lt;/code&gt;, la variable est bien numérique. Dans le cas contraire, &lt;code&gt;1&lt;/code&gt; est mis dans (valtyp) pour désigner un type chaîne de caractères.&lt;/p&gt;
&lt;p&gt;Puis le second caractère de la variable, qui avait été sauvé dans &lt;code&gt;B&lt;/code&gt; est augmenté de &lt;code&gt;$80&lt;/code&gt; (&lt;code&gt;A&lt;/code&gt; égal à &lt;code&gt;1&lt;/code&gt; après &lt;code&gt;RCCA&lt;/code&gt; vaut &lt;code&gt;$80&lt;/code&gt;). C'est comme cela que les &lt;strong&gt;variables&lt;/strong&gt; de types &lt;strong&gt;chaînes de caractères&lt;/strong&gt; sont &lt;strong&gt;identifiées&lt;/strong&gt; : le second octet de leur nom a le bit 7 à  &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lorsque l'on arrive dans &lt;code&gt;num_vrble&lt;/code&gt;, on a dans &lt;code&gt;C&lt;/code&gt; le premier caractère de la variable, dans &lt;code&gt;B&lt;/code&gt; le second caractère de la variable, porteur de l'information de type chaîne, et (valtyp) qui contient aussi le type de la variable.&lt;/p&gt;
&lt;h4&gt;Aparté sur les noms de variables longs&lt;/h4&gt;
&lt;p&gt;Dans le BASIC original, la simplicité voulu par le langage avait amené les auteurs à ne permette des noms de variables qu'à &lt;strong&gt;une seule lettre&lt;/strong&gt;, éventuellement suivie par un chiffre. Plus tard, les variables de type chaînes ont été ajoutées, et le nombre de caractères étendus.&lt;/p&gt;
&lt;p&gt;Dans le monde de la micro-informatique 8 bits, il n'y a &lt;strong&gt;pas beaucoup de place&lt;/strong&gt; en RAM, et cette limite est soit conservée, soit relaxée par l'intermédiaire du &lt;strong&gt;système permissif&lt;/strong&gt; des &lt;strong&gt;noms longs&lt;/strong&gt;, dont seuls les premiers caractères sont significatifs.&lt;/p&gt;
&lt;p&gt;Sur VG5000µ, ce sont les deux premiers caractères qui comptent. D'ailleurs, tous les noms de variable en interne ont deux caractères, le second caractère étant éventuellement égal à &lt;code&gt;$00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je trouve cette idée de caractères significatifs &lt;strong&gt;désastreuse&lt;/strong&gt;. Si elle part de l'idée que l'on peut utiliser des noms de variables plus expressifs, elle n'en n'offre pas les moyens, car absolument &lt;strong&gt;aucun test&lt;/strong&gt; n'est fait sur ces caractères supplémentaires. D'expérience, il est facile, dans un programme un peu long, de ne plus faire attention au fait que deux noms longs possèdent les deux mêmes premiers caractères.&lt;/p&gt;
&lt;p&gt;Et si l'on y fait attention, il faut alors trouver un autre nom pour éviter la collision, et ce nom perd souvent en signification claire, et par la même perd l'intérêt des noms longs.&lt;/p&gt;
&lt;h4&gt;Pour qui est-ce ?&lt;/h4&gt;
&lt;p&gt;Il existe quelques &lt;strong&gt;contraintes&lt;/strong&gt; sur les variables, et c'est dans l'aiguillage suivant qu'elles sont traitées.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;num_vrble:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;subflg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;aryvar&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;simplevar&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;


&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;subscript&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;simplevar:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La variable système &lt;code&gt;(subflg)&lt;/code&gt; sert à plusieurs choses. Ici, elle donne une &lt;strong&gt;indication&lt;/strong&gt; sur une contrainte au niveau de la variable attendue. Si &lt;code&gt;(subflg)&lt;/code&gt; est à &lt;code&gt;1&lt;/code&gt;, c'est que l'on &lt;strong&gt;s'attend à un tableau&lt;/strong&gt;, le branchement est alors vers la recherche d'une variable tableau.&lt;/p&gt;
&lt;p&gt;Si &lt;code&gt;(subflg)&lt;/code&gt; est supérieur à &lt;code&gt;1&lt;/code&gt;, alors c'est que les &lt;strong&gt;tableaux sont interdits&lt;/strong&gt;, on saute donc vers &lt;code&gt;simplevar&lt;/code&gt;. Les deux cas d'interdictions sont la variable d'index d'un &lt;code&gt;FOR&lt;/code&gt; et la variable paramètre d'une fonction &lt;code&gt;DEFFN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;S'il n'y a &lt;strong&gt;pas de contrainte&lt;/strong&gt; sur cette variable, mais que l'on trouve une parenthèse ouvrante à la suite de la variable, alors c'est qu'il y a un index, et l'on va vers cette routine.&lt;/p&gt;
&lt;p&gt;Et dans le cas contraire, il s'agit d'une variable &lt;strong&gt;simple&lt;/strong&gt;. Ouf!&lt;/p&gt;
&lt;h4&gt;Dans le cas simple&lt;/h4&gt;
&lt;p&gt;Comme cet article va être assez long comme ça, on traitera les tableaux une autre fois. À présent que l'on sait que l'on a affaire à une &lt;strong&gt;variable simple&lt;/strong&gt; (pas un tableau), que l'on a son nom et son type, il est grand temps de vérifier si elle existe !&lt;/p&gt;
&lt;p&gt;La première partie de cette recherche consiste à initialiser le domaine de recherche et... de vérifier si par hasard on ne serait pas en train d'&lt;strong&gt;évaluer une fonction&lt;/strong&gt; &lt;code&gt;DEFFN&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;simplevar:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;subflg&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;prmnam&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;prmval&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;pop_hl_ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;arytab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;vartab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout d'abord, &lt;code&gt;(subflg)&lt;/code&gt; est remis à &lt;code&gt;0&lt;/code&gt;. Le contexte a bien été traité et ne doit plus l'être. Puis le &lt;code&gt;PUSH HL&lt;/code&gt; sert à sauver le pointeur vers la ligne tokenisée en court.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;nom de la variable&lt;/strong&gt;, présente dans &lt;code&gt;BC&lt;/code&gt; est placée dans &lt;code&gt;DE&lt;/code&gt; pour utiliser la &lt;strong&gt;comparaison&lt;/strong&gt; entre &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HL&lt;/code&gt; prend la valeur de la variable système &lt;code&gt;(prmnam)&lt;/code&gt; (parameter name), qui contient, s'il y a lieu, le nom de la variable qui sert de paramètre à une fonction &lt;code&gt;DEFFN&lt;/code&gt; en train d'être évaluée.&lt;/p&gt;
&lt;p&gt;Si la variable que l'on cherche est &lt;strong&gt;celle du paramètre&lt;/strong&gt; d'une &lt;strong&gt;fonction&lt;/strong&gt; que l'on est en train d'&lt;strong&gt;évaluer&lt;/strong&gt;, il faut la traiter spécialement, car le nom de cette variable ne doit pas affecter une variable du même nom hors de la fonction.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;traitement spécial&lt;/strong&gt; consiste à, si &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt; sont égaux, &lt;strong&gt;sortir immédiatement&lt;/strong&gt; de la routine de recherche, en faisant pointer &lt;code&gt;DE&lt;/code&gt; sur la variable système &lt;code&gt;prmval&lt;/code&gt;. Ce buffer de 4 octets contient la &lt;strong&gt;valeur actuelle&lt;/strong&gt; du paramètre de la fonction, et &lt;code&gt;DE&lt;/code&gt; est le pointeur que renvoie la routine de recherche de variable pour identifier la valeur cherchée.&lt;/p&gt;
&lt;p&gt;Dans le cas d'une recherche générique, &lt;code&gt;DE&lt;/code&gt; est initialisé avec &lt;code&gt;(arytab)&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt; avec &lt;code&gt;(vartab)&lt;/code&gt;, les deux bornes de la mémoire contenant les variables simples.&lt;/p&gt;
&lt;h4&gt;Cette fois on cherche !&lt;/h4&gt;
&lt;p&gt;Ça y est, après tous ces préparatifs, on arrive au point de la &lt;strong&gt;recherche de la variable&lt;/strong&gt; dans la mémoire ! Et pour cela, la routine va dérouler une boucle qui va cherche parmi tous les variables existantes une dont le nom correspond.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;next_var:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_var_yet&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;var_diff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;var_diff:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;var_found&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;next_var&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En début de &lt;strong&gt;boucle&lt;/strong&gt;, une &lt;strong&gt;comparaison&lt;/strong&gt; entre &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt; est faite. Si les deux sont égaux, c'est qu'on a &lt;strong&gt;fini la recherche&lt;/strong&gt;. En effet, tout au long de la boucle, &lt;code&gt;HL&lt;/code&gt;, parti de &lt;code&gt;(vartab)&lt;/code&gt;, va être incrémenté. &lt;code&gt;DE&lt;/code&gt; représente la limite haute, qui ne bouge pas.&lt;/p&gt;
&lt;p&gt;Si la recherche est terminée sans avoir trouvé la variable, alors on saute en &lt;code&gt;no_var_yet&lt;/code&gt;, il va falloir &lt;strong&gt;la créer&lt;/strong&gt;. En effet, tout accès à une variable en BASIC induit sa création si elle n'existe pas encore.&lt;/p&gt;
&lt;p&gt;En se souvenant que &lt;code&gt;BC&lt;/code&gt; contient le nom de la variable inversé, le premier caractère, dans &lt;code&gt;C&lt;/code&gt; est soustrait de celui pointé par &lt;code&gt;HL&lt;/code&gt;. S'ils sont &lt;strong&gt;différents&lt;/strong&gt;, c'est qu'on n'a &lt;strong&gt;pas trouvé&lt;/strong&gt; la variable pour le moment, on saute plus loin.&lt;/p&gt;
&lt;p&gt;Si le &lt;strong&gt;premier caractère&lt;/strong&gt; correspond, on fait le même test avec le &lt;strong&gt;second caractère&lt;/strong&gt;. Si ces &lt;strong&gt;deux tests passent&lt;/strong&gt;, alors on a &lt;strong&gt;trouvé le nom&lt;/strong&gt;, on saute en &lt;code&gt;var_found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sinon, on saute les quatre octets suivants, qui contiennent la valeur de la variable, et on boucle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : comme le nom de la variable en interne est modifié en fonction de son type, cette recherche montre bien que les variables &lt;code&gt;A&lt;/code&gt; et &lt;code&gt;A$&lt;/code&gt; sont deux variables différentes. De même que les fonctions, que l'on n'a fait qu'effleurer. Dans la cas d'une fonction définition par &lt;code&gt;DEF FN A(...)&lt;/code&gt;, c'est le premier des deux octets qui porte un bit 7 à &lt;code&gt;1&lt;/code&gt;, et qui défini donc une troisième espace de nom.&lt;/p&gt;
&lt;p&gt;Le cas où les deux octets aurait un bit 7 à &lt;code&gt;1&lt;/code&gt; pourrait définir une fonction sur des chaînes de caractères. Mais ce cas n'est pas permis par le BASIC sur VG5000µ.&lt;/p&gt;
&lt;h3&gt;Création de la variable&lt;/h3&gt;
&lt;p&gt;De la section précédente, on peut sortir soit en ayant trouvé la variable, soit en ne l'ayant pas trouvé. Si la &lt;strong&gt;variable n'est pas trouvé&lt;/strong&gt;, il faut la &lt;strong&gt;créer&lt;/strong&gt; et l'initialiser puis enchaîner sur la section où la variable est trouvée... si elle a pu être créée bien entendu.&lt;/p&gt;
&lt;p&gt;Comme c'est assez long, voyons ça en plusieurs partie. Tout d'abord, la création elle-même, avec un petit &lt;strong&gt;plot twist&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;no_var_yet:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;from_eval&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;ret_null&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0006&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;strend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;mem_move_ckk&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;strend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arytab&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout d'abord, on récupère le pointeur sur la ligne évaluée qui était depuis la pile et on l'échange avec la valeur actuellement en haut de la pile. C'est un pas de danse assez &lt;strong&gt;classique en Z80&lt;/strong&gt; qui permet d'aller &lt;strong&gt;récupérer&lt;/strong&gt; la valeur en &lt;strong&gt;deuxième position&lt;/strong&gt; sur la pile.&lt;/p&gt;
&lt;p&gt;Puis on sauve la valeur de &lt;code&gt;DE&lt;/code&gt; (qui contient &lt;code&gt;(arytab)&lt;/code&gt;) avant d'y mettre une valeur spécifique : l'adresse d'une instruction de retour après un &lt;code&gt;CALL&lt;/code&gt; particulier. Cette adresse est le chemin que prend l'appel à la &lt;strong&gt;récupération&lt;/strong&gt; d'une variable lors de l'&lt;strong&gt;évaluation&lt;/strong&gt; d'une &lt;strong&gt;expression&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Si on vient de là, alors c'est un cas spécifique, et on saute à la section &lt;code&gt;ret_null&lt;/code&gt; qui est un &lt;strong&gt;raccourci&lt;/strong&gt; qui renvoie directement la valeur nulle à l'appelant. Et tout ceci &lt;strong&gt;sans créer de variable&lt;/strong&gt; ! Après tout, pourquoi créer une variable qui a sa valeur par défaut ? Nous verrons &lt;code&gt;ret_null&lt;/code&gt; plus loin.&lt;/p&gt;
&lt;p&gt;Dans le cas où l'on ne vient par d'une évaluation, alors l'adresse de retour est remise à sa place sur la pile et on y repousse le pointeur sur la ligne exécutée.&lt;/p&gt;
&lt;p&gt;Il s'agit maintenant de &lt;strong&gt;vérifier&lt;/strong&gt; s'il y a de la &lt;strong&gt;place en mémoire&lt;/strong&gt; pour créer la variable. Une variable a besoin de 6 octets en mémoire, et c'est donc avec 6 qu'est initialisé &lt;code&gt;BC&lt;/code&gt; (après avoir été sauvé sur la pile, car &lt;code&gt;BC&lt;/code&gt; contenait une information importante : le nom de la variable).&lt;/p&gt;
&lt;p&gt;Ici, il faut suivre... &lt;code&gt;HL&lt;/code&gt; est initialisé avec &lt;code&gt;(strend)&lt;/code&gt;, c'est-à-dire la première adresse libre en mémoire principale et on lui ajoute 6 via &lt;code&gt;BC&lt;/code&gt;. Au passage, sur la pile est poussé &lt;code&gt;(strend)&lt;/code&gt;, qui est récupéré dans &lt;code&gt;BC&lt;/code&gt;, puis l'adresse &lt;code&gt;(strend) + 6&lt;/code&gt; est poussée sur la pile.&lt;/p&gt;
&lt;p&gt;On résume, par ordre croissant, on a :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dans &lt;code&gt;DE&lt;/code&gt; se trouve &lt;code&gt;(arytab)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Dans &lt;code&gt;BC&lt;/code&gt; se trouve &lt;code&gt;(strend)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Dans &lt;code&gt;HL&lt;/code&gt; se trouve &lt;code&gt;(strend) + 6&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sur la pile on a &lt;code&gt;(strend) + 6&lt;/code&gt; en première position de &lt;code&gt;POP&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout est prêt&lt;/strong&gt; pour appeler &lt;code&gt;mem_move_chk&lt;/code&gt; qui va déplacer la zone comprise entre &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;BC&lt;/code&gt;, c'est-à-dire toute la mémoire des tableaux, vers une zone dont l'adresse de fin sera &lt;code&gt;HL&lt;/code&gt;. Autrement dit, les &lt;strong&gt;tableaux&lt;/strong&gt; sont &lt;strong&gt;poussés&lt;/strong&gt; de 6 octets pour faire de la place pour la nouvelle variable.&lt;/p&gt;
&lt;p&gt;Cette routine de &lt;strong&gt;déplacement&lt;/strong&gt; commence aussi par une vérification que la &lt;strong&gt;place nécessaire&lt;/strong&gt; est &lt;strong&gt;disponible&lt;/strong&gt;. Dans le cas contraire, une &lt;strong&gt;erreur&lt;/strong&gt; est levée et le processus est arrêté.&lt;/p&gt;
&lt;p&gt;Après le déplacement de la mémoire pour faire de la place, les variables &lt;code&gt;(strend)&lt;/code&gt; et &lt;code&gt;(arytab)&lt;/code&gt; sont ajustées à leur nouvelles valeur.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;clear_mem:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;clear_mem&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À présent qu'un &lt;strong&gt;emplacement est libre&lt;/strong&gt; pour la variable, on parcourt son emplacement pour y placer des &lt;code&gt;$00&lt;/code&gt; avec cette boucle.&lt;/p&gt;
&lt;p&gt;Puis on récupère le nom de la variable dans &lt;code&gt;DE&lt;/code&gt; et on enregistre ce nom dans les deux premiers octets des 6 octets tout neufs.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;variable&lt;/strong&gt; est à présent &lt;strong&gt;créée&lt;/strong&gt;. Il ne reste plus qu'à &lt;strong&gt;retourner un pointeur&lt;/strong&gt; avec l'emplacement de sa valeur à l'appelant.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;var_found:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;DE&lt;/code&gt; prend la valeur de &lt;code&gt;HL&lt;/code&gt; qui pointe juste après le nom de la variable, donc sur les 4 octets de sa valeur.&lt;/p&gt;
&lt;p&gt;Puis &lt;code&gt;HL&lt;/code&gt; récupère sa valeur de pointeur d'exécution et la routine se termine.&lt;/p&gt;
&lt;h3&gt;Retour de variable non définie&lt;/h3&gt;
&lt;p&gt;On l'a vu juste avant, si, lors de l'évaluation d'une expression, une variable n'est pas trouvée, le BASIC ne va pas créer cette variable et se contentera de renvoyer la valeur nulle pour le type demandé.&lt;/p&gt;
&lt;p&gt;Nous pouvons le confirmer avec cette &lt;strong&gt;petite expérience&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49D8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49DC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A$&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49D8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49DC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Donne :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Aucune variable créée" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201908/VG5000-BASIC-VariableNulleAuto.png"&gt;&lt;/p&gt;
&lt;p&gt;Le nombre à droite est &lt;code&gt;(vartab)&lt;/code&gt; et ne bouge pas, puisque le listing ne bouge pas. La valeur de droite est la valeur de &lt;code&gt;(strend)&lt;/code&gt; et reste constante entre le premier et le second affichage. Aucune variable n'a été créée par les accès à &lt;code&gt;A&lt;/code&gt; et &lt;code&gt;A$&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;différence de 12 octets&lt;/strong&gt; correspond à la variable créé par la &lt;strong&gt;fonction&lt;/strong&gt; elle-même et à la variable paramètre de cette fonction. En effet, et c'est assez étrange, alors que la recherche de variable dans une fonction est court-circuitée, comme expliqué plus haut, le BASIC créé tout de même une variable vide, qui ne sera pas utilisée.&lt;/p&gt;
&lt;p&gt;Du coup, si vous voulez &lt;strong&gt;éviter de perdre 6 octets&lt;/strong&gt;, prenez comme non de paramètre de vos fonction une variable utilisée ailleurs. Elle ne sera pas modifiée.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Changeons un peu l'expérience&lt;/strong&gt; et cette fois, donnons les valeurs nulles (0 pour un nombre, "" pour une chaîne) spécifiquement aux deux variables (le &lt;code&gt;LET&lt;/code&gt; est optionnel, mais je le laisse pour être clair sur la signification de la création de la variable).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Aucune variable créée" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201908/VG5000-BASIC-VariableNulleCreee.png"&gt;&lt;/p&gt;
&lt;p&gt;La valeur de &lt;code&gt;(vartab)&lt;/code&gt; est différente par rapport au premier test car le programme est un peu plus long. Néanmoins, sa valeur ne change pas avant et après la création des variables, ce qui donne une référence. Il y a toujours 12 octets pour les variables créées par la fonction.&lt;/p&gt;
&lt;p&gt;Par contre, &lt;code&gt;(strend)&lt;/code&gt; &lt;strong&gt;augmente de 12 octets&lt;/strong&gt; avant et après les assignations. Les &lt;strong&gt;variables&lt;/strong&gt; ont bien été &lt;strong&gt;créées&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;Et cette valeur nulle ?&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;ret_null:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fac&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;null_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;faclo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Lors du branchement vers &lt;code&gt;ret_null&lt;/code&gt;, &lt;code&gt;A&lt;/code&gt; avait été mis à &lt;code&gt;0&lt;/code&gt;, c'est donc cette valeur que l'on met dans l'&lt;strong&gt;accumulateur flottant&lt;/strong&gt;, qui contient la valeur de l'expression évaluée. Lorsqu'on lit une chaîne, ce sont dans les deux premiers octets de ce même accumulateur que se trouve un pointeur vers la chaîne évaluée. On y place un pointeur vers une chaîne nulle (&lt;code&gt;null_str&lt;/code&gt; contient un &lt;code&gt;$00&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POP HL&lt;/code&gt; récupère le pointeur sur la ligne en exécution. Pas besoin de mettre en place &lt;code&gt;DE&lt;/code&gt;, car cette &lt;strong&gt;branche&lt;/strong&gt; de la routine n'est appelée qu'en cas d'&lt;strong&gt;évaluation d'expression&lt;/strong&gt;, et comme l'adresse de retour a été &lt;strong&gt;enlevée&lt;/strong&gt; de la pile pour comparaison et n'y a pas été remis, le retour ne se fait pas à l'appelant direct (qui irait chercher la valeur de la variable retournée) mais à son appelant précédent (l'évaluateur).&lt;/p&gt;
&lt;p&gt;Est-ce que cette &lt;strong&gt;optimisation acrobatique&lt;/strong&gt; était bien &lt;strong&gt;nécessaire&lt;/strong&gt; ? Je n'ai pas la réponse.&lt;/p&gt;
&lt;h3&gt;Reset de la mémoire&lt;/h3&gt;
&lt;p&gt;Une dernière chose avant de clore cet article. Le BASIC du VG5000µ efface toutes les variables lorsqu'un programme est lancé avec &lt;code&gt;RUN&lt;/code&gt;. On est assuré que la mémoire est « effacée » (le contenu est toujours là, seul les pointeurs sont réinitialisés). Les valeurs spécifiées par un &lt;code&gt;CLEAR&lt;/code&gt; sont par contre conservées.&lt;/p&gt;
&lt;p&gt;De même, les variables sont effacées au moindre changement dans le listing.&lt;/p&gt;
&lt;h3&gt;Un peu de BASIC&lt;/h3&gt;
&lt;p&gt;Et pour terminer, un petit listing BASIC qui va afficher les variables présentes en mémoire... et donc du programme en cours d'exécution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;VT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49D8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49DA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;VT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="il"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; VARIABLE(S)&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;VT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;AT&lt;/span&gt;&lt;span class="il"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;6&lt;/span&gt;
&lt;span class="nl"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;70&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Affiche&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  4 VARIABLE(S)
 PK
 P
 VT
 AT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et &lt;code&gt;PT&lt;/code&gt; ? Comme la variable est créés après la récupération de &lt;code&gt;AT&lt;/code&gt; (&lt;code&gt;(arytab)&lt;/code&gt;), cette variable n'est pas vue par le programme, ce qui est tout à fait conforme à ce qui était attendu.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="BASIC-80"></category></entry><entry><title>VG5000µ, le BASIC cherche ses lignes</title><link href="https://www.triceraprog.fr/vg5000m-le-basic-cherche-ses-lignes.html" rel="alternate"></link><published>2019-08-16T00:00:00+02:00</published><updated>2019-08-16T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-16:/vg5000m-le-basic-cherche-ses-lignes.html</id><summary type="html">&lt;p&gt;Peut-être l'avez vous remarqué, &lt;strong&gt;certains programmes&lt;/strong&gt; en BASIC sont construits avec leur &lt;strong&gt;programme principal&lt;/strong&gt; avec des numéros de ligne « &lt;strong&gt;hauts&lt;/strong&gt; » et ont leurs traitements &lt;strong&gt;souvent appelés&lt;/strong&gt; dans les lignes « &lt;strong&gt;basses&lt;/strong&gt; ».&lt;/p&gt;
&lt;p&gt;Ainsi, dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-un-listing-en-basic.html"&gt;article précédent&lt;/a&gt; sur le listing, le programme commence par un &lt;code&gt;GOTO 10000&lt;/code&gt; et le décodage de ligne est en &lt;code&gt;1300&lt;/code&gt;. À vrai dire, avant que je ne stocke les adresses des &lt;code&gt;tokens&lt;/code&gt; dans un tableau, le &lt;strong&gt;décodage&lt;/strong&gt; systématique de leurs noms étaient dans des &lt;strong&gt;lignes encore plus basses&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La raison en est toute simple : lorsque le &lt;code&gt;BASIC&lt;/code&gt; sur VG5000µ cherche un numéro de ligne, il le cherche &lt;strong&gt;systématiquement depuis le début du programme&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;C'est où que ça cherche ?&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;routine de recherche&lt;/strong&gt; de ligne est en &lt;code&gt;$2347&lt;/code&gt; et est appelée par &lt;code&gt;GOTO&lt;/code&gt;, &lt;code&gt;RESTORE&lt;/code&gt;, &lt;code&gt;RENUM&lt;/code&gt; (beaucoup !), &lt;code&gt;LIST&lt;/code&gt;, &lt;code&gt;AUTO&lt;/code&gt; (à chaque nouvelle ligne), &lt;code&gt;NEW&lt;/code&gt;, mais aussi lorsqu'il s'agit d'&lt;strong&gt;insérer une nouvelle ligne&lt;/strong&gt; dans le listing au bon endroit …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Peut-être l'avez vous remarqué, &lt;strong&gt;certains programmes&lt;/strong&gt; en BASIC sont construits avec leur &lt;strong&gt;programme principal&lt;/strong&gt; avec des numéros de ligne « &lt;strong&gt;hauts&lt;/strong&gt; » et ont leurs traitements &lt;strong&gt;souvent appelés&lt;/strong&gt; dans les lignes « &lt;strong&gt;basses&lt;/strong&gt; ».&lt;/p&gt;
&lt;p&gt;Ainsi, dans l'&lt;a href="https://www.triceraprog.fr/vg5000m-un-listing-en-basic.html"&gt;article précédent&lt;/a&gt; sur le listing, le programme commence par un &lt;code&gt;GOTO 10000&lt;/code&gt; et le décodage de ligne est en &lt;code&gt;1300&lt;/code&gt;. À vrai dire, avant que je ne stocke les adresses des &lt;code&gt;tokens&lt;/code&gt; dans un tableau, le &lt;strong&gt;décodage&lt;/strong&gt; systématique de leurs noms étaient dans des &lt;strong&gt;lignes encore plus basses&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La raison en est toute simple : lorsque le &lt;code&gt;BASIC&lt;/code&gt; sur VG5000µ cherche un numéro de ligne, il le cherche &lt;strong&gt;systématiquement depuis le début du programme&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;C'est où que ça cherche ?&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;routine de recherche&lt;/strong&gt; de ligne est en &lt;code&gt;$2347&lt;/code&gt; et est appelée par &lt;code&gt;GOTO&lt;/code&gt;, &lt;code&gt;RESTORE&lt;/code&gt;, &lt;code&gt;RENUM&lt;/code&gt; (beaucoup !), &lt;code&gt;LIST&lt;/code&gt;, &lt;code&gt;AUTO&lt;/code&gt; (à chaque nouvelle ligne), &lt;code&gt;NEW&lt;/code&gt;, mais aussi lorsqu'il s'agit d'&lt;strong&gt;insérer une nouvelle ligne&lt;/strong&gt; dans le listing au bon endroit, voire de &lt;strong&gt;remplacer&lt;/strong&gt; une ancienne.&lt;/p&gt;
&lt;p&gt;Pour appeler cette routine, il suffit d'assigner à &lt;code&gt;DE&lt;/code&gt; le &lt;strong&gt;numéro&lt;/strong&gt; de ligne &lt;strong&gt;recherché&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;line_search:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;txttab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;line_search_lp:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prelin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ccf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ccf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;line_search_lp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout commence avec l'&lt;strong&gt;initialisation&lt;/strong&gt; de &lt;code&gt;BC&lt;/code&gt; avec $0000 et de &lt;code&gt;HL&lt;/code&gt; avec le pointeur de &lt;strong&gt;début de listing&lt;/strong&gt;. Puis débute la boucle de recherche.&lt;/p&gt;
&lt;p&gt;En &lt;strong&gt;début de boucle&lt;/strong&gt;, la ligne contenue dans &lt;code&gt;BC&lt;/code&gt; est stocké dans une variable système &lt;code&gt;prelin&lt;/code&gt;. Cette variable système contiendra en tout temps le dernier numéro de ligne qui a été trouvé dans le listing.&lt;/p&gt;
&lt;p&gt;Jusqu'au &lt;code&gt;RET Z&lt;/code&gt;, il s'agit de &lt;strong&gt;lire le contenu&lt;/strong&gt; du pointeur de &lt;strong&gt;ligne suivante&lt;/strong&gt; et vérifier s'il est égal à &lt;code&gt;$0000&lt;/code&gt;. Si c'est le cas, ce &lt;code&gt;RET Z&lt;/code&gt; provoque la fin de la routine. Le Carry Flag est à &lt;code&gt;0&lt;/code&gt; grâce au &lt;code&gt;OR&lt;/code&gt; qui précède, ce qui indiquera que la ligne n'a pas été trouvée.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour rappel&lt;/strong&gt;, une ligne de BASIC stockée en mémoire commence par un pointeur de chaînage vers la ligne suivante, ou &lt;code&gt;$0000&lt;/code&gt; s'il s'agit de la dernière ligne.&lt;/p&gt;
&lt;p&gt;On peut être &lt;strong&gt;surpris&lt;/strong&gt; par ce &lt;code&gt;DEC HL&lt;/code&gt; avant le retour de la routine, compensé par le premier &lt;code&gt;INC HL&lt;/code&gt; juste après le &lt;code&gt;RET Z&lt;/code&gt;. Comme le BASIC &lt;strong&gt;sauve&lt;/strong&gt; un octet en fusionnant les 4 octets nuls terminant le chaînage des lignes avec le &lt;code&gt;$00&lt;/code&gt; d'une fin de ligne, le pointeur, qui est un cran après ce &lt;code&gt;$00&lt;/code&gt; de fin de ligne, réintègre le besoin des 4 octets nuls de fin de chaînage.&lt;/p&gt;
&lt;p&gt;Mais si on ne sort pas de la routine, alors cet octet n'est pas fusionné, il faut remettre &lt;code&gt;HL&lt;/code&gt; à sa place initiale.&lt;/p&gt;
&lt;p&gt;Après le &lt;code&gt;RET Z&lt;/code&gt;, le &lt;strong&gt;numéro de la ligne BASIC&lt;/strong&gt;, qui est dans la ligne BASIC stockée formé par les deux octets suivants, est lu dans &lt;code&gt;HL&lt;/code&gt;. Puis &lt;strong&gt;comparé&lt;/strong&gt; à &lt;code&gt;DE&lt;/code&gt; via &lt;code&gt;RST DE_COMPARE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En se souvenant que le numéro de ligne &lt;strong&gt;recherché&lt;/strong&gt; est dans &lt;code&gt;DE&lt;/code&gt;, après cette comparaison, il y a trois cas :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt; &lt;strong&gt;sont égaux&lt;/strong&gt; : on a donc &lt;strong&gt;trouvé&lt;/strong&gt; la ligne. Le flag &lt;code&gt;Z&lt;/code&gt; est mis à &lt;code&gt;1&lt;/code&gt;, le Carry Flag est à &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HL&lt;/code&gt; &lt;strong&gt;est supérieur à&lt;/strong&gt; &lt;code&gt;DE&lt;/code&gt; : on a trouvé un numéro de ligne plus grand que celui recherché. La ligne recherchée &lt;strong&gt;n'existe donc pas&lt;/strong&gt;. &lt;code&gt;Z&lt;/code&gt; est à &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;Carry&lt;/code&gt; est à &lt;code&gt;0&lt;/code&gt; aussi.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HL&lt;/code&gt; &lt;strong&gt;est inférieur à&lt;/strong&gt; &lt;code&gt;DE&lt;/code&gt; : il faut &lt;strong&gt;continuer&lt;/strong&gt; à chercher. &lt;code&gt;Z&lt;/code&gt; est à &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;Carry&lt;/code&gt; est à &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Après la comparaison, &lt;code&gt;HL&lt;/code&gt; est remis à l'adresse sauvée en début de boucle dans &lt;code&gt;BC&lt;/code&gt;, pour revenir sur l'adresse de chaînage. Cette adresse est celle de la ligne que l'on vient de valider comme étant la suivante (voire la bonne !), l'adresse est donc lue à nouveau dans &lt;code&gt;HL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les lignes suivantes traitent les &lt;strong&gt;différents cas&lt;/strong&gt; de &lt;strong&gt;comparaison&lt;/strong&gt; de ligne.&lt;/p&gt;
&lt;p&gt;Tout d'abord le couple &lt;code&gt;CCF&lt;/code&gt; / &lt;code&gt;RET Z&lt;/code&gt; fait &lt;strong&gt;sortir&lt;/strong&gt; la routine si la &lt;strong&gt;ligne a été trouvée&lt;/strong&gt;. &lt;code&gt;CCF&lt;/code&gt; qui inverse la valeur du Carry Flag, le met donc à &lt;code&gt;1&lt;/code&gt; dans le cas où &lt;code&gt;Z&lt;/code&gt; était à 1. En sortie de routine, le Carry Flag à &lt;code&gt;1&lt;/code&gt; indique que la ligne a été trouvée. &lt;code&gt;HL&lt;/code&gt; pointe sur le début de la zone de cette ligne.&lt;/p&gt;
&lt;p&gt;Puis le couple &lt;code&gt;CCF&lt;/code&gt; / &lt;code&gt;RET NC&lt;/code&gt; remet le Carry Flag a son état d'après la comparaison entre &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt; et le test. Dans le cas où &lt;strong&gt;la ligne n'est pas là&lt;/strong&gt;, on &lt;strong&gt;sort&lt;/strong&gt; de la &lt;strong&gt;routine&lt;/strong&gt;, mais donc cette fois avec le Carry Flag à &lt;code&gt;0&lt;/code&gt;, indiquant que la ligne n'a pas été trouvée. &lt;code&gt;HL&lt;/code&gt; pointe alors vers l'adresse de la ligne suivante, et &lt;code&gt;BC&lt;/code&gt; sur la ligne précédente. C'est intéressant dans le cas où l'on veut chaîner une &lt;strong&gt;nouvelle ligne&lt;/strong&gt; entre les deux.&lt;/p&gt;
&lt;p&gt;Si aucun de ces cas de sortie n'a eu lieu, le &lt;code&gt;JR&lt;/code&gt; final repart pour un &lt;strong&gt;nouveau tour&lt;/strong&gt; de boucle.&lt;/p&gt;
&lt;h3&gt;Et NEXT et RETURN ?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;NEXT&lt;/code&gt; et &lt;code&gt;RETURN&lt;/code&gt; sont &lt;strong&gt;deux instructions&lt;/strong&gt; qui provoquent une &lt;strong&gt;rupture de séquence&lt;/strong&gt;. Autrement dit, suite à leur exécution, l'exécution continue ailleurs. En début de boucle si la boucle n'est pas terminée avec &lt;code&gt;NEXT&lt;/code&gt;, ou après le &lt;code&gt;GOSUB&lt;/code&gt; dans le cas du &lt;code&gt;RETURN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;fonctionnement&lt;/strong&gt; de ces instructions est &lt;strong&gt;différent&lt;/strong&gt;. &lt;code&gt;FOR&lt;/code&gt; et &lt;code&gt;GOSUB&lt;/code&gt; vont placer le pointeur sur les instructions en train d'être interprétées dans un endroit sûr. &lt;code&gt;GOSUB&lt;/code&gt; le place &lt;strong&gt;sur la pile&lt;/strong&gt;, &lt;code&gt;FOR&lt;/code&gt; aussi... si des &lt;code&gt;FOR&lt;/code&gt; sont imbriqués, sinon, dans une &lt;strong&gt;variable système&lt;/strong&gt; spécifique &lt;code&gt;(endfor)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lorsqu'il faut reprendre l'exécution, le pointeur vers l'instruction en cours en remis à la valeur sauvegardée (avec son numéro de ligne correspondant, une autre variable système à garder cohérente, &lt;code&gt;(curlin)&lt;/code&gt;) puis le décodage continue.&lt;/p&gt;
&lt;p&gt;Par conséquent, les boucles &lt;code&gt;FOR&lt;/code&gt;/&lt;code&gt;NEXT&lt;/code&gt; et un &lt;code&gt;RETURN&lt;/code&gt; &lt;strong&gt;ne sont pas affectés&lt;/strong&gt; par la recherche de numéro de ligne.&lt;/p&gt;
&lt;h3&gt;Ça optimise ?&lt;/h3&gt;
&lt;p&gt;Choisir pour des destinations de saut de numéros de lignes les plus proches du début du programme est donc &lt;strong&gt;une optimisation&lt;/strong&gt;. Mais soyons franc, c'est une &lt;strong&gt;toute petite&lt;/strong&gt; optimisation. La recherche par parcours de liste chaînée est rapide en assembleur en comparaison de l’évaluation d'une expression un peu complexe avec des variables à manipuler par exemple.&lt;/p&gt;
&lt;p&gt;J'ai pu lire que sur certains &lt;strong&gt;BASICs&lt;/strong&gt; d'autres machines, une optimisation avait été faite par le simple fait de rechercher la ligne de destination &lt;strong&gt;par rapport&lt;/strong&gt; à la ligne actuelle, privilégiant ainsi la localité des sauts. Est-ce que cela serait efficace sur la ROM VG5000µ ? Peut-être... à suivre.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="BASIC-80"></category></entry><entry><title>VG5000µ, un listing en BASIC</title><link href="https://www.triceraprog.fr/vg5000m-un-listing-en-basic.html" rel="alternate"></link><published>2019-08-12T00:00:00+02:00</published><updated>2019-08-12T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-12:/vg5000m-un-listing-en-basic.html</id><summary type="html">&lt;p&gt;Un programme en &lt;strong&gt;BASIC&lt;/strong&gt; qui ferait un listing de lui-même. Reprogrammer l'instruction &lt;code&gt;LIST&lt;/code&gt;. C'est un peu &lt;strong&gt;inutile&lt;/strong&gt;, mais cela est un &lt;strong&gt;prétexte&lt;/strong&gt; pour expliquer comment le programme est stocké en mémoire dans la machine.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;VG5000µ&lt;/strong&gt; utilise une version du &lt;strong&gt;BASIC-80&lt;/strong&gt; de Microsoft. Ce BASIC se retrouve sur d'autres machines dans des versions variées, mais dont on retrouve les grands principes.&lt;/p&gt;
&lt;h2&gt;Structure générale d'un programme en mémoire&lt;/h2&gt;
&lt;p&gt;Comme on l'a vu &lt;a href="https://www.triceraprog.fr/vg5000m-une-cartographie-de-la-memoire-basic.html"&gt;précédemment&lt;/a&gt;, le BASIC respecte un &lt;strong&gt;pointeur&lt;/strong&gt; vers le début du programme qui se nomme (txttab), situé en &lt;code&gt;$488E&lt;/code&gt;. Par défaut avec la ROM interne du VG5000µ, si aucune extension ne l'a modifié, (txttab) vaut &lt;code&gt;$49FC&lt;/code&gt; au démarrage.&lt;/p&gt;
&lt;p&gt;Chaque ligne est composée par les éléments suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une &lt;strong&gt;adresse&lt;/strong&gt; mémoire (sur 2 octets) vers l'emplacement de la &lt;strong&gt;ligne suivante&lt;/strong&gt;, ou &lt;code&gt;$0000&lt;/code&gt; pour marquer la fin de la liste de lignes,&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;numéro de ligne&lt;/strong&gt; (sur 2 octets) qui correspond au numéro …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Un programme en &lt;strong&gt;BASIC&lt;/strong&gt; qui ferait un listing de lui-même. Reprogrammer l'instruction &lt;code&gt;LIST&lt;/code&gt;. C'est un peu &lt;strong&gt;inutile&lt;/strong&gt;, mais cela est un &lt;strong&gt;prétexte&lt;/strong&gt; pour expliquer comment le programme est stocké en mémoire dans la machine.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;VG5000µ&lt;/strong&gt; utilise une version du &lt;strong&gt;BASIC-80&lt;/strong&gt; de Microsoft. Ce BASIC se retrouve sur d'autres machines dans des versions variées, mais dont on retrouve les grands principes.&lt;/p&gt;
&lt;h2&gt;Structure générale d'un programme en mémoire&lt;/h2&gt;
&lt;p&gt;Comme on l'a vu &lt;a href="https://www.triceraprog.fr/vg5000m-une-cartographie-de-la-memoire-basic.html"&gt;précédemment&lt;/a&gt;, le BASIC respecte un &lt;strong&gt;pointeur&lt;/strong&gt; vers le début du programme qui se nomme (txttab), situé en &lt;code&gt;$488E&lt;/code&gt;. Par défaut avec la ROM interne du VG5000µ, si aucune extension ne l'a modifié, (txttab) vaut &lt;code&gt;$49FC&lt;/code&gt; au démarrage.&lt;/p&gt;
&lt;p&gt;Chaque ligne est composée par les éléments suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une &lt;strong&gt;adresse&lt;/strong&gt; mémoire (sur 2 octets) vers l'emplacement de la &lt;strong&gt;ligne suivante&lt;/strong&gt;, ou &lt;code&gt;$0000&lt;/code&gt; pour marquer la fin de la liste de lignes,&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;numéro de ligne&lt;/strong&gt; (sur 2 octets) qui correspond au numéro de ligne BASIC,&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;ensemble d'octets&lt;/strong&gt; représentant le &lt;strong&gt;contenu&lt;/strong&gt; de la ligne, qui se termine pas un &lt;code&gt;$00&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Juste après le zéro se trouve la nouvelle ligne, et la ROM maintient les lignes &lt;strong&gt;dans l'ordre&lt;/strong&gt; de leur numéro de ligne BASIC.&lt;/p&gt;
&lt;p&gt;L'ensemble des &lt;strong&gt;lignes stockées&lt;/strong&gt; forme donc une « &lt;strong&gt;liste chaînée&lt;/strong&gt; » selon le schéma suivant.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Liste chaînée des lignes du BASIC-80 sur VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201908/VG5000-BASIC-Lignes.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : comme la dernière ligne est suivi par le pointeur vers l'adresse $0000, le BASIC en profite pour gagner un octet et ne met pas spécifiquement un $00 à la fin de cette ligne, puisqu'il y en a déjà 4.&lt;/p&gt;
&lt;p&gt;Pour notre programme de &lt;strong&gt;décodage&lt;/strong&gt; de ce qui se trouve dans la mémoire, il va donc falloir d'abord aller récupérer l'adresse de (txttab). On pourrait la mettre en dur, mais faisons ça &lt;strong&gt;proprement&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le BASIC sur VG5000µ n'a comme instruction pour &lt;strong&gt;lire la mémoire&lt;/strong&gt; que &lt;code&gt;PEEK&lt;/code&gt;, qui ne lit qu'un octet. Qu'à cela ne tienne, voici une petite &lt;strong&gt;fonction&lt;/strong&gt; qui, donnée une variable &lt;code&gt;P&lt;/code&gt; pointant sur une zone mémoire, en retourne la valeur entière sur 16 bits qui y est stockée.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;De là, on peut donc partir de (txttab) puis de &lt;strong&gt;parcourir&lt;/strong&gt; tout le &lt;strong&gt;chaînage&lt;/strong&gt; jusqu'à trouver un pointeur nul (&lt;code&gt;$0000&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Ce qui peut donner ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Définition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;fonction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;lire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;un&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;entier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;octets&lt;/span&gt;
&lt;span class="nl"&gt;10030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;488E&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Récupération&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;txttab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Lecture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointeur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="vg"&gt;next&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;suivante&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;10200&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointeur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;est&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;nul&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;plus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;loin&lt;/span&gt;
&lt;span class="nl"&gt;10060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;LI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Sinon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;avant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointeur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;et&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;lit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;numéro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;
&lt;span class="nl"&gt;10070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;On&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;affiche&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;numéro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;
&lt;span class="nl"&gt;10080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1300&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;On&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;avance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointeur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;et&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;décode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;voir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;plus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;loin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Passage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointeur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;vers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;suivante&lt;/span&gt;
&lt;span class="nl"&gt;10100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;10040&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Et&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;boucle&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Voici le &lt;strong&gt;corps principal&lt;/strong&gt; du programme écrit. Avec ça, même en ne mettant qu'un &lt;code&gt;RETURN&lt;/code&gt; en ligne 1300, vous pouvez voir les &lt;strong&gt;numéros de ligne&lt;/strong&gt; du votre programme s'afficher.&lt;/p&gt;
&lt;h2&gt;Décodage du contenu des lignes&lt;/h2&gt;
&lt;p&gt;Les lignes sont formées d'une &lt;strong&gt;suite d'octets&lt;/strong&gt; terminée par un $00, située entre le numéro de la ligne BASIC et l'adresse de début de la ligne suivante.&lt;/p&gt;
&lt;p&gt;Le &lt;strong&gt;contenu&lt;/strong&gt; d'une ligne peut contenir des &lt;strong&gt;caractères&lt;/strong&gt;, mais aussi des &lt;code&gt;tokens&lt;/code&gt;. Les &lt;code&gt;tokens&lt;/code&gt; (jetons en français) représentent les &lt;strong&gt;instructions&lt;/strong&gt;, &lt;strong&gt;fonctions&lt;/strong&gt; et &lt;strong&gt;signes&lt;/strong&gt; reconnus par le BASIC lorsque la ligne a été analysée à l'entrée par le clavier (sur cassette, les tokens sont enregistrés, et donc chargés, directement).&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;token&lt;/code&gt; est facilement reconnaissable, son &lt;strong&gt;bit de poids fort est à 1&lt;/strong&gt;. Autrement dit, si le caractère présent est strictmeent supérieur à 127, il s'agit d'un &lt;code&gt;token&lt;/code&gt;. D'ailleurs, lorsque l'on entre un programme au clavier, le BASIC fait bien attention de mettre tous les caractères entrés sur 7 bits.&lt;/p&gt;
&lt;p&gt;C'est aussi dans ce traitement que le BASIC va chercher, à l'aide d'une &lt;strong&gt;liste de mots-clés&lt;/strong&gt; et signes connus, à &lt;strong&gt;reconnaître&lt;/strong&gt; et donc de &lt;code&gt;tokeniser&lt;/code&gt; la ligne. Dès qu'une &lt;strong&gt;suite de caractères&lt;/strong&gt; est un mot-clé ou un signe &lt;strong&gt;connu&lt;/strong&gt;, la suite de caractères est &lt;strong&gt;remplacée&lt;/strong&gt;, dans la chaîne encodée, par son &lt;code&gt;token&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si les caractères lus ne forment pas un mot connu, ceux-ci sont copiés tels quels dans la ligne encodée.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Par exemple&lt;/strong&gt;, si BASIC encode la ligne : &lt;code&gt;PRINT"HELLO"&lt;/code&gt;, le résultat sera la suite &lt;code&gt;$94,'"', 'H','E,'L','L','O','"',$00&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Le décodage&lt;/h3&gt;
&lt;p&gt;Pour &lt;strong&gt;reconstituer&lt;/strong&gt; la ligne, il s'agit donc de prendre les caractères un par un et de vérifier. Est-ce un &lt;strong&gt;token&lt;/strong&gt; ou pas ? Si ce n'est pas un &lt;code&gt;token&lt;/code&gt;, on l'écrit directement à l'écran (ou presque, on va voir plus loin). Si c'est un &lt;strong&gt;token&lt;/strong&gt;, on soustrait &lt;code&gt;128&lt;/code&gt; à sa valeur pour avoir son index.&lt;/p&gt;
&lt;h4&gt;Les tokens&lt;/h4&gt;
&lt;p&gt;Reste à retrouver le &lt;code&gt;token&lt;/code&gt; dans la table située en &lt;code&gt;$209E&lt;/code&gt; et donc un extrait à partir du début ressemble à cela :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; .ND.OR.EXT&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c4&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; .ATA.NPUT.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c7&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; IM.EAD.ET.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; OTO.UN.F.E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; STORE.OSUB&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d3&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; .ETURN.EM.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; TOP.N.PRIN&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;d0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; T.EF.OKE.R&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; INT.ONT.IS&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; T.LIST.LEA&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette &lt;strong&gt;table&lt;/strong&gt; est &lt;strong&gt;encodée&lt;/strong&gt; de la manière suivante : les mots-clés sont les uns à la suite des autres. Chaque &lt;strong&gt;premier caractère&lt;/strong&gt; a son bit de poids fort à 1, ce qui marque la séparation entre les mots.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Faisons un essai&lt;/strong&gt; : &lt;code&gt;$94&lt;/code&gt; est le &lt;code&gt;token&lt;/code&gt; pour &lt;code&gt;PRINT&lt;/code&gt;, soit 148 en décimal. 148 - 128 = 20. Mais attention, le premier token est 128, donc il faut commencer à compter à partir de &lt;code&gt;0&lt;/code&gt;. Cherchez le &lt;strong&gt;21ième&lt;/strong&gt; mot clé et vous lirez &lt;code&gt;.RINT&lt;/code&gt; (attention, le &lt;code&gt;.PRINT&lt;/code&gt; précédent est le codage de &lt;code&gt;LPRINT&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Pour faire plus &lt;strong&gt;simple&lt;/strong&gt;, vous pouvez aussi compter &lt;strong&gt;21 points&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Dans mon &lt;strong&gt;premier essai&lt;/strong&gt; de programme, j'avais traduit en BASIC ce que fait la ROM en assembleur : à chaque mot-clé, on &lt;strong&gt;parcours la table&lt;/strong&gt; des mots-clés depuis le début. À chaque fois que l'on rencontre un caractère supérieur ou égal a 128, on décroit le numéro du &lt;code&gt;token&lt;/code&gt; d'une unité. &lt;strong&gt;Arrivé à zéro&lt;/strong&gt;, on a trouvé, on peut donc recopier à l'écran tous les caractères (sur 7 bits) jusqu'au prochain supérieur ou égal à 128, exclu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ça fonctionne&lt;/strong&gt;. Mais ce qui est très rapide en assembleur demande beaucoup de manipulations au BASIC. Parcourir un long tableau et faire des comparaisons et des tests est &lt;strong&gt;très lourd&lt;/strong&gt;, même en usant de quelques astuces.&lt;/p&gt;
&lt;p&gt;Lorsqu'il fallait décoder un &lt;code&gt;token&lt;/code&gt; élevé, comme le signe &lt;code&gt;=&lt;/code&gt; (&lt;code&gt;token&lt;/code&gt; 65) ou la fonction &lt;code&gt;MID$&lt;/code&gt; (&lt;code&gt;token&lt;/code&gt; 95, le dernier), le décodage devenait très long, &lt;strong&gt;très très long&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;J'ai donc finalement opté pour payer &lt;strong&gt;le coût&lt;/strong&gt; de décodage une fois, au détriment d'une &lt;strong&gt;consommation mémoire&lt;/strong&gt; plus importante.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;5000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INITIALISATION...&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Affichage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;d&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;un message, parce que c&amp;#39;est un peu long&lt;/span&gt;
&lt;span class="nl"&gt;5010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DIM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;95&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Il&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;96&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;à&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;95&lt;/span&gt;
&lt;span class="nl"&gt;5020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;209E&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;début&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;table&lt;/span&gt;
&lt;span class="nl"&gt;5030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Initialisation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;avec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;
&lt;span class="nl"&gt;5040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nl"&gt;KT:&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Adresse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;courant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;dans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;tableau&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;et&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;augmentation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;l&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;index&lt;/span&gt;
&lt;span class="nl"&gt;5050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Déplacement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;à&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;l&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;adresse suivante de la table&lt;/span&gt;
&lt;span class="nl"&gt;5060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;5080&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;bit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;poids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;fort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;saute&lt;/span&gt;
&lt;span class="nl"&gt;5070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;5050&lt;/span&gt;&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Sinon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;boucle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;l&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;avancée dans la table&lt;/span&gt;
&lt;span class="nl"&gt;5080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;est&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="il"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;c&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;est fini !&lt;/span&gt;
&lt;span class="nl"&gt;5090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;5040&lt;/span&gt;&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Sinon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;boucle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;l&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;enregistrement de l&amp;#39;adresse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : j'aurai pu écrire ça avec une boucle &lt;code&gt;FOR&lt;/code&gt; car pour cette ROM là, je connais la taille de la table, qui ne bougera pas, mais je voulais garder ce bout de code &lt;strong&gt;flexible&lt;/strong&gt;. Il fonctionnera pour une autre tableau d'un autre &lt;code&gt;BASIC-80&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Décoder le &lt;code&gt;token&lt;/code&gt; revient maintenant à aller chercher son adresse dans la table puis de recopier les caractères jusqu'au premier marquant le début du mot suivant.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM KT &amp;lt;- ADRESSE TOKEN(V)&lt;/span&gt;
&lt;span class="mf"&gt;1510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;128&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Calcul du token à partir du caractère lu&lt;/span&gt;
&lt;span class="mf"&gt;1520&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Lecture de l&amp;#39;adresse de son nom en mémoire&lt;/span&gt;
&lt;span class="mf"&gt;1530&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PRINT(KEYWORD(KT))&lt;/span&gt;
&lt;span class="mf"&gt;1540&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Préparation de la chaîne et lecture du premier caractère&lt;/span&gt;
&lt;span class="mf"&gt;1550&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Construction de la chaîne&lt;/span&gt;
&lt;span class="mf"&gt;1560&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Passage à l&amp;#39;adresse suivante&lt;/span&gt;
&lt;span class="mf"&gt;1570&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Lecture du caractère suivant&lt;/span&gt;
&lt;span class="mf"&gt;1580&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;127&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1600&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Si c&amp;#39;est le mot suivant, on saute plus loin&lt;/span&gt;
&lt;span class="mf"&gt;1590&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1550&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM SInon, on boucle sur la construction&lt;/span&gt;
&lt;span class="mf"&gt;1600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R$&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM Le mot est trouvé, on l&amp;#39;affiche et on revient à l&amp;#39;appelant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : j'aurai pu afficher directement chaque caractère plutôt que de construire la chaîne au fur et à mesure. Je n'ai pas vérifié ce qui serait le plus rapide. Cette version là use pas mal la mémoire de chaînes de caractère, c'est certain.&lt;/p&gt;
&lt;h4&gt;Les entiers compactés&lt;/h4&gt;
&lt;p&gt;Je n'ai aucune idée de si c'est leur nom officiel, mais c'est comme celui que je les appelle. Certains &lt;strong&gt;nombres sont encodées&lt;/strong&gt; par le BASIC dans une forme particulière : le caractère &lt;code&gt;$0E&lt;/code&gt; suivi d'un nombre entier codé sur 16 bits (donc deux octets).&lt;/p&gt;
&lt;p&gt;En particulier, les numéros de lignes sont codées de cette manière. Ainsi les instructions de saut comme &lt;code&gt;GOTO&lt;/code&gt; ou &lt;code&gt;GOSUB&lt;/code&gt; n'ont pas à décoder systématiquement le numéro en paramètre. Il a déjà été décodé et stocké dans la ligne.&lt;/p&gt;
&lt;p&gt;Afficher un &lt;strong&gt;entier compacté&lt;/strong&gt; n'est pas très compliqué grâce à la fonction de lecture d'un entier sur 16 bits.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;2999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PRINT(NUM16(I+1))&lt;/span&gt;
&lt;span class="nl"&gt;3000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;pointe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;vers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="vg"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;l&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;entier est juste après&lt;/span&gt;
&lt;span class="nl"&gt;3010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;3020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;On&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;saute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;les&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;deux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractères&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;lus&lt;/span&gt;
&lt;span class="nl"&gt;3030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : lorsque le BASIC utilise un entier compacté, il induit aussi une &lt;strong&gt;fin d'instruction&lt;/strong&gt;. Il n'encode donc pas le séparateur ':' éventuel. Je l'affiche donc ici systématiquement, ce qui n'est pas tout à fait correct car il apparaît parfois en fin de ligne. Ce n'est pas syntaxiquement faux non plus.&lt;/p&gt;
&lt;h4&gt;Les différents cas&lt;/h4&gt;
&lt;p&gt;Il y a donc &lt;strong&gt;trois cas&lt;/strong&gt; pour un caractère à décoder, auquel j'&lt;strong&gt;ajoute une quatrième&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si le caractère est un &lt;code&gt;token&lt;/code&gt;, on le décode,&lt;/li&gt;
&lt;li&gt;Sinon, si le caractère est &lt;code&gt;$0E&lt;/code&gt;, on décode un entier compacté,&lt;/li&gt;
&lt;li&gt;Sinon, s'il est inférieur à 17 ou égal à 30 et 31, c'est un caractère de contrôle, on le remplace par le caractère espace,&lt;/li&gt;
&lt;li&gt;Sinon, on le recopie tel quel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;1300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM DECODE LA LIGNE ENTRE PT ET NX&lt;/span&gt;
&lt;span class="nl"&gt;1310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="il"&gt;-1&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Décodage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;tout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;le&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;contenu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;voir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;note&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;juste&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;après&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Lecture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractère&lt;/span&gt;
&lt;span class="nl"&gt;1330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1500:&lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1370&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Est&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;ce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;un&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="nl"&gt;1340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;3000:&lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1370&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Est&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;ce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;un&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;entier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;comptacté&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="nl"&gt;1350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="il"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Est&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;ce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;un&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractère&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;non&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;affichable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="nl"&gt;1360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Affichage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;du&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;caractère&lt;/span&gt;
&lt;span class="nl"&gt;1370&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Fin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;de&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;boucle&lt;/span&gt;
&lt;span class="nl"&gt;1380&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;REM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Saut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;à&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;la&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;ligne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;quand&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;c&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;est terminé&lt;/span&gt;
&lt;span class="nl"&gt;1390&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : la ROM ne fait pas tout à fait comme ça, elle décode jusqu'à trouver le $00. Dans la pratique, les lignes sont stockées dans l'ordre du chaînage, par ordre de ligne croissant. Je décode donc entre le début du contenu de la chaîne tokenisé et la ligne suivante.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Voilà donc réunies toutes les pièces qui permettent de &lt;strong&gt;lister le programme en mémoire&lt;/strong&gt;... et donc le programme lui-même.&lt;/p&gt;
&lt;p&gt;L'&lt;strong&gt;instruction&lt;/strong&gt; &lt;code&gt;LIST&lt;/code&gt; &lt;strong&gt;incluse&lt;/strong&gt; dans la ROM du VG5000µ est &lt;strong&gt;meilleure&lt;/strong&gt; que cela : les commentaires sont affichés d'une couleur différente, il n'y a pas d'espace avant les numéros de lignes, pas de ':' qui traînent derrière les &lt;code&gt;GOTO&lt;/code&gt; et &lt;code&gt;GOSUB&lt;/code&gt; en fin de ligne.&lt;/p&gt;
&lt;p&gt;Mais l'idée était surtout de montrer comment était encodé le listing en mémoire.&lt;/p&gt;
&lt;p&gt;Et pour finir, le programme en entier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;10000&lt;/span&gt;

&lt;span class="nl"&gt;1300&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM DECODE LA LIGNE ENTRE PT ET NX&lt;/span&gt;
&lt;span class="nl"&gt;1310&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="il"&gt;-1&lt;/span&gt;
&lt;span class="nl"&gt;1320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1330&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1500:&lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1370&lt;/span&gt;
&lt;span class="nl"&gt;1340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;3000:&lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1370&lt;/span&gt;
&lt;span class="nl"&gt;1350&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="il"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;32&lt;/span&gt;
&lt;span class="nl"&gt;1360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;1370&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;span class="nl"&gt;1380&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;
&lt;span class="nl"&gt;1390&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;1500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM KT &amp;lt;- ADRESSE TOKEN(V)&lt;/span&gt;
&lt;span class="nl"&gt;1510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;V&lt;/span&gt;&lt;span class="il"&gt;-128&lt;/span&gt;
&lt;span class="nl"&gt;1520&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1530&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PRINT(KEYWORD(KT))&lt;/span&gt;
&lt;span class="nl"&gt;1540&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1550&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;R$&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1560&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;1570&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;1580&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;1600&lt;/span&gt;
&lt;span class="nl"&gt;1590&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1550&lt;/span&gt;
&lt;span class="nl"&gt;1600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;R$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;2999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM PRINT(NUM16(I+1))&lt;/span&gt;
&lt;span class="nl"&gt;3000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;3010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;3020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;
&lt;span class="nl"&gt;3030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;

&lt;span class="nl"&gt;5000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INITIALISATION...&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;5010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;DIM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="il"&gt;94&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;5020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;209E&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;5030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;
&lt;span class="nl"&gt;5040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;K&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nl"&gt;KT:&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;KW&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;5050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;
&lt;span class="nl"&gt;5060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;5080&lt;/span&gt;
&lt;span class="nl"&gt;5070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;5050&lt;/span&gt;
&lt;span class="nl"&gt;5080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;KT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;RETURN&lt;/span&gt;
&lt;span class="nl"&gt;5090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;5040&lt;/span&gt;

&lt;span class="nl"&gt;10000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;REM DEMARRAGE&lt;/span&gt;
&lt;span class="nl"&gt;10010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;5000&lt;/span&gt;
&lt;span class="nl"&gt;10020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;DEFFNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="il"&gt;256&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;PEEK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;488E&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;10200&lt;/span&gt;
&lt;span class="nl"&gt;10060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;LI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;FNPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;10070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;10080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;GOSUB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;1300&lt;/span&gt;
&lt;span class="nl"&gt;10090&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;PT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vg"&gt;NX&lt;/span&gt;
&lt;span class="nl"&gt;10100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;GOTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;10040&lt;/span&gt;

&lt;span class="nl"&gt;10200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FINI&amp;quot;&lt;/span&gt;

&lt;span class="nl"&gt;11000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category><category term="BASIC-80"></category></entry><entry><title>VG5000µ, une Cartographie de la Mémoire BASIC</title><link href="https://www.triceraprog.fr/vg5000m-une-cartographie-de-la-memoire-basic.html" rel="alternate"></link><published>2019-08-08T00:00:00+02:00</published><updated>2019-08-08T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-08-08:/vg5000m-une-cartographie-de-la-memoire-basic.html</id><summary type="html">&lt;p&gt;Quand j'ai commencé à étudier les documentations sur le VG5000µ, des incohérences sur certains points me sont apparues. Les différentes sources ne donnaient pas les même renseignements. Ou alors je lisais mal. Mais un truc ne collait pas.&lt;/p&gt;
&lt;p&gt;En étudiant la ROM, là encore, ça ne collait pas avec les documentations. Mais le code ne ment pas, j'ai donc débuté une quête de la vérité : que se passe-t-il vraiment ?&lt;/p&gt;
&lt;p&gt;... ce n'était peut-être pas si épique, mais bon...&lt;/p&gt;
&lt;p&gt;L'anomalie qui m'intéresse aujourd'hui est celle de la gestion de la mémoire par le BASIC. Et voici les pièces qui ont provoqué mon étonnement.&lt;/p&gt;
&lt;h3&gt;Première pièce&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;manuel de l'utilisateur&lt;/strong&gt;, page 46, indique que le &lt;strong&gt;premier paramètre&lt;/strong&gt; de la commande définit la totalité de l'espace occupé par les chaînes de caractères et doit être compris entre -32768 et 32767. Spécifier une mémoire à réserver négative est un peu étrange, et un test rapide …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Quand j'ai commencé à étudier les documentations sur le VG5000µ, des incohérences sur certains points me sont apparues. Les différentes sources ne donnaient pas les même renseignements. Ou alors je lisais mal. Mais un truc ne collait pas.&lt;/p&gt;
&lt;p&gt;En étudiant la ROM, là encore, ça ne collait pas avec les documentations. Mais le code ne ment pas, j'ai donc débuté une quête de la vérité : que se passe-t-il vraiment ?&lt;/p&gt;
&lt;p&gt;... ce n'était peut-être pas si épique, mais bon...&lt;/p&gt;
&lt;p&gt;L'anomalie qui m'intéresse aujourd'hui est celle de la gestion de la mémoire par le BASIC. Et voici les pièces qui ont provoqué mon étonnement.&lt;/p&gt;
&lt;h3&gt;Première pièce&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;manuel de l'utilisateur&lt;/strong&gt;, page 46, indique que le &lt;strong&gt;premier paramètre&lt;/strong&gt; de la commande définit la totalité de l'espace occupé par les chaînes de caractères et doit être compris entre -32768 et 32767. Spécifier une mémoire à réserver négative est un peu étrange, et un test rapide montre que passer une valeur négative est rejetée par le BASIC.&lt;/p&gt;
&lt;p&gt;Au passage, un coup d'œil dans la ROM montre que l'instruction &lt;code&gt;CLEAR&lt;/code&gt; utilise une routine qui ne décode que des entiers positifs...&lt;/p&gt;
&lt;p&gt;Plus étonnant, le &lt;strong&gt;second paramètre&lt;/strong&gt;, qui indique la plus haute adresse possible atteignable par le BASIC doit être inférieur à 32767 pour le VG5000 standard, et 42864 pour l'extension mémoire 16ko. Et ne mentionne pas 32ko d'extension.&lt;/p&gt;
&lt;p&gt;42864... Ça ne correspond pas à grand chose. Avec l'extension 16ko, je vois plutôt une adresse maximale à 49151. En effet, la ROM prend les 16 premiers ko, et les 16+16 ko de RAM sont à la suite. 48 * 1024 donne 49152 octets.&lt;/p&gt;
&lt;p&gt;Bref, &lt;strong&gt;louche&lt;/strong&gt;. De plus, un essai direct d'un &lt;code&gt;CLEAR 50, 42864&lt;/code&gt; ne fonctionne pas, un paramètre invalide est indiqué. La routine pour décoder le second paramètre étant une routine qui prend des entiers entre &lt;code&gt;-32768&lt;/code&gt; et &lt;code&gt;32767&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Une cartographie de la mémoire &lt;strong&gt;page 86&lt;/strong&gt; indique que la mémoire peut bien aller jusqu'à &lt;strong&gt;49151&lt;/strong&gt;, qu'il faut spécifier cette valeur en complément à 2 sous une forme négative. C'est incohérent avec la description de &lt;code&gt;CLEAR&lt;/code&gt; mais l'expérience montre que la &lt;strong&gt;cartographie a raison&lt;/strong&gt;. Elle indique aussi des valeur de pointeur (stktop), (fretop), (arytab) et (txttab), mais n'indique pas où les trouver.&lt;/p&gt;
&lt;h3&gt;Deuxième pièce&lt;/h3&gt;
&lt;p&gt;La deuxième source est « &lt;strong&gt;Clefs pour VG5000&lt;/strong&gt; », un livre des éditions du P.S.I.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Page 15&lt;/strong&gt;, la description de CLEAR est globalement reprise avec les mêmes renseignements erronés.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Page 69&lt;/strong&gt;, une cartographie de la mémoire est disponible et indique des noms de variables pointeurs sur des zones mémoire. Plus loin, ces variables systèmes sont décrites, avec leurs adresses. C'est par ici que j'avais commencé à regarder le fonctionnement.&lt;/p&gt;
&lt;p&gt;Deux choses me &lt;strong&gt;paraissaient bizarre&lt;/strong&gt;. Une flèche entre &lt;code&gt;arytab&lt;/code&gt; et &lt;code&gt;fretop&lt;/code&gt; sans nom. Soit. Mais aussi une variable &lt;code&gt;fretop&lt;/code&gt; qui est sous la pile. C'est bizarre car le bas de la pile, c'est déjà le registre &lt;code&gt;SP&lt;/code&gt;, quel intérêt de garder une information comme ça ? Pour protéger la pile ?&lt;/p&gt;
&lt;p&gt;C'est cependant cohérent avec le manuel d'utilisateur et donne une information en plus sur le fait que (memsiz) n'est pas initialisé tout en haut de la RAM disponible mais trois octets avant. Il ajoute une variable de système : (vartab).&lt;/p&gt;
&lt;p&gt;C'est à ce moment là que j'ai commencé à étudier la &lt;strong&gt;ROM&lt;/strong&gt; et voir que (fretop) était initialisé avec la valeur (memsiz), et que lors d'allocation de chaînes de caractères, l'algorithme partait du principe que (fretop) était toujours supérieur à (stktop).&lt;/p&gt;
&lt;p&gt;En fait, l'&lt;strong&gt;erreur d'allocation&lt;/strong&gt; de chaîne était lancée, si je ne me trompais pas (mais le doute est permis quand on regarde des pages de code assembleur), lorsque (fretop) atteignant (stktop) &lt;strong&gt;par le haut&lt;/strong&gt;. Autrement dit, tant que &lt;code&gt;(fretop)-(stktop)&lt;/code&gt; était positif, il y avait de la place. Je détaille ça &lt;strong&gt;plus loin&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et donc, &lt;strong&gt;ça ne collait pas&lt;/strong&gt; avec le schéma.&lt;/p&gt;
&lt;p&gt;Les descriptions des variables sont les suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$488E&lt;/code&gt; : adresse de début du &lt;strong&gt;programme&lt;/strong&gt; Basic (txttab)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$4895&lt;/code&gt; : Adresse du haut de la &lt;strong&gt;pile&lt;/strong&gt; (stktop)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$49C3&lt;/code&gt; : adresse du haut de la zone &lt;strong&gt;"chaînes"&lt;/strong&gt; (fretop)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$49D8&lt;/code&gt; : adresse de début de la zone &lt;strong&gt;"variables"&lt;/strong&gt; (vartab)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$49DA&lt;/code&gt; : adresse de début de la zone &lt;strong&gt;"chaînes"&lt;/strong&gt; (arytab) (c'est incohérent d'après le schéma, mais on se doute bien que &lt;strong&gt;ary&lt;/strong&gt; signifie &lt;strong&gt;array&lt;/strong&gt; est qu'il s'agit en fait de la zone pour les &lt;strong&gt;tableaux&lt;/strong&gt; &lt;code&gt;DIM&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$49DC&lt;/code&gt; : adresse de &lt;strong&gt;fin du stockage&lt;/strong&gt; en cours, n'est pas nommé. Je ne le savais pas à ce moment-là, mais il s'agit de (strend) et c'est le nom qu'il manque entre (arytab) et (fretop)... il faut dire que la description n'est pas hyper parlante. Quel stockage ? En cours de quoi ?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Troisième pièce&lt;/h3&gt;
&lt;p&gt;Le troisième document dans lequel je me suis plongé est celui du &lt;strong&gt;manuel technique&lt;/strong&gt;, en anglais. &lt;strong&gt;Page 6&lt;/strong&gt;, on trouve le tableau source des deux précédents documents., mais là encore, (fretop) est sous la pile...&lt;/p&gt;
&lt;p&gt;Plus loin, &lt;strong&gt;page 9&lt;/strong&gt;, la liste des variables systèmes, là encore probablement la source du livre P.S.I, est donné. On y trouve (txttab), (stktop), (fretop), (vartab), (arytab) avec sa description correcte mentionnant des tableaux, et (fretop), et (strend) indiquant « end of storage in use ».&lt;/p&gt;
&lt;p&gt;La description de (strend) est &lt;strong&gt;un peu plus éclairante&lt;/strong&gt; que sa traduction dans le livre P.S.I, même si ça manque de détail. Il n’apparaît pas dans la cartographie de la mémoire.&lt;/p&gt;
&lt;p&gt;Il n'y a pas d'autres mentions du fonctionnement des allocations mémoire dans ce document, à part un peu à propos de manipulation de (txttab) et (vartab) quand on veut lancer un programme BASIC depuis un ROM d'extension.&lt;/p&gt;
&lt;h3&gt;Quatrième pièce&lt;/h3&gt;
&lt;p&gt;De tous les documents sur le VG5000µ, les plus &lt;strong&gt;dignes de confiances, ceux qui vont un peu plus dans le détail et dans lesquels je n'ai jamais trouvé d'erreur jusqu'à maintenant, ce sont les « &lt;/strong&gt;Technical Bulletin** ». Sur celui du 14 juin 1984, à propos de « BASIC Text Relocation » il est mentionné que (strend) sera bougé, avec (vartab), (arytab) et (temp), si (txttab) est modifié et que le BASIC exécute une des routines qui replace tout ça.&lt;/p&gt;
&lt;p&gt;Pas tellement plus d'information cependant.&lt;/p&gt;
&lt;p&gt;Dans le bulletin du 11 septembre 1984, une mention de (stktop) et (memsiz) est fait, qui donne les bonnes adresses en fonction des différentes configuration de mémoire.&lt;/p&gt;
&lt;h3&gt;Au final...&lt;/h3&gt;
&lt;p&gt;Au final... et bien le mieux est d'aller voir dans la &lt;strong&gt;ROM&lt;/strong&gt; ce qu'il se passe. Et pour chercher, je pars sur deux pistes : où donc est-ce que (fretop) est utilisé, et qu'est-ce que (strend) ?&lt;/p&gt;
&lt;p&gt;(fretop) est utilisé a de nombreux endroits, mais quelques-uns de ses usages sont suffisant pour comprendre.&lt;/p&gt;
&lt;h4&gt;L’initialisation&lt;/h4&gt;
&lt;p&gt;La fonction suivante est appelé lorsqu'il s'agit de &lt;strong&gt;réinitialiser&lt;/strong&gt; la mémoire. Au lancement de la machine, par un appel à &lt;code&gt;NEW&lt;/code&gt;, mais aussi directement en &lt;code&gt;reset_vars&lt;/code&gt; lors d'un &lt;code&gt;RUN&lt;/code&gt; ou en &lt;code&gt;init_vars&lt;/code&gt; lors d'un &lt;code&gt;CLEAR&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;reset_mem:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;txttab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; $2ed9&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;reset_mem_2:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;reset_mem_3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;reset_mem_4:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;vartab&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;reset_vars:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;txttab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;init_vars:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;memsiz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fretop&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;inst_restore&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;vartab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arytab&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;strend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout commence avec comme point de repère (txttab), qui est le &lt;strong&gt;début du programme BASIC&lt;/strong&gt; en cours.&lt;/p&gt;
&lt;p&gt;Le &lt;code&gt;jp reset_mem_3&lt;/code&gt; renvoie en &lt;code&gt;reset_mem_4&lt;/code&gt; après avoir coupé le lien sur la première ligne de &lt;code&gt;BASIC&lt;/code&gt;, effaçant par la même occasion l'accès au programme (qui est toujours là...).&lt;/p&gt;
&lt;p&gt;Cette gymnastique avec &lt;code&gt;reset_mem_3&lt;/code&gt;, qui n'est jamais appelé par ailleurs, vient à mon avis du &lt;strong&gt;patch&lt;/strong&gt; de la ROM 1.1, qui fait tout pour rester stable dans les adresses de routines. Je vérifierai cette théorie plus tard.&lt;/p&gt;
&lt;p&gt;(vartab) est placé deux octets plus loin que (txttab) (HL est aussi incrémenté par le code de &lt;code&gt;reset_mem_3&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;(temp) est placé un octet avec (txttab)&lt;/p&gt;
&lt;p&gt;(fretop) est initialisé à la même adresse que (memsiz), ce qui montre bien que, au moins là, &lt;strong&gt;les cartographie mémoire sont fausses&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'appel à &lt;code&gt;inst_restore&lt;/code&gt; est l'exécution de l'instruction &lt;code&gt;RESTORE&lt;/code&gt; du BASIC, qui va chercher et stocker la première ligne contenant des &lt;code&gt;DATA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Puis enfin, (arytab) et (strend) prennent la valeur de (vartab).&lt;/p&gt;
&lt;p&gt;Un peu plus loin, les lignes suivantes remettent le registre &lt;code&gt;SP&lt;/code&gt; à l'adresse en haut de sa zone, stockée dans (stktop).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;stktop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; $2eff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La conclusion sur l’initialisation de la mémoire est que les &lt;strong&gt;adresses de références&lt;/strong&gt; sont (txttab), (memsiz) et (stktop). Les autres pointeurs sont placés en fonction de ces adresses.&lt;/p&gt;
&lt;h4&gt;Vérification mémoire de chaînes&lt;/h4&gt;
&lt;p&gt;Lorsqu'une chaîne de caractère est sur le point d'être créé, la routine suivante est appelée en premier lieu :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;stktop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; $36bf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;fretop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cpl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de_compare&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;out_str_mem&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À l'entrée de cette routine, &lt;code&gt;A&lt;/code&gt; contient le &lt;strong&gt;nombre de caractères&lt;/strong&gt; de la chaîne à créer.&lt;/p&gt;
&lt;p&gt;Après les trois premières lignes, on se retrouve avec (stktop) dans DE et (fretop) dans HL. Les trois lignes suivantes mettent dans &lt;code&gt;BC&lt;/code&gt; l'inverse de &lt;code&gt;A&lt;/code&gt; (en complément à 2).&lt;/p&gt;
&lt;p&gt;Via le &lt;code&gt;add&lt;/code&gt;, HL contient donc (fretop) moins le &lt;strong&gt;nombre de caractères&lt;/strong&gt; dont on a besoin, (le inc qui suit est la correction de la soustraction en complément à 2).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rst de_compare&lt;/code&gt; est une routine qui &lt;strong&gt;compare&lt;/strong&gt; les valeurs de &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;DE&lt;/code&gt;, si &lt;code&gt;HL&lt;/code&gt; est inférieur à DE, alors le flag &lt;code&gt;Carry&lt;/code&gt; est levé, ce qui provoque le saut qui suit vers l'erreur indiquant qu'il n'y a pas assez de mémoire dans l'espace réservé aux chaînes de caractères.&lt;/p&gt;
&lt;p&gt;Ce qui est important ici, c'est que ce calcul montre que (fretop) &lt;strong&gt;doit être supérieur&lt;/strong&gt; à (stktop). Ce qui montre encore que les schémas sont faux.&lt;/p&gt;
&lt;h4&gt;FRE(" ")&lt;/h4&gt;
&lt;p&gt;Dernière vérification, histoire d'être vraiment certain, en analysant la fonction &lt;code&gt;FRE(" ")&lt;/code&gt;. Cette commande avec une chaîne en paramètre n'est &lt;strong&gt;pas documentée&lt;/strong&gt; dans le manuel d'instruction, mais on la trouve dans les « bulletins ».&lt;/p&gt;
&lt;p&gt;Lorsque &lt;code&gt;FRE&lt;/code&gt; a un paramètre numérique (peu importe lequel), la fonction renvoie la place restante en mémoire &lt;code&gt;BASIC&lt;/code&gt;... pour tout ce qui n'est pas stockage des caractères de chaînes.&lt;/p&gt;
&lt;p&gt;Avec un paramètre alphanumérique, &lt;code&gt;FRE&lt;/code&gt; renvoie l'espace restant dans &lt;strong&gt;la mémoire réservée aux caractères&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et en voici le code :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;inst_fre:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;strend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; $38b1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;inst_fre_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;gstrcu&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;call36e3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;stktop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;fretop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;inst_fre_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;inst_fre_2:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tout commence en plaçant (strend) dans &lt;code&gt;DE&lt;/code&gt; (via &lt;code&gt;HL&lt;/code&gt;). Puis en mettant &lt;code&gt;SP&lt;/code&gt; dans &lt;code&gt;HL&lt;/code&gt; (via le &lt;code&gt;add&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;(valtyp) contient le &lt;strong&gt;type de l'expression&lt;/strong&gt; qui vient d'être évaluée. À l'appel d'une fonction, il s'agit de la valeur du paramètre. Si cette valeur est numérique (= &lt;code&gt;0&lt;/code&gt;), la suite se passe en &lt;code&gt;inst_fre_2&lt;/code&gt; où le résultat de l'opération &lt;code&gt;HL - DE&lt;/code&gt; est mis dans le couple de registres &lt;code&gt;A&lt;/code&gt; et &lt;code&gt;C&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Au passage, notons que la &lt;strong&gt;mémoire restante&lt;/strong&gt; est calculée comme la différence entre le pointeur de pile courant et (strend), ce qui permet de situer correctement la fonction de (strend) comme marquant la fin (adresse haute) du stockage BASIC « listing + variables + tableaux ».&lt;/p&gt;
&lt;p&gt;Si l'expression était alphanumérique, alors il y a deux appels (dont un auquel je n'ai pas encore donné de nom) qui permettent d'appeler le &lt;strong&gt;ramasse miettes&lt;/strong&gt; (Garbage Collection) sur les chaînes de caractères. Passons.&lt;/p&gt;
&lt;p&gt;Puis (stktop) est placé dans &lt;code&gt;DE&lt;/code&gt; et (fretop) dans &lt;code&gt;HL&lt;/code&gt;, avant d'effectuer le même calcul que précédemment &lt;code&gt;HL - DE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ce qui montre à nouveau que (fretop) &lt;strong&gt;doit être supérieur à&lt;/strong&gt; (stktop) et qui indique même que cet espace correspond à la zone de mémoire &lt;strong&gt;libre&lt;/strong&gt; pour les chaînes. Autrement dit, (fretop) présente l'adresse la plus basse des chaînes de caractères, toutes stockées &lt;strong&gt;au-dessus&lt;/strong&gt;. Le nom a probablement provoqué la confusion de sa description comme étant l'adresse &lt;strong&gt;du haut&lt;/strong&gt;, mais c'est en fait une zone qui croît &lt;strong&gt;vers le bas&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;En donc ?&lt;/h3&gt;
&lt;p&gt;(fretop) est un pointeur qui est valide entre (memsiz) et (stktop). L'espace entre (memsiz) et (stktop) est déterminé par le premier paramètre de &lt;code&gt;CLEAR&lt;/code&gt; et (memsiz) est déterminé par le second paramètre de &lt;code&gt;CLEAR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Et grâce à ces informations, nous pouvons &lt;strong&gt;cartographier&lt;/strong&gt;, la mémoire avec ses pointeurs de manière correcte et complète, du moins je l'espère.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cartographie Mémoire VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201908/VG5000-CartographieMémoire.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="BASIC"></category></entry><entry><title>Récréation 3D, Z80 du VG5000µ</title><link href="https://www.triceraprog.fr/recreation-3d-z80-du-vg5000m.html" rel="alternate"></link><published>2019-06-01T00:00:00+02:00</published><updated>2019-06-01T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2019-06-01:/recreation-3d-z80-du-vg5000m.html</id><content type="html">&lt;p&gt;Deux ans déjà que j'avais créé quelques &lt;a href="https://www.triceraprog.fr/recreation-3d.html"&gt;modèles 3D&lt;/a&gt;... Le temps passe vite. Et l'envie m'a repris.&lt;/p&gt;
&lt;p&gt;Voici donc une petite recréation du Z80 présent dans le VG5000µ. Fait depuis des images et je ne suis donc pas complètement certains des mesures. J'irai vérifier la prochaine fois que j'en démonte un, si j'y pense.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Z80 présent dans le VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201906/VG5000-Z80-720.png"&gt;&lt;/p&gt;
&lt;p&gt;Update: nouvelle version, corrigée avec des dimensions DIP plus correctes (mais le boitier du SGS est plat... ça fait donc un mélange)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Z80 présent dans le VG5000µ" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201906/VG5000-Z80-fixed-720.png"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="VG5000"></category><category term="3d"></category><category term="Image"></category><category term="Synthèse"></category></entry><entry><title>Bonne Année 2019 !</title><link href="https://www.triceraprog.fr/bonne-annee-2019.html" rel="alternate"></link><published>2018-12-31T00:00:00+01:00</published><updated>2018-12-31T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-12-31:/bonne-annee-2019.html</id><content type="html">&lt;p&gt;Bonjour à tous. Cette année, j'espère pouvoir faire aboutir un projet autour du VG5000µ que j'ai commencé il y a longtemps et que j'avance petit pas par petit pas.&lt;/p&gt;
&lt;p&gt;En attendant, je vous souhaite :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;B$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;AAHGGGGGCB00A@GGGGCBCB00998898=&amp;lt;10&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;B$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;LB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;2&lt;/span&gt;
&lt;span class="nl"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kr"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;MID$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;B$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;MID$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;B$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="il"&gt;-64&lt;/span&gt;
&lt;span class="nl"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;CHR$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;A&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;I&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À essayer sur votre ancienne machine sous BASIC préférée. Ça devrait être portable sur à peu près toutes les machines avec interpréteur BASIC et des capactités par trop limitées sur les chaînes de caractères (adieu ZX81...). Sur certains, il faudra ajouter &lt;code&gt;LET&lt;/code&gt; aux lignes 10, 20 et 40 pour les assignations de variable.&lt;/p&gt;</content><category term="Divers"></category><category term="BASIC"></category></entry><entry><title>VG5000µ, ajouter des instructions au BASIC ?</title><link href="https://www.triceraprog.fr/vg5000m-ajouter-des-instructions-au-basic.html" rel="alternate"></link><published>2018-10-16T00:00:00+02:00</published><updated>2018-10-16T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-10-16:/vg5000m-ajouter-des-instructions-au-basic.html</id><summary type="html">&lt;p&gt;Il y a quelques temps, un message sur le &lt;strong&gt;forum&lt;/strong&gt; &lt;a href="https://forum.system-cfg.com/"&gt;Config.cfg&lt;/a&gt; demandait s'il était simple ou même possible d'ajouter des &lt;strong&gt;instructions supplémentaires&lt;/strong&gt; à la ROM d'un &lt;strong&gt;VG5000µ&lt;/strong&gt;. C'est une question que je me posais aussi, avec dans l'idée d'ajouter des instructions graphiques utilisant l'implémentation des &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-afficher-le-point.html"&gt;articles précédents&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;J'ai donc continué à étudier la &lt;strong&gt;ROM&lt;/strong&gt; (que je commence à bien connaître maintenant) à la recherche d'une méthode. Et on va voir que ça n'est pas gagné.&lt;/p&gt;
&lt;h4&gt;Le parseur&lt;/h4&gt;
&lt;p&gt;Lorsque la touche &lt;code&gt;RET&lt;/code&gt; du clavier est &lt;strong&gt;appuyée&lt;/strong&gt;, il se passe &lt;strong&gt;plusieurs choses&lt;/strong&gt;. Tout d'abord, un caractère &lt;code&gt;NUL&lt;/code&gt; (valeur 0) est placé dans le buffer d'entrée à l'emplacement du dernier caractère qui n'est pas un espace (adresses &lt;code&gt;$3c4a&lt;/code&gt; à &lt;code&gt;$3c56&lt;/code&gt;). Le &lt;code&gt;RET&lt;/code&gt; à la fin de cette fonction ramène hors de la boucle principal du traitement interactif.&lt;/p&gt;
&lt;p&gt;Après un traitement de la &lt;strong&gt;protection&lt;/strong&gt; de programmes qui n'est pas le sujet ici, une …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Il y a quelques temps, un message sur le &lt;strong&gt;forum&lt;/strong&gt; &lt;a href="https://forum.system-cfg.com/"&gt;Config.cfg&lt;/a&gt; demandait s'il était simple ou même possible d'ajouter des &lt;strong&gt;instructions supplémentaires&lt;/strong&gt; à la ROM d'un &lt;strong&gt;VG5000µ&lt;/strong&gt;. C'est une question que je me posais aussi, avec dans l'idée d'ajouter des instructions graphiques utilisant l'implémentation des &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-afficher-le-point.html"&gt;articles précédents&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;J'ai donc continué à étudier la &lt;strong&gt;ROM&lt;/strong&gt; (que je commence à bien connaître maintenant) à la recherche d'une méthode. Et on va voir que ça n'est pas gagné.&lt;/p&gt;
&lt;h4&gt;Le parseur&lt;/h4&gt;
&lt;p&gt;Lorsque la touche &lt;code&gt;RET&lt;/code&gt; du clavier est &lt;strong&gt;appuyée&lt;/strong&gt;, il se passe &lt;strong&gt;plusieurs choses&lt;/strong&gt;. Tout d'abord, un caractère &lt;code&gt;NUL&lt;/code&gt; (valeur 0) est placé dans le buffer d'entrée à l'emplacement du dernier caractère qui n'est pas un espace (adresses &lt;code&gt;$3c4a&lt;/code&gt; à &lt;code&gt;$3c56&lt;/code&gt;). Le &lt;code&gt;RET&lt;/code&gt; à la fin de cette fonction ramène hors de la boucle principal du traitement interactif.&lt;/p&gt;
&lt;p&gt;Après un traitement de la &lt;strong&gt;protection&lt;/strong&gt; de programmes qui n'est pas le sujet ici, une fonction &lt;strong&gt;cherche&lt;/strong&gt; si la ligne commence par un &lt;strong&gt;numéro de ligne&lt;/strong&gt; puis débute la transcription de la ligne vers une ligne « tokenisée ». La procédure de &lt;strong&gt;tokénisation&lt;/strong&gt;, en bref, va repérer toutes les instructions, fonctions et opérations connues et les transformer en « tokens » : un octet dont le bit de poids fort est à 1.&lt;/p&gt;
&lt;p&gt;Un token permet de prendre moins de place en mémoire et facilite le travail de l'évaluateur.&lt;/p&gt;
&lt;p&gt;La procédure saute bien entendu les chaînes de caractères en repérant les paires de guillemets.&lt;/p&gt;
&lt;p&gt;Je &lt;strong&gt;laisse de côté&lt;/strong&gt; le traitement de caractères à significations particulières (le &lt;code&gt;?&lt;/code&gt; qui remplace &lt;code&gt;PRINT&lt;/code&gt; comme dans la plupart des &lt;strong&gt;BASIC&lt;/strong&gt; par exemple) pour arriver à la &lt;strong&gt;recherche principale&lt;/strong&gt;. Cette routine, qui commence globalement en &lt;code&gt;$23a5&lt;/code&gt;, va &lt;strong&gt;comparer&lt;/strong&gt; le contenu des caractères à décoder (en les passant en majuscules si nécessaire) avec une &lt;strong&gt;liste de noms&lt;/strong&gt; et &lt;strong&gt;symboles&lt;/strong&gt; dans une table située en &lt;code&gt;$23a7&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Premier problème&lt;/strong&gt;, cette &lt;strong&gt;liste&lt;/strong&gt; est &lt;strong&gt;figée&lt;/strong&gt;. Si aucune correspondance n'est trouvée, la routine ne dispose pas de hook pour passer la main à une éventuelle liste gérée par l'utilisateur. Les &lt;strong&gt;caractères&lt;/strong&gt; sans correspondance sont &lt;strong&gt;laissés tels quels&lt;/strong&gt; dans le buffer. Si plus tard, à l'évaluation, ces caractères n'ont pas de sens (ne désignent pas une variable par exemple), une erreur sera émise.&lt;/p&gt;
&lt;p&gt;On pourrait alors imaginer se servir d'un autre &lt;code&gt;hook&lt;/code&gt;, celui qui est appelé à chaque affichage de caractère (&lt;code&gt;$47e2&lt;/code&gt;) ou celui qui est appelé lors d'un retour à la ligne (&lt;code&gt;\$47e5&lt;/code&gt;), afin d'ajouter un parsing à la main. Mais pour cela, il faudrait &lt;strong&gt;choisir&lt;/strong&gt; des &lt;strong&gt;tokens libres&lt;/strong&gt; pour les nouvelles instructions ; ce qui amène à étudier les tokens.&lt;/p&gt;
&lt;h4&gt;Les tokens&lt;/h4&gt;
&lt;p&gt;Voici la liste des tokens avec leurs valeurs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Commandes&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Support -&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Opérateurs&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Fonctions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;128:END&lt;/td&gt;
&lt;td style="text-align: left;"&gt;178:TAB(&lt;/td&gt;
&lt;td style="text-align: left;"&gt;185:+&lt;/td&gt;
&lt;td style="text-align: left;"&gt;195:SGN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;129:FOR&lt;/td&gt;
&lt;td style="text-align: left;"&gt;179:TO&lt;/td&gt;
&lt;td style="text-align: left;"&gt;186:-&lt;/td&gt;
&lt;td style="text-align: left;"&gt;196:INT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;130:NEXT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;180:FN&lt;/td&gt;
&lt;td style="text-align: left;"&gt;187:*&lt;/td&gt;
&lt;td style="text-align: left;"&gt;197:ABS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;131:DATA&lt;/td&gt;
&lt;td style="text-align: left;"&gt;181:SPC(&lt;/td&gt;
&lt;td style="text-align: left;"&gt;188:/&lt;/td&gt;
&lt;td style="text-align: left;"&gt;198:USR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;132:INPUT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;182:THEN&lt;/td&gt;
&lt;td style="text-align: left;"&gt;189:^&lt;/td&gt;
&lt;td style="text-align: left;"&gt;199:FRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;133:DIM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;183:NOT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;190:AND&lt;/td&gt;
&lt;td style="text-align: left;"&gt;200:LPOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;134:READ&lt;/td&gt;
&lt;td style="text-align: left;"&gt;184:STEP&lt;/td&gt;
&lt;td style="text-align: left;"&gt;191:OR&lt;/td&gt;
&lt;td style="text-align: left;"&gt;201:POS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;135:LET&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;192:&amp;gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;202:SQR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;136:GOTO&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;193:=&lt;/td&gt;
&lt;td style="text-align: left;"&gt;203:RND&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;137:RUN&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;194:&amp;lt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;204:LOG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;138:IF&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;205:EXP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;139:RESTORE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;206:COS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;140:GOSUB&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;207:SIN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;141:RETURN&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;208:TAN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;142:REM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;209:ATN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;143:STOP&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;210:PEEK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;144:ON&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;211:LEN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;145:LPRINT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;212:STR$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;146:DEF&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;213:VAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;147:POKE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;214:ASC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;148:PRINT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;215:STICKX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;149:CONT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;216:STICKY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;150:LIST&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;217:ACTION&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;151:LLIST&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;218:KEY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;152:CLEAR&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;219:LPEN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;153:RENUM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;220:CHR$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;154:AUTO&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;221:LEFT$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;155:LOAD&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;222:RIGHT$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;156:SAVE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;223:MID$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;157:CLOAD&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;158:CSAVE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;159:CALL&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;160:INIT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;161:SOUND&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;162:PLAY&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;163:TX&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;164:GR&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;165:SCREEN&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;166:DISPLAY&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;167:STORE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;168:SCROLL&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;169:PAGE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;170:DELIM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;171:SETE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;172:ET&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;173:EG&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;174:CURSOR&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;175:DISK&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;176:MODEM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;177:NEW&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On peut remarquer que cette &lt;strong&gt;liste&lt;/strong&gt; comporte &lt;strong&gt;plusieurs parties&lt;/strong&gt;. La première, de 128 à 177, contient des &lt;strong&gt;instructions&lt;/strong&gt;, c'est-à-dire des &lt;strong&gt;commandes impératives&lt;/strong&gt;, sans valeur de retour.&lt;/p&gt;
&lt;p&gt;De 178 à 184, il s'agit de commandes de &lt;strong&gt;support&lt;/strong&gt;, qui ne peuvent être trouvées qu'en &lt;strong&gt;conjonction&lt;/strong&gt; de commandes maîtresses. Par exemple &lt;code&gt;THEN&lt;/code&gt; avec &lt;code&gt;IF&lt;/code&gt; ; &lt;code&gt;TO&lt;/code&gt; et &lt;code&gt;STEP&lt;/code&gt; avec &lt;code&gt;FOR&lt;/code&gt;,...&lt;/p&gt;
&lt;p&gt;De 185 à 194, il s'agit d'&lt;strong&gt;opérateurs logiques&lt;/strong&gt; et &lt;strong&gt;arithmétiques&lt;/strong&gt;. Enfin, à partir de 195 jusqu'à la fin, 223, il s'agit de &lt;strong&gt;fonctions&lt;/strong&gt;, qui retournent des &lt;strong&gt;valeurs&lt;/strong&gt;, et qui apparaîtrons donc, au côté des opérateurs, dans des &lt;strong&gt;expressions&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On commence à sentir que s'il fallait &lt;strong&gt;ajouter&lt;/strong&gt; des mot-clés, en fonction de leur nature, il faudrait les &lt;strong&gt;placer&lt;/strong&gt; dans le &lt;strong&gt;bon groupe&lt;/strong&gt;. Sauf que cette &lt;strong&gt;liste&lt;/strong&gt; est &lt;strong&gt;compacte&lt;/strong&gt;. On peut imaginer ajouter des fonctions après &lt;code&gt;MID$&lt;/code&gt;, mais ajouter une instruction ou un opérateur &lt;strong&gt;décalerait&lt;/strong&gt; toute la table, ce qui poserait un problème de compatibilité au moins avec les programmes enregistrés (les programmes &lt;strong&gt;BASIC&lt;/strong&gt; enregistrés le sont sous forme tokenisée).&lt;/p&gt;
&lt;h4&gt;L'évaluateur&lt;/h4&gt;
&lt;p&gt;C'est donc vers l'&lt;strong&gt;évaluateur&lt;/strong&gt; qu'il faut se tourner et se demander comment sont &lt;strong&gt;traitées&lt;/strong&gt; les lignes en &lt;strong&gt;BASIC&lt;/strong&gt;. Et c'est là que vient se planter le dernier clou dans le cercueil de l'ajout de commandes utilisateurs... du moins sans modifier la &lt;strong&gt;ROM&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tout d'abord, examinons le décodage des tokens en &lt;code&gt;$250f&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;inst_let&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Comme tous les tokens sont supérieurs ou égaux&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="c1"&gt;; à $80, si le caractère est inférieur, c&amp;#39;est le début du nom d&amp;#39;une variable.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="c1"&gt;; C&amp;#39;est un LET implicite.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stx_err_prt&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Les 50 ($32) premiers tokens seulement sont des instructions&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="c1"&gt;; Si le token est après, alors c&amp;#39;est une Erreur de syntaxe.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Voilà&lt;/strong&gt;... la &lt;strong&gt;ROM&lt;/strong&gt; contient &lt;strong&gt;en dur&lt;/strong&gt; les &lt;strong&gt;bornes&lt;/strong&gt; des instructions pouvant être décodées.&lt;/p&gt;
&lt;p&gt;Et ce n'est &lt;strong&gt;pas fini&lt;/strong&gt;. Lorsque l'on regarde l'évaluation d'expression en &lt;code&gt;$28d8&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;valtyp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Type numérique par défaut&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;rst&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;chget&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;missing_op&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Cas où le caractère est NUL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_num&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Cas où le caractère est un chiffre.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_hex_dec&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Saut si sur le point de parser un nombre en hexa (caractère &amp;#39;&amp;amp;&amp;#39;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a_to_z_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_var&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Saut si la valeur est entre A et Z&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b9&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Token pour &amp;#39;+&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;parse_value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Caractère &amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_num&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Token pour &amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_min&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Caractère &amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b7&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Token pour &amp;#39;NOT&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_not&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b4&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Token pour &amp;#39;FN&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_fn&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c3&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Token pour &amp;#39;SGN&amp;#39;, la première des fonctions&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;str_to_func&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Afin de déterminer le type de valeur à décoder, un certain nombre de tokens est là aussi &lt;strong&gt;en dur&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;Et donc ?&lt;/h4&gt;
&lt;p&gt;Et donc &lt;strong&gt;tel quel&lt;/strong&gt;, la &lt;strong&gt;ROM&lt;/strong&gt; ne &lt;strong&gt;fourni pas&lt;/strong&gt; de &lt;strong&gt;mécanisme&lt;/strong&gt; d’extension pour écrire de &lt;strong&gt;nouvelles instructions&lt;/strong&gt;. D'autre part, même s'il reste une trentaine de tokens libres à la fin de la liste, les constantes dans le parseur et dans l'évaluateur exigent que les tailles des groupes du tableau soient respectés.&lt;/p&gt;
&lt;p&gt;Reste la &lt;strong&gt;possibilité&lt;/strong&gt; de &lt;strong&gt;modifier&lt;/strong&gt; la &lt;strong&gt;ROM&lt;/strong&gt; pour ajouter les nouvelles instructions, ce qui n'est pas très compliqué, mais qui nécessitera de la &lt;strong&gt;conversion&lt;/strong&gt; au chargement pour être &lt;strong&gt;compatible&lt;/strong&gt; avec des programmes en &lt;strong&gt;BASIC&lt;/strong&gt; enregistrés sur K7.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ROM"></category><category term="ASM"></category></entry><entry><title>VG5000µ, Schémas de principe</title><link href="https://www.triceraprog.fr/vg5000m-schemas-de-principe.html" rel="alternate"></link><published>2018-09-01T00:00:00+02:00</published><updated>2018-09-01T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-09-01:/vg5000m-schemas-de-principe.html</id><summary type="html">&lt;p&gt;Le &lt;strong&gt;schéma de principe&lt;/strong&gt; scanné depuis la documentation de maintenance trouvée sur le &lt;a href="http://vg5000.free.fr/"&gt;site My VG5000&lt;/a&gt; et reconstitué du &lt;strong&gt;VG5000µ&lt;/strong&gt; m'a souvent aidé à comprendre le fonctionnement de cette machine. Et &lt;strong&gt;je remercie l'auteur&lt;/strong&gt; de ce travail !&lt;/p&gt;
&lt;p&gt;Pour contribuer à mon tour à la &lt;strong&gt;documentation VG5000µ&lt;/strong&gt;, j'ai refait les schémas de la &lt;strong&gt;platine principale&lt;/strong&gt; et de la &lt;strong&gt;platine k7&lt;/strong&gt; au propre, afin d'en augmenter la &lt;strong&gt;lisibilité&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Quelques commentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;j'ai ajouté en précision les broches non branchées du &lt;strong&gt;Z80&lt;/strong&gt; et de l'&lt;strong&gt;EF9345&lt;/strong&gt;. Cela montre rapidement les choix hardware du VG5000µ qui ne seront pas contournables sans modification du matériel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai utilisé les nomenclatures des &lt;strong&gt;datasheets&lt;/strong&gt; des composants, ce qui change un peu la &lt;strong&gt;nomenclature&lt;/strong&gt; originale.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai gardé la disposition générale du schéma, pour ne pas perdre les habitués, mais il peut y avoir quelques changements dans le détail, lorsque je pensais pouvoir améliorer la lisibilité.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai modifié les marquages des …&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Le &lt;strong&gt;schéma de principe&lt;/strong&gt; scanné depuis la documentation de maintenance trouvée sur le &lt;a href="http://vg5000.free.fr/"&gt;site My VG5000&lt;/a&gt; et reconstitué du &lt;strong&gt;VG5000µ&lt;/strong&gt; m'a souvent aidé à comprendre le fonctionnement de cette machine. Et &lt;strong&gt;je remercie l'auteur&lt;/strong&gt; de ce travail !&lt;/p&gt;
&lt;p&gt;Pour contribuer à mon tour à la &lt;strong&gt;documentation VG5000µ&lt;/strong&gt;, j'ai refait les schémas de la &lt;strong&gt;platine principale&lt;/strong&gt; et de la &lt;strong&gt;platine k7&lt;/strong&gt; au propre, afin d'en augmenter la &lt;strong&gt;lisibilité&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Quelques commentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;j'ai ajouté en précision les broches non branchées du &lt;strong&gt;Z80&lt;/strong&gt; et de l'&lt;strong&gt;EF9345&lt;/strong&gt;. Cela montre rapidement les choix hardware du VG5000µ qui ne seront pas contournables sans modification du matériel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai utilisé les nomenclatures des &lt;strong&gt;datasheets&lt;/strong&gt; des composants, ce qui change un peu la &lt;strong&gt;nomenclature&lt;/strong&gt; originale.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai gardé la disposition générale du schéma, pour ne pas perdre les habitués, mais il peut y avoir quelques changements dans le détail, lorsque je pensais pouvoir améliorer la lisibilité.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j'ai modifié les marquages des portes logiques vers une nomenclature en toute lettre ; par contre, je n'ai aucune idée de la nomenclature officiel pour un Buffer, j'ai mis BUF en attendant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;une porte &lt;strong&gt;AND&lt;/strong&gt;, en sortie des deux portes NAND du 7812 n'avait pas de marquage sur le schéma originel, j'ai retrouvé le composant en suivant le schéma d'implantation (ce n'était pas trop compliqué, puisque qu'il n'y a qu'un seul composant qui fourni des portes AND, mais au moins, c'est vérifié)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le schéma original comporte la plupart des signaux en anglais, sauf quelques-uns (genre RVB), j'ai gardé RVB sur les sorties mais changé en RGB sur la nomenclature EF9345, comme sur la &lt;strong&gt;datasheet&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;De même il y a un mélange &lt;strong&gt;COMMUT.RAPIDE&lt;/strong&gt; mais &lt;strong&gt;SOUND&lt;/strong&gt; sur la &lt;strong&gt;sortie vidéo&lt;/strong&gt;, j'ai tout &lt;strong&gt;unifié&lt;/strong&gt; en français.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mais du coup, j'ai des signaux en anglais sur la sortie &lt;strong&gt;SON/K7&lt;/strong&gt;...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Merci à tous les commentateurs du &lt;a href="https://forum.system-cfg.com/viewtopic.php?f=7&amp;amp;t=9245"&gt;fil de discussion&lt;/a&gt; sur System.cfg qui m'ont permis d'améliorer les schémas.&lt;/p&gt;
&lt;h4&gt;La platine principale&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 29 avril 2021)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/202104/VG5000-Schema-v1.4.png"&gt;&lt;img alt="Platine principale" src="https://www.triceraprog.fr/images/202104/VG5000-Schema-v1.4-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;La platine K7/Son&lt;/h4&gt;
&lt;p&gt;Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2.png"&gt;&lt;img alt="Platine K7/Son" src="https://www.triceraprog.fr/images/201809/VG5000-Schema-k7-v1.2-750.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;Le schéma a été mis à jour dans &lt;a href="https://www.triceraprog.fr/vg5000m-schemas-de-principe-mis-a-jour-en-v15.html"&gt;un nouvel article&lt;/a&gt;.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Schéma"></category></entry><entry><title>VG5000µ, SetPoint en C</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-c.html" rel="alternate"></link><published>2018-06-25T00:00:00+02:00</published><updated>2018-06-25T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-06-25:/vg5000m-setpoint-en-c.html</id><summary type="html">&lt;p&gt;Après cette implémentation en &lt;strong&gt;assembleur Z80&lt;/strong&gt; d'une fonction &lt;code&gt;setpoint&lt;/code&gt; qui affiche, de manière assez basique, un point à l'écran, je me pose la question d'utiliser un langage de &lt;strong&gt;plus haut niveau&lt;/strong&gt;... mais pas trop.&lt;/p&gt;
&lt;p&gt;J'ai une assez longue expérience du &lt;strong&gt;C&lt;/strong&gt; et la question que je me pose est : qu'est-ce que ça donne de &lt;strong&gt;programmer en C&lt;/strong&gt; pour générer du code &lt;strong&gt;sur Z80&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Programmer en C a quelques avantages a priori : c'est nettement &lt;strong&gt;plus concis&lt;/strong&gt; et lisible que de l'assembleur, j'y suis &lt;strong&gt;plus habitué&lt;/strong&gt; et c'est &lt;strong&gt;portable&lt;/strong&gt; sur de nombreuses plateformes. C'est le cas d'autres langages, mais le choix naturel pour moi puisque écrire du C m'est habituel. En tout cas bien plus habituel que d'écrire directement de l'assembleur Z80.&lt;/p&gt;
&lt;h4&gt;Premier essai&lt;/h4&gt;
&lt;p&gt;Voici le code C d'un premier essai :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt; // Afin d&amp;#39;utiliser les types standards&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Définition de la fonction&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;// En entrée …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Après cette implémentation en &lt;strong&gt;assembleur Z80&lt;/strong&gt; d'une fonction &lt;code&gt;setpoint&lt;/code&gt; qui affiche, de manière assez basique, un point à l'écran, je me pose la question d'utiliser un langage de &lt;strong&gt;plus haut niveau&lt;/strong&gt;... mais pas trop.&lt;/p&gt;
&lt;p&gt;J'ai une assez longue expérience du &lt;strong&gt;C&lt;/strong&gt; et la question que je me pose est : qu'est-ce que ça donne de &lt;strong&gt;programmer en C&lt;/strong&gt; pour générer du code &lt;strong&gt;sur Z80&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Programmer en C a quelques avantages a priori : c'est nettement &lt;strong&gt;plus concis&lt;/strong&gt; et lisible que de l'assembleur, j'y suis &lt;strong&gt;plus habitué&lt;/strong&gt; et c'est &lt;strong&gt;portable&lt;/strong&gt; sur de nombreuses plateformes. C'est le cas d'autres langages, mais le choix naturel pour moi puisque écrire du C m'est habituel. En tout cas bien plus habituel que d'écrire directement de l'assembleur Z80.&lt;/p&gt;
&lt;h4&gt;Premier essai&lt;/h4&gt;
&lt;p&gt;Voici le code C d'un premier essai :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt; // Afin d&amp;#39;utiliser les types standards&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Définition de la fonction&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;// En entrée, les coordonnées&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;// Pas de valeur de retour (void)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// Les mêmes calculs qu&amp;#39;en BASIC&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x4000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Je dois ajouter une fonction `main` pour que le fichier CRT puisse en trouver une.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;J'ai globalement laissé les &lt;strong&gt;mêmes noms&lt;/strong&gt; de variable que j'ai utilisé dans la version &lt;strong&gt;BASIC&lt;/strong&gt;, et les &lt;strong&gt;mêmes calculs&lt;/strong&gt;. C'est un &lt;strong&gt;portage simple&lt;/strong&gt;, sans trop se poser de questions.&lt;/p&gt;
&lt;h4&gt;Le compilateur SCCZ80&lt;/h4&gt;
&lt;p&gt;Afin de &lt;strong&gt;transformer&lt;/strong&gt; le code C &lt;strong&gt;en code machine&lt;/strong&gt;, il me faut un &lt;strong&gt;compilateur&lt;/strong&gt; qui sache sortir du langage machine &lt;strong&gt;Z80&lt;/strong&gt;. J'en connais deux, mais il en existe d'autres. Le &lt;strong&gt;premier&lt;/strong&gt; fait parti de l'environnement complet &lt;a href="https://www.z88dk.org/"&gt;&lt;strong&gt;z88dk&lt;/strong&gt;&lt;/a&gt; et se nomme &lt;code&gt;SCCZ80&lt;/code&gt;. L'&lt;strong&gt;autre&lt;/strong&gt; est &lt;a href="https://sourceforge.net/projects/sdcc/"&gt;&lt;strong&gt;SDCC&lt;/strong&gt;&lt;/a&gt;, pour Small Device C Compiler. Ce dernier peut générer du code pour de nombreux microprocesseurs. Il peut être aussi utilisé par l'environnement spécialisé z80 qu'est z88dk.&lt;/p&gt;
&lt;p&gt;Je commence avec &lt;strong&gt;SCCZ80&lt;/strong&gt; : &lt;code&gt;zcc +vg5k -O3 -m c_setpoint_basic.c&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;+vg5k&lt;/strong&gt; indique que à la suite que ma plateforme cible est un VG5000µ,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-O3&lt;/strong&gt; indique que je veux optimiser le code au niveau maximum,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-m&lt;/strong&gt; indique que je veux générer un fichier avec des informations sur le résultat,&lt;/li&gt;
&lt;li&gt;et enfin le &lt;strong&gt;nom du fichier&lt;/strong&gt; en C.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour que la compilation fonctionne, je dois ajouter une fonction &lt;code&gt;main()&lt;/code&gt;. En effet, le &lt;strong&gt;CRT&lt;/strong&gt; (C Run Time) va chercher cette fonction &lt;code&gt;main()&lt;/code&gt; pour l'appeler au démarrage. Or pour utiliser la fonction &lt;code&gt;-m&lt;/code&gt; du compilateur, je dois construire une application complète.&lt;/p&gt;
&lt;p&gt;Je pourrais tenter de compiler seulement le fichier .c en fichier objet (.o), malheureusement, comme on va le voir juste après, &lt;strong&gt;SCCZ80&lt;/strong&gt; appelle de nombreuses fonctions... Bref, c'est plus simple de faire une application complète.&lt;/p&gt;
&lt;p&gt;Et cela me permet d'aller voir dans le fichier &lt;code&gt;.map&lt;/code&gt; la taille de la fonction &lt;code&gt;setpoint&lt;/code&gt; telle que compilée pour ce compilateur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;251 octets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La fonction écrite à la main fait 196 octets, fonctions de multiplication et division comprises. Ici, c'est 251 octets &lt;strong&gt;sans&lt;/strong&gt; les appels aux &lt;strong&gt;nombreuses fonctions&lt;/strong&gt; donc le compilateur se sert.&lt;/p&gt;
&lt;h4&gt;Le compilateur SDCC&lt;/h4&gt;
&lt;p&gt;Avant d'aller plus loin, un petit essai avec &lt;strong&gt;SDCC&lt;/strong&gt; donne 125 octets, auquel il faut ajouter la fonction de division, 42 octets, pour un total de &lt;strong&gt;167 octets&lt;/strong&gt;. C'est beaucoup mieux. C'est même mieux que le code écrit directement en assembleur, qui ne l'oublions pas utilise une table assez importante pour la division. Le &lt;strong&gt;code manuel&lt;/strong&gt; du &lt;code&gt;setpoint&lt;/code&gt; hors appels de fonction &lt;strong&gt;reste plus petit&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Par contre, SDCC fait grand usage des registres &lt;code&gt;IX&lt;/code&gt; et &lt;code&gt;IY&lt;/code&gt;. Et &lt;code&gt;IX&lt;/code&gt; est strictement &lt;strong&gt;réservé&lt;/strong&gt; par la &lt;strong&gt;ROM&lt;/strong&gt; du VG5000µ, il faut l'utiliser avec des grandes précautions. Le fichier CRT du VG5000µ le préserve en sauvant sa valeur, et part du principe que l'on configure l'assembleur pour échanger l'utilisation de &lt;code&gt;IY&lt;/code&gt; et &lt;code&gt;IX&lt;/code&gt; (pour au final ne pas utiliser &lt;code&gt;IX&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;Pourquoi c'est si gros ?&lt;/h4&gt;
&lt;p&gt;Je reviens en premier lieu sur la compilation en &lt;strong&gt;SCCZ80&lt;/strong&gt;. Ce compilateur part sur une &lt;strong&gt;stratégie&lt;/strong&gt; : la compilation d'un programme entier doit donner un &lt;strong&gt;exécutable petit&lt;/strong&gt;. Pour cela, les fonctions les plus courantes sont &lt;strong&gt;factorisées&lt;/strong&gt; dans des &lt;strong&gt;routines assembleurs&lt;/strong&gt; utilisées par le compilateur.&lt;/p&gt;
&lt;p&gt;C'est le cas par exemple pour les fonctions de &lt;strong&gt;division&lt;/strong&gt; et de &lt;strong&gt;multiplication&lt;/strong&gt;. Mais c'est aussi le cas pour des services comme « aller chercher un entier sur la pile », utile dans le modèle C pour le passage de paramètres aux fonctions.&lt;/p&gt;
&lt;p&gt;En regardant le &lt;strong&gt;code généré&lt;/strong&gt;, on peut voir aussi beaucoup de &lt;strong&gt;manipulations de registres&lt;/strong&gt; pour essayer de faire les calculs sur 8 bits que je demande. Ça à l'air un peu trop complexe. Et si on essayait de partir sur une base de calculs en 16 bits ?&lt;/p&gt;
&lt;p&gt;Pour cela, je change les types &lt;code&gt;uint8_t&lt;/code&gt; du code source ci-dessus en &lt;code&gt;uint16_t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;216 octets&lt;/strong&gt; ! Voici qui est beaucoup mieux.&lt;/p&gt;
&lt;p&gt;Le compilateur &lt;strong&gt;SCCZ80&lt;/strong&gt; a donc l'air de mieux travailler avec des entiers de &lt;strong&gt;16 bits&lt;/strong&gt;. Cela est en partie du à l'utilisation de ces routines annexes, qui sont écrites avec un modèle sur 16 bits en tête. En demandant des calculs sur 8 bits, j'oblige le compilateur à sans cesse passer de 8 à 16 bits et inversement.&lt;/p&gt;
&lt;p&gt;Et &lt;strong&gt;SDCC&lt;/strong&gt; ? ... 183 octets. Là, ce n'est pas bon. De son côté, SDCC était &lt;strong&gt;plus efficace&lt;/strong&gt; à faire ses opérations sur du &lt;strong&gt;8 bits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;SDCC &lt;strong&gt;contrairement à&lt;/strong&gt; SCCZ80, a pour objectif principal la &lt;strong&gt;vitesse d'exécution&lt;/strong&gt;, quitte à avoir du code machine plus gros. Pour cela, certaines stratégies sont employées. Ici, tous &lt;strong&gt;les calculs&lt;/strong&gt; sont faits &lt;strong&gt;sur place&lt;/strong&gt;, avec des manipulations de registres, à l'&lt;strong&gt;exception&lt;/strong&gt; notable de la &lt;strong&gt;division&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Du coup, travailler sur les registres 16 bits est un peu plus compliqué et cela a un impact direct sur la taille du code.&lt;/p&gt;
&lt;h4&gt;Est-ce qu'on peut aider ?&lt;/h4&gt;
&lt;p&gt;Première idée, puisque SDCC passe beaucoup de temps à récupérer les arguments de la fonctions, c'est de repasser ceux-ci sur 8 bits.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec moins d'instruction d'accès à la pile, on fait gagner &lt;strong&gt;10 octets&lt;/strong&gt; à &lt;strong&gt;SDCC&lt;/strong&gt;. Pas négligeable. Côté &lt;strong&gt;SCCZ80&lt;/strong&gt;, c'est un gain de &lt;strong&gt;3 octets&lt;/strong&gt;. C'est toujours ça.&lt;/p&gt;
&lt;p&gt;On peut aussi aider en utilisant une fonction de division par 3 spécialisé, comme en assembleur, sous cette forme :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;div3_table&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;div3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;div3_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La fonction de &lt;strong&gt;division générique&lt;/strong&gt; utilisée pour &lt;strong&gt;SCCZ80&lt;/strong&gt; fait &lt;strong&gt;37 octets&lt;/strong&gt; et pour &lt;strong&gt;SDCC&lt;/strong&gt;, &lt;strong&gt;42 octets&lt;/strong&gt;. La fonction par tableau utilisée ici est plus grosse, mais plus rapide.&lt;/p&gt;
&lt;p&gt;Côté &lt;strong&gt;SCCZ80&lt;/strong&gt;, on descend à &lt;strong&gt;212 octets&lt;/strong&gt;... Soit 1 octet de gain. Pas top. Côté SDCC, ça remonte même à &lt;strong&gt;177 octets&lt;/strong&gt; (ou 176 en jouant sur les tailles des types entiers).&lt;/p&gt;
&lt;h4&gt;Conventions d'appel&lt;/h4&gt;
&lt;p&gt;Lorsque l'on &lt;strong&gt;appelle&lt;/strong&gt; une &lt;strong&gt;fonction&lt;/strong&gt; avec des &lt;strong&gt;paramètres&lt;/strong&gt;, il y a &lt;strong&gt;plusieurs moyens&lt;/strong&gt; de les &lt;strong&gt;transmettre&lt;/strong&gt;. On peut passer par une &lt;strong&gt;convention&lt;/strong&gt; basée sur l'&lt;strong&gt;utilisation de registres&lt;/strong&gt;, ou bien passer &lt;strong&gt;par la pile&lt;/strong&gt; par exemple. Par défaut, les deux compilateurs passent pas la pile. Cependant, on peut indiquer à la fonction que l'on préfère passer par une autre convention lorsqu'il n'y a qu'un paramètre à la fonction.&lt;/p&gt;
&lt;p&gt;Pour cela, on modifie la fonction &lt;code&gt;div3&lt;/code&gt; comme ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;div3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__z88dk_fastcall&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;div3_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Côté &lt;strong&gt;SDCC&lt;/strong&gt;, la fonction &lt;code&gt;div3&lt;/code&gt; fond grâce au &lt;strong&gt;passage&lt;/strong&gt; du &lt;strong&gt;paramètre&lt;/strong&gt; et de la &lt;strong&gt;valeur de retour&lt;/strong&gt; par le registre &lt;code&gt;l&lt;/code&gt;. Plus besoin de mécanisme pour aller chercher la valeur dans la pile, calcul qui était généré de manière assez complexe par SDCC. La fonction passe de &lt;strong&gt;27 octets&lt;/strong&gt; à... &lt;strong&gt;10 octets&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;Le code généré est tout de même étrange :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;_div3:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde de L dans C&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;_div3_table&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de C dans L... mais pourquoi ?&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;l_div3_00101:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce petit tour de passe-passe entre les registres &lt;code&gt;C&lt;/code&gt; et &lt;code&gt;L&lt;/code&gt; est inutile. &lt;code&gt;L&lt;/code&gt; n'est pas utilisé entre temps, et &lt;code&gt;C&lt;/code&gt; n'est pas utilisé ensuite. Voilà de quoi gagner 2 octets supplémentaire en réécrivant la fonction à la main.&lt;/p&gt;
&lt;p&gt;Côté appelant, &lt;code&gt;setpoint&lt;/code&gt; est aussi un peu simplifié et tombe à &lt;strong&gt;174 octets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Utilisons SCCZ80 à présent avec la même convention d'appel. La fonction initiale n'était pas très grosse, avec ses 14 octets, elle passe à 14 octets. Mais là encore les compilateur génère des choses étranges :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;._div3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; HL est poussé sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;_div3_table&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; HL est récupéré de la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; pour y être immédiatement remis&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; pour que la valeur soit ignorée...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ces &lt;code&gt;push&lt;/code&gt; et &lt;code&gt;pop&lt;/code&gt; du registre &lt;code&gt;HL&lt;/code&gt; sont &lt;strong&gt;rigoureusement inutiles&lt;/strong&gt;. Il n'y a pas de valeur à préserver. Et au final, le contenu de la pile est extrait dans un registre dont on ne s'est pas servi &lt;code&gt;BC&lt;/code&gt; mais qui du coup est invalidé. Ce sont donc &lt;strong&gt;4 octets à économiser&lt;/strong&gt; (et pas mal de cycles d'exécutions) en enlevant ces instructions. Cela nous amène à &lt;strong&gt;10 octets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La différence, si on oubli ces instructions inutiles, entre les deux codes générés est le &lt;code&gt;LD H,0&lt;/code&gt; (2 octets) pour s'assurer que la valeur de retour sur 16 bits est valide avec &lt;strong&gt;SCCZ80&lt;/strong&gt;. &lt;strong&gt;SDCC&lt;/strong&gt; ne prend pas cette précaution, à la charge de l'appelant de n'utiliser que la valeur du registre 8 bits &lt;code&gt;L&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Et l'inlining ?&lt;/h4&gt;
&lt;p&gt;Une possibilité de compilation de l'appel d'une fonction est... de ne pas l'appeler, mais plutôt de faire comme si son code était « sur place ». C'est le mot-clé anglais « inline » qui nous permet de spécifier cela.&lt;/p&gt;
&lt;p&gt;Côté positif, si le code de la fonction lui-même est petit par rapport au code nécessaire au passage des paramètres et code de retour, cela peut-être gagnant d'injecter le code sur place. Côté négatif, il est possible que ce code injecté un peu partout fasse augmenter la taille du code final.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;div3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;div3_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec &lt;strong&gt;SCCZ80&lt;/strong&gt;, je ne suis pas allé bien loin. L'utilisation de « inline » fait émettre des erreurs au compilateur. Je ne me suis pas penché plus sur le problème.&lt;/p&gt;
&lt;p&gt;Avec &lt;strong&gt;SDCC&lt;/strong&gt; par contre, non seulement le mot clé est pris en compte, mais le code est réduit de pas mal : &lt;strong&gt;161 octets&lt;/strong&gt;. Et forcément, pas de code généré pour &lt;code&gt;div3&lt;/code&gt;. C'est &lt;strong&gt;plus petit&lt;/strong&gt; que ce que j'avais écrit à la main (ce qui peut aussi s'expliquer par mes compétences limitées en assembleur Z80).&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Le &lt;strong&gt;C&lt;/strong&gt; est &lt;strong&gt;utilisable&lt;/strong&gt; pour générer du code &lt;strong&gt;Z80&lt;/strong&gt;. Les compilateurs utilisent des versions réduites du C actuel, mais néanmoins &lt;strong&gt;très corrects&lt;/strong&gt;. Le bon côté est que le &lt;strong&gt;temps d'écriture du code&lt;/strong&gt;, pour certaines opérations, est &lt;strong&gt;réduit&lt;/strong&gt;, en tout cas pour moi.&lt;/p&gt;
&lt;p&gt;Par contre, il est nécessaire de &lt;strong&gt;garder le code généré à l’œil&lt;/strong&gt;. Celui-ci peut rapidement être gourmand ou générer des choses inutiles. Il faut alors se poser la question d'adapter se code et de le &lt;strong&gt;passer en assembleur&lt;/strong&gt;, en perdant au passage la portabilité.&lt;/p&gt;
&lt;p&gt;Cette &lt;strong&gt;portabilité&lt;/strong&gt; reste limitée, puisqu'il est nécessaire d'aider fortement le compilateur.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="C"></category><category term="Z80"></category></entry><entry><title>VG5000µ, SetPoint en ASM, afficher le point</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-afficher-le-point.html" rel="alternate"></link><published>2018-05-29T00:00:00+02:00</published><updated>2018-05-29T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-05-29:/vg5000m-setpoint-en-asm-afficher-le-point.html</id><summary type="html">&lt;p&gt;À présent que l'on sait diviser par 3, reprenons l'affichage d'un point à l'écran. Pour rappel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;En entrée&lt;/strong&gt;, nous avons : des coordonnées X et Y, comprises entre &lt;code&gt;0&lt;/code&gt; et &lt;code&gt;79&lt;/code&gt; pour X et &lt;code&gt;0&lt;/code&gt; et &lt;code&gt;74&lt;/code&gt; pour Y.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;En effet de bord&lt;/strong&gt;, c'est-à-dire en modification de l'état de la machine, nous voulons : le point correspondant à l'écran qui prend la couleur d'encre définie.&lt;/p&gt;
&lt;p&gt;Pour cette version, la procédure ne prendra pas d'information de couleur, je me contenterai d'utiliser la couleur d'encre &lt;code&gt;0&lt;/code&gt; (noir) sur fond &lt;code&gt;6&lt;/code&gt; (bleu), qui est la combinaison à l'initialisation de la machine.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;étapes&lt;/strong&gt;, d'après les articles précédents, sont donc :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;À partir de X et Y, trouver les coordonnées du caractère à modifier à l'écran&lt;/li&gt;
&lt;li&gt;À partir de X et Y, trouver les coordonnées à l’intérieur du caractère semi-graphique&lt;/li&gt;
&lt;li&gt;À partir de coordonnées du caractère, calculer l'adresse mémoire écran correspondante&lt;/li&gt;
&lt;li&gt;Récupérer les valeurs pour la …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;À présent que l'on sait diviser par 3, reprenons l'affichage d'un point à l'écran. Pour rappel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;En entrée&lt;/strong&gt;, nous avons : des coordonnées X et Y, comprises entre &lt;code&gt;0&lt;/code&gt; et &lt;code&gt;79&lt;/code&gt; pour X et &lt;code&gt;0&lt;/code&gt; et &lt;code&gt;74&lt;/code&gt; pour Y.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;En effet de bord&lt;/strong&gt;, c'est-à-dire en modification de l'état de la machine, nous voulons : le point correspondant à l'écran qui prend la couleur d'encre définie.&lt;/p&gt;
&lt;p&gt;Pour cette version, la procédure ne prendra pas d'information de couleur, je me contenterai d'utiliser la couleur d'encre &lt;code&gt;0&lt;/code&gt; (noir) sur fond &lt;code&gt;6&lt;/code&gt; (bleu), qui est la combinaison à l'initialisation de la machine.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;étapes&lt;/strong&gt;, d'après les articles précédents, sont donc :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;À partir de X et Y, trouver les coordonnées du caractère à modifier à l'écran&lt;/li&gt;
&lt;li&gt;À partir de X et Y, trouver les coordonnées à l’intérieur du caractère semi-graphique&lt;/li&gt;
&lt;li&gt;À partir de coordonnées du caractère, calculer l'adresse mémoire écran correspondante&lt;/li&gt;
&lt;li&gt;Récupérer les valeurs pour la paire d'adresse mémoire&lt;/li&gt;
&lt;li&gt;Si le caractère présent n'était pas un caractère semi-graphique standard, considérer qu'il était complètement éteint (valeur &lt;code&gt;0&lt;/code&gt; pour le caractère)&lt;/li&gt;
&lt;li&gt;Modifier la valeur du caractère récupéré en fonction des coordonnées à l'intérieur du caractère semi-graphique&lt;/li&gt;
&lt;li&gt;Modifier la mémoire écran avec les nouvelles valeurs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comme le code est plutôt long, je vais changer de méthode. Le code entier va suivre, commenté au maximum en ligne.&lt;/p&gt;
&lt;h4&gt;Le Code&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La procédure se nomme &amp;#39;setpoint&amp;#39; et sera appelée avec `call setpoint`&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Les coordonnées (x,y) du point à allumer sont mises dans, respectivement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; L et H. Autrement dit, HL contient yx.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; C&amp;#39;est le format utilisé par la ROM du VG5000µ pour ses coordonnées de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; curseur. Autant le garder.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;setpoint:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La procédure sauve tous les registres exceptés IX et IY.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; On pourrait aussi considérer que c&amp;#39;est à l&amp;#39;appelant de veiller à&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; garder ses registres intègres&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Ce n&amp;#39;est pas le plus efficace, mais pour le moment, c&amp;#39;est le plus sûr.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Pour le moment :&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - HL contient les coordonnées (y,x)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - Les autres registres sont libres&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On travaille sur y&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div3&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Que l&amp;#39;on divise par 3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Et donc D contient y/3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On travaille sur x&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La ligne suivante ne fonctionne que si C (le Drapeau de retenue)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; est bien à zéro (ce qui est assuré avec le div_3 utilisé)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Sinon, il faudrait utiliser `srl a`, qui est codé sur deux octets plutôt que 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;rra&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; On divise A par 2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Et donc E contient x/2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; À ce point :&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - DE contient les coordonnées (y/3,x/2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - HL contient toujours les coordonnées (y,x)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - Les autres registres sont libres&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; B sera utilisé temporairement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On travaille à nouveau sur x&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On ne garde de A que le bit de poids faible.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Et donc B contient x modulo 2 (le reste de la division entière par 2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On travaille à nouveau sur y&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; On soustrait D, qui contient y/3 (partie entière)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Une seconde fois&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Puis une troisième fois.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Et donc A contient y modulo 3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; On remarque ici qu&amp;#39;une fonction qui retournerait en même temps le quotient&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ET le reste de la division entière pourrait faire gagner un peu de temps...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; On travaille dessus immédiatement sur (y modulo 3)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Dorénavant, j&amp;#39;utiliserai le signe % pour modulo.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A contient à présent (y % 3) * 2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A contient à présent (y % 3) * 2 + (x % 2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Petit point :&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - A contient la puissance de 2 nécessaire à trouver le bon caractère&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - DE contient toujours les coordonnées (y/3,x/2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - BC ne contient plus rien d&amp;#39;intéressant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - HL ne contient plus rien d&amp;#39;intéressant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;   À vrai dire, HL n&amp;#39;est plus utile depuis le ld a,h précédent&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Équivalent à cp $0 mais plus conci et rapide&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le résultat de cette comparaison de A avec 0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; va être conservé par les drapeaux jusqu&amp;#39;au&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; JR suivant, car les instructions LD n&amp;#39;altèrent&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; par les drapeaux.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Il faut à présent calculer la valeur 2 à la puissance A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On charge B avec la valeur A. B va servir de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; compteur de boucle.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On initialise le résultat à 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;no_power&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Si A était égal à zéro, on n&amp;#39;a rien besoin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; de calculer, donc on passe à la suite.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La boucle suivante décale vers la gauche le contenu de A de 1 position&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Autrement dit, A est multiplié par 2 à chaque tour de boucle.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; À la fin de la boucle, A contient donc 2 puissance B.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;power_of_2:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;rla&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;power_of_2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;no_power:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; A contient l&amp;#39;index du caractère semi-graphique à aller chercher.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; On sauve cette valeur pour plus tard dans la pile.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Petit point :&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - HL est libre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - BC est libre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - DE contient les coordonnées (y/3, x/2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - A est sauvé sur la pile, on pourra donc l&amp;#39;utiliser pour des calculs&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; L&amp;#39;objectif est à présent d&amp;#39;aller calculer l&amp;#39;adresse mémoire du caractère&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; à changer dans la plage mémoire dédiée en RAM.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La fonction de multiplication que j&amp;#39;utilise ici, et qui n&amp;#39;aura pas&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; son article dédié, utilise HL et DE. DE est transféré dans BC.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Et donc à présent DE est libre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Et BC contient (y/3, x/2)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Le premier calcul à faire est (y/3)*80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; H contient 80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; E contient y / 3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;mult&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Appel de la multiplication&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; À présent, HL contient (y/3)*80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Le second calcul à faire est d&amp;#39;arrondir X à l&amp;#39;entier pair&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; inférieur le plus proche. Pour cela, (x/2)*2, en utilisant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; une division entière donne le ŕésultat.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; A contient x/2 (division entière)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A contient (x/2)*2 (division entière)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Petit point :&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - HL contient le déplacement mémoire sur le début de la ligne&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - A contient le déplacement en colonnes sur la ligne&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - BC est libre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; - DE est libre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Il faut donc additionner HL et A pour avoir l&amp;#39;index mémoire.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Le Z80 ne peut pas faire ça directement. Il faut donc charger&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; A dans un registre 16 bits. BC par exemple.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; HL contient à présent (x/2)*2 + (y/3)*80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; On se ressert de BC pour indiquer la base de l&amp;#39;adresse mémoire vidéo&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; auquel on ajoute l&amp;#39;index, pour obtenir l&amp;#39;adresse mémoire dans HL.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Il est temps d&amp;#39;aller chercher les informations déjà présentes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; en mémoire. Pour cela, on a besoin des deux adresses HL et HL+1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; (voir les articles sur l&amp;#39;agencement de la mémoire vidéo)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; BC contient HL + 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; A contient donc la valeur d&amp;#39;attribut du caractère&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;bit&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Ce qui nous intéresse est sont bit numéro 7&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;set_base_char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; S&amp;#39;il est à 0, ce n&amp;#39;est pas un caractère semi-graphique&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Sinon, on a besoin de connaître la valeur actuelle de ce&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; caractère&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; On récupère la valeur du caractère semi-graphique&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; actuellement à l&amp;#39;écran dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Si le caractère fait partie de la place 64 à 127 (les caractères pleins)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; alors on continue plus loin.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;bit&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;char_ok&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;set_base_char:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; Dans le cas où le caractère à l&amp;#39;écran n&amp;#39;était pas&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; semi-grapique plein, on part sur une base du&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; caractère 64, qui est le caractère semi-graphique&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; &amp;#39;tout éteint&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;char_ok:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Recupération dans D de l&amp;#39;index du caractère calculé.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Cette valeur vient du &amp;#39;push af&amp;#39; effectué plus haut.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Une opération bit à bit &amp;#39;OU&amp;#39; entre l&amp;#39;ancienne valeur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; et le nouvel index donne le nouveau caractère.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Ce caractère est placé à l&amp;#39;écran&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Et dans cette implémentation, on fixe les attributs&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; selon les valeurs de couleurs à l&amp;#39;allumage du VG5000µ&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Une amélioration sera d&amp;#39;aller chercher dans les variables&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; systèmes quels sont les couleurs courantes.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; La routine se termine, on restitue la valeur de tous les registres&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; utilisés pour revenir à l&amp;#39;appelant.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;


&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie: valeur divisée par 3, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_table&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_table:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; 18&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;mult:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;; Entrée, registre H et registre E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Sortie, le registre HL comtient le résultat&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; de l&amp;#39;opération H * E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Utilise HL, B, DE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;mult_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;mult_skip&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;mult_skip:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;mult_loop&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Comment est-ce que ça s'utilise ?&lt;/h4&gt;
&lt;p&gt;Cette routine s'utilise donc en mettant dans &lt;code&gt;HL&lt;/code&gt; les coordonnées (y, x) du point à afficher. Elle pourrait être améliorée en déterminant si on veut afficher ou éteindre le point, spécifier les couleurs ou les récupérer des variables systèmes. Il y a probablement quelque optimisations qui trainent.&lt;/p&gt;
&lt;p&gt;Toujours est-il que par rapport à la routine est basique, l'exécution sera beaucoup plus rapide. Il serait possible d'être encore plus réactif en s'adressant directement au processeur vidéo. Mais je préférais utiliser le buffer vidéo en RAM pour plus de simplicité. Une implémetnation utilisant le processeur vidéo peut se trouver dans la bibliothèque d'affichage de &lt;a href="https://www.z88dk.org/"&gt;Z88DK&lt;/a&gt; pour le VG5000µ. Z88DK est tout un système, basé sur un compilateur C, pour programmer les machines Z80.&lt;/p&gt;
&lt;p&gt;Pour revenir à l'utilisation de cette routine, voici un exemple qui affiche plusieurs lignes horizontales à l'écran.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde des registres utilisés.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; La coordonnée y est 10 ($A en hexa)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; On prépare une boucle de 25 itérations&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;loop_1:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde temporaire de la boucle externe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; afin de préparer une boucle interne&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; La coordonnée x est 16 ($10 en hexa)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; On prépare une boucle de 40 itérations&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;loop_2:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;setpoint&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; On affiche un point&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; On incrémente la coordonnée x de 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;loop_2&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Et on boucle&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Ce qui affiche une ligne de 40 pixels de large&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; à la coordonnée y courante.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de l&amp;#39;index de boucle externe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; On incrémente la coordonnée y deux fois&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; on &amp;quot;saute&amp;quot; donc une ligne.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;loop_1&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Et on recommence ceci 25 fois.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; On affiche donc 25 lignes les unes sous les autres&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; séparées à chaque fois par une hauteur d&amp;#39;un pixel&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Restauration des registres utilisés et retour à l&amp;#39;appelant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Résultat&lt;/h4&gt;
&lt;p&gt;&lt;img alt="Affichage des résultats de tests dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201805/VG5000-LignesHorizontalesASM.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>VG5000µ, SetPoint en ASM, diviser par 3 sans diviser</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-par-3-sans-diviser.html" rel="alternate"></link><published>2018-04-15T00:00:00+02:00</published><updated>2018-04-15T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-04-15:/vg5000m-setpoint-en-asm-diviser-par-3-sans-diviser.html</id><summary type="html">&lt;p&gt;Les &lt;strong&gt;trois&lt;/strong&gt; derniers &lt;strong&gt;articles&lt;/strong&gt; sur la &lt;strong&gt;division&lt;/strong&gt; on permit de s'attarder sur trois manière de diviser un nombre entier par 3.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser.html"&gt;la première méthode&lt;/a&gt; effectuait une &lt;strong&gt;série de soustractions&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-plus-vite.html"&gt;la seconde méthode&lt;/a&gt; utilisait la &lt;em&gt;méthode scolaire&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-encore-plus-vite.html"&gt;la troisième méthode&lt;/a&gt; se servait de &lt;strong&gt;divisions par 4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La méthode de cet article, qui sera le dernier avant de revenir à l'affichage d'un point, va diviser grâce à, globalement, &lt;strong&gt;une seule addition&lt;/strong&gt;. Oui ! Une seule addition.&lt;/p&gt;
&lt;h4&gt;L'idée&lt;/h4&gt;
&lt;p&gt;Au &lt;a href="({filename}/Machines/20180225-VG5000-SetPointASM-2.md)"&gt;tout début&lt;/a&gt; de la série d'articles sur la division, j'ai mis en place un &lt;strong&gt;système de tests&lt;/strong&gt; pour m'assurer que mes bouts d'assembleurs faisaient ce qu'il étaient censés faire. Et pour cela, je comparais une &lt;strong&gt;série de divisions&lt;/strong&gt; avec un &lt;strong&gt;tableau de résultats&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mais alors, pourquoi ne pas &lt;strong&gt;utiliser un tableau&lt;/strong&gt; de résultats directement ? On &lt;strong&gt;stock&lt;/strong&gt; quelque part le résultat de toutes les divisions par 3 des nombres entiers de 0 à 255, et on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Les &lt;strong&gt;trois&lt;/strong&gt; derniers &lt;strong&gt;articles&lt;/strong&gt; sur la &lt;strong&gt;division&lt;/strong&gt; on permit de s'attarder sur trois manière de diviser un nombre entier par 3.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser.html"&gt;la première méthode&lt;/a&gt; effectuait une &lt;strong&gt;série de soustractions&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-plus-vite.html"&gt;la seconde méthode&lt;/a&gt; utilisait la &lt;em&gt;méthode scolaire&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-encore-plus-vite.html"&gt;la troisième méthode&lt;/a&gt; se servait de &lt;strong&gt;divisions par 4&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La méthode de cet article, qui sera le dernier avant de revenir à l'affichage d'un point, va diviser grâce à, globalement, &lt;strong&gt;une seule addition&lt;/strong&gt;. Oui ! Une seule addition.&lt;/p&gt;
&lt;h4&gt;L'idée&lt;/h4&gt;
&lt;p&gt;Au &lt;a href="({filename}/Machines/20180225-VG5000-SetPointASM-2.md)"&gt;tout début&lt;/a&gt; de la série d'articles sur la division, j'ai mis en place un &lt;strong&gt;système de tests&lt;/strong&gt; pour m'assurer que mes bouts d'assembleurs faisaient ce qu'il étaient censés faire. Et pour cela, je comparais une &lt;strong&gt;série de divisions&lt;/strong&gt; avec un &lt;strong&gt;tableau de résultats&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mais alors, pourquoi ne pas &lt;strong&gt;utiliser un tableau&lt;/strong&gt; de résultats directement ? On &lt;strong&gt;stock&lt;/strong&gt; quelque part le résultat de toutes les divisions par 3 des nombres entiers de 0 à 255, et on va &lt;strong&gt;piocher&lt;/strong&gt; dedans. &lt;strong&gt;Facile&lt;/strong&gt; à implémenter, ultra &lt;strong&gt;rapide&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La contrepartie, évidemment, c'est que cela va prendre &lt;strong&gt;un peu de place&lt;/strong&gt;. Mais voyons ce que cela donne.&lt;/p&gt;
&lt;h4&gt;Le code&lt;/h4&gt;
&lt;p&gt;Nul besoin d'une longue &lt;strong&gt;explication&lt;/strong&gt; pour cette méthode. L'entier à diviser (le dividende) est dans le registre &lt;code&gt;A&lt;/code&gt;, on &lt;strong&gt;l'ajoute&lt;/strong&gt; à l'&lt;strong&gt;adresse du tableau&lt;/strong&gt; des résultats pré-calculés, on récupère la valeur dans &lt;code&gt;A&lt;/code&gt; et voilà !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3_5:&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie: valeur divisée par 3, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Utilisation des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_table&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Chargement dans HL de l&amp;#39;adresse de la table des résultats&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Mise à 0 de B&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Placement de la valeur de A dans C&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; On a donc à présent le registre BC qui contient le dividende&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;; Addition du dividende et de l&amp;#39;adresse du tableau&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Récupération du résultat&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Échange des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Retour à l&amp;#39;appelant.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_table:&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; La table des résultats&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Il n'y a &lt;strong&gt;pas&lt;/strong&gt; vraiment de &lt;strong&gt;nouvelles instructions&lt;/strong&gt; utilisées ici, mais de &lt;strong&gt;nouvelles formes&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comme on ne peut pas additionner directement les registres &lt;code&gt;HL&lt;/code&gt; et &lt;code&gt;A&lt;/code&gt;, on doit passer la valeur de &lt;code&gt;A&lt;/code&gt; dans un registre 16 bits. &lt;code&gt;BC&lt;/code&gt; est souvent utilisé, mais ça aurait pu être &lt;code&gt;DE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Comme on ne peut pas charger le contenu de &lt;code&gt;A&lt;/code&gt; directement dans &lt;code&gt;BC&lt;/code&gt;, on le fait en &lt;strong&gt;deux étapes&lt;/strong&gt;. Le registre 16 bits &lt;code&gt;BC&lt;/code&gt; est constitué des deux registres 8 bits &lt;code&gt;B&lt;/code&gt; et &lt;code&gt;C&lt;/code&gt;. On place donc &lt;code&gt;0&lt;/code&gt; dans &lt;code&gt;B&lt;/code&gt; et &lt;code&gt;C&lt;/code&gt; prend la valeur de &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LD A,(HL)&lt;/code&gt; récupère la &lt;strong&gt;valeur pointée&lt;/strong&gt; par le registre &lt;code&gt;HL&lt;/code&gt;, plutôt que la valeur de HL. C'est-à-dire que l'octet à l'adresse mémoire pointée par &lt;code&gt;HL&lt;/code&gt; est &lt;strong&gt;récupérée&lt;/strong&gt;, puis chargé dans &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;C'est mieux du coup ?&lt;/h4&gt;
&lt;p&gt;D'un point de vu code de la &lt;strong&gt;fonction&lt;/strong&gt; elle-même, c'est &lt;strong&gt;nettement mieux&lt;/strong&gt;, 11 octets seulement. Par contre suivi d'un tableau de 255 octets. C'est donc à la fois le code le plus concis jusqu'à maintenant, mais aussi la fonction la plus grosse dans sa globalité.&lt;/p&gt;
&lt;p&gt;Il est possible cependant de la &lt;strong&gt;réduire&lt;/strong&gt; dans le cas présent. En effet, comme on ne divise que des &lt;strong&gt;numéros de lignes&lt;/strong&gt;, on pourrait s'arrêter à 75 résultats. Cela donne &lt;strong&gt;86 octets&lt;/strong&gt;, c'est toujours plus imposant que les autres versions, mais un peu mieux.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention aussi&lt;/strong&gt;, l'accès au tableau n'est pas protégé. S´il est plus petit que 255, rien n'empêche l'appelant de passer une valeur qui va déborder. Cela donnera des résultats faux.&lt;/p&gt;
&lt;p&gt;D'un point de vu &lt;strong&gt;rapidité&lt;/strong&gt; c'est &lt;strong&gt;constant&lt;/strong&gt; et &lt;strong&gt;rapide&lt;/strong&gt; : 15 cycles. Comme c'est une fonction très courte, il est possible aussi, au besoin, de &lt;strong&gt;l'inliner&lt;/strong&gt;, c'est-à-dire de faire l'opération à l'endroit où elle est nécessaire plutôt que d'appeler une fonction. Cela &lt;strong&gt;économise&lt;/strong&gt; le temps de mise en place et de retour de la fonction (les &lt;code&gt;EXX&lt;/code&gt; et &lt;code&gt;RET&lt;/code&gt;). On tombe alors à 10 cycles, que l'on peut potentiellement améliorer en utilisant les valeurs de registres au moment de l'appel.&lt;/p&gt;
&lt;p&gt;Difficile de faire plus rapide comme méthode (à quelques astuces potentielles prêt).&lt;/p&gt;
&lt;h4&gt;Que choisir ?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;C'est la question&lt;/strong&gt;. Nous voici avec &lt;strong&gt;quatre méthodes&lt;/strong&gt; pour diviser par trois. &lt;strong&gt;Deux&lt;/strong&gt; sont des &lt;strong&gt;méthodes générales&lt;/strong&gt; de division, &lt;strong&gt;deux&lt;/strong&gt; sont &lt;strong&gt;spécialisées&lt;/strong&gt; dans la division par 3. La première question à se poser est donc de savoir de quoi on a besoin.&lt;/p&gt;
&lt;p&gt;Ensuite, nous avons des fonctions qui ont des &lt;strong&gt;compromis&lt;/strong&gt; en terme de &lt;strong&gt;taille&lt;/strong&gt; et de &lt;strong&gt;rapidité&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;C'est ici qu´utiliser une &lt;strong&gt;fonction&lt;/strong&gt; s'avère &lt;strong&gt;utile&lt;/strong&gt;. Pour le moment, le choix n'a &lt;strong&gt;pas d'importance&lt;/strong&gt;. Les quatre fonctions demandent un dividende dans &lt;code&gt;A&lt;/code&gt; et retournent le résultat dans &lt;code&gt;A&lt;/code&gt;. Il est donc possible de &lt;strong&gt;remplacer&lt;/strong&gt; l'une par l'autre et de continuer le développement de l'affichage du point.&lt;/p&gt;
&lt;p&gt;Il sera temps, ensuite, de &lt;strong&gt;choisir&lt;/strong&gt; quelle méthode sera la plus &lt;strong&gt;adéquate&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler&lt;/strong&gt; : probablement aucune de celles-ci en l'état, car nous allons avoir besoin du reste de la division par 3...&lt;/p&gt;
&lt;p&gt;À la prochaine !&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>VG5000µ, SetPoint en ASM, diviser encore plus vite</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-encore-plus-vite.html" rel="alternate"></link><published>2018-04-08T00:00:00+02:00</published><updated>2018-04-08T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-04-08:/vg5000m-setpoint-en-asm-diviser-encore-plus-vite.html</id><summary type="html">&lt;p&gt;Dans le &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-plus-vite.html"&gt;dernier article&lt;/a&gt;, j'avais cherché une version &lt;strong&gt;plus rapide&lt;/strong&gt; pour effectuer une division par 3, toujours dans l'optique d'&lt;strong&gt;afficher un point à l'écran&lt;/strong&gt; en transcrivant la &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-basic-limplementation.html"&gt;routine écrite en BASIC&lt;/a&gt; vers de l'assembleur Z80.&lt;/p&gt;
&lt;p&gt;Le résultat était &lt;strong&gt;mitigé&lt;/strong&gt; : une routine en moyenne plus rapide et &lt;strong&gt;plus stable&lt;/strong&gt;, mais sur le domaine de définition considéré (le nombre de lignes graphiques du VG5000µ), pas entièrement gagnante.&lt;/p&gt;
&lt;p&gt;Dans cet article, je vais donc étudier une &lt;strong&gt;autre manière&lt;/strong&gt; de faire, un peu différente. Alors que les deux premières implémentations permettait de diviser par n'importe quel nombre de 1 à 255, cette nouvelle version est spécialisée dans la division par 3.&lt;/p&gt;
&lt;p&gt;Est-ce que cette spécialisation permettra de gagner en performance et/ou en taille ?&lt;/p&gt;
&lt;h4&gt;L'idée&lt;/h4&gt;
&lt;p&gt;Le &lt;strong&gt;Z80&lt;/strong&gt; n'a pas d'instruction pour &lt;strong&gt;diviser&lt;/strong&gt; de manière générale, cela a déjà été mentionné dans les articles précédents. Par contre, il est tout à fait possible de …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans le &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-plus-vite.html"&gt;dernier article&lt;/a&gt;, j'avais cherché une version &lt;strong&gt;plus rapide&lt;/strong&gt; pour effectuer une division par 3, toujours dans l'optique d'&lt;strong&gt;afficher un point à l'écran&lt;/strong&gt; en transcrivant la &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-basic-limplementation.html"&gt;routine écrite en BASIC&lt;/a&gt; vers de l'assembleur Z80.&lt;/p&gt;
&lt;p&gt;Le résultat était &lt;strong&gt;mitigé&lt;/strong&gt; : une routine en moyenne plus rapide et &lt;strong&gt;plus stable&lt;/strong&gt;, mais sur le domaine de définition considéré (le nombre de lignes graphiques du VG5000µ), pas entièrement gagnante.&lt;/p&gt;
&lt;p&gt;Dans cet article, je vais donc étudier une &lt;strong&gt;autre manière&lt;/strong&gt; de faire, un peu différente. Alors que les deux premières implémentations permettait de diviser par n'importe quel nombre de 1 à 255, cette nouvelle version est spécialisée dans la division par 3.&lt;/p&gt;
&lt;p&gt;Est-ce que cette spécialisation permettra de gagner en performance et/ou en taille ?&lt;/p&gt;
&lt;h4&gt;L'idée&lt;/h4&gt;
&lt;p&gt;Le &lt;strong&gt;Z80&lt;/strong&gt; n'a pas d'instruction pour &lt;strong&gt;diviser&lt;/strong&gt; de manière générale, cela a déjà été mentionné dans les articles précédents. Par contre, il est tout à fait possible de diviser par des &lt;strong&gt;multiples de 2&lt;/strong&gt;. Il suffit de &lt;strong&gt;décaler&lt;/strong&gt; un nombre d'un bit vers la droite pour diviser un nombre entier codé en binaire par 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exemple :&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$00010010_{2}$ (18 en base 10) &lt;strong&gt;décalé vers la droite une fois&lt;/strong&gt; donne $00001001_{2}$ (9 en base 10).&lt;/p&gt;
&lt;p&gt;Il faut donc trouver une manière d'exprimer une &lt;strong&gt;division par trois&lt;/strong&gt; à partir de divisions par des multiples de 2 aidées d’additions ou soustractions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le calcul est le suivant&lt;/strong&gt; : on remarque tout d'abord que n'importe quel nombre entier &lt;code&gt;n&lt;/code&gt; peut s'écrire sous la forme $n = 4\times a + b$, avec $b$ inférieur à 4. Autrement dit, sous forme d'une division par 4 plus le reste de la division entière. Trouver $a$ et $b$ est donc simple. $a$ est le résultat de la division entière (&lt;strong&gt;quotient&lt;/strong&gt;) de $n$ par $4$. $b$ le &lt;strong&gt;reste&lt;/strong&gt; de la division entière de $n$ par $4$.&lt;/p&gt;
&lt;p&gt;Sous cette forme, par &lt;strong&gt;exemple&lt;/strong&gt;, $15$ s'écrit $4\times3 + 3$.&lt;/p&gt;
&lt;p&gt;Puisque l'on veut diviser &lt;code&gt;n&lt;/code&gt; par 3, écrivons le résultat à partir de cette forme $\frac{n}{3} = \frac{4\times a + b}{3}$&lt;/p&gt;
&lt;p&gt;On n'est pas très avancé, il faudrait trouver dans l'expression un terme ou une forme que l'on connaît déjà qui nous permettrait de &lt;strong&gt;converger&lt;/strong&gt; vers le résultat.&lt;/p&gt;
&lt;p&gt;Sortons $a$ de la fraction : $\frac{n}{3} = \frac{3\times a}{3} + \frac{a + b}{3} = a + \frac{a + b}{3}$.&lt;/p&gt;
&lt;p&gt;Ça c'est intéressant. Le &lt;strong&gt;résultat&lt;/strong&gt; que l'on cherche est égal à $a$, donc le résultat de la division par $4$ additionné à... un &lt;strong&gt;quelque chose&lt;/strong&gt;. Et ce quelque chose est un nombre que l'on voudrait diviser par 3 !&lt;/p&gt;
&lt;p&gt;Appelons ce nombre $n_{1}$, cela donne : $\frac{n}{3} = a + \frac{n_{1}}{3}$.&lt;/p&gt;
&lt;p&gt;Ce terme $\frac{n_{1}}{3}$ peut &lt;strong&gt;lui-même&lt;/strong&gt; être écrit sous la forme : $\frac{n_{1}}{3} = \frac{4\times a_{1} + b_{1}}{3} = a_{1} + \frac{a_{1} + b_{1}}{3}$, c'est-à-dire sous la forme d'une division par 4 de $n_{1}$ et d'un quelque chose d'autre.&lt;/p&gt;
&lt;p&gt;Et &lt;strong&gt;ainsi de suite&lt;/strong&gt;... Jusqu'à ce que $n_{i}$ soit inférieur ou égal à 3. Dans ce cas, il y a deux cas : soit $n_{i} = 3$ et diviser ce nombre par $3$ donne $1$. Soit $n_{i} &amp;lt; 3$ et ce nombre divisé par $3$ donne $0$.&lt;/p&gt;
&lt;h4&gt;Exemple&lt;/h4&gt;
&lt;p&gt;Revoyons l'exemple avec 15 (pour plus de cohérence, j'ajoute l'indice 0 aux premiers termes) :&lt;/p&gt;
&lt;p&gt;$\frac{15}{3} = \frac{4\times a_{0} + b_{0}}{3}$. On trouve les termes de la division par 4 : $a_{0} = 3$, $b_{0} = 3$&lt;/p&gt;
&lt;p&gt;Donc $\frac{15}{3} = 3 + \frac{3 + 3}{3} = 3 + n_{1}$.&lt;/p&gt;
&lt;p&gt;Il s'agit donc à présent de trouver $\frac{n_{1}}{3} = \frac{3 + 3}{3} = \frac{6}{3} = \frac{4 \times a_{1} + b_{1}}{3}$.&lt;/p&gt;
&lt;p&gt;Comme $6 = 4 \times 1 + 2$, on a $a_{1} = 1$ et $b_{1} = 2$.&lt;/p&gt;
&lt;p&gt;Donc $\frac{n_{1}}{3} = 1 + \frac{1 + 2}{3} = 1 + \frac{3}{3}$. On est dans le cas où le nombre restant est égal à $3$, on sait calculer facilement sa division par $3$, c'est $1$.&lt;/p&gt;
&lt;p&gt;Si on remonte tout ça dans l'expression initiale on a donc :&lt;/p&gt;
&lt;p&gt;$\frac{15}{3} = 3 + (1 + (1)) = 5$&lt;/p&gt;
&lt;h4&gt;L'implémentation&lt;/h4&gt;
&lt;p&gt;Pour cette implémentation, mis à part le dividende, nous avons besoin :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d'un &lt;strong&gt;résultat intermédiaire&lt;/strong&gt; dans lequel on va additionner les différents termes $a_{i}$ au fur et à mesure des itérations&lt;ul&gt;
&lt;li&gt;dans l'exemple précédent, on y mettra la première fois $3$, puis on y additionnera $1$&lt;/li&gt;
&lt;li&gt;j'utiliserai pour ça le registre &lt;code&gt;E&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;d'un &lt;strong&gt;dividende intermédiaire&lt;/strong&gt; à diviser par 3 (les termes $n_{i}$)&lt;ul&gt;
&lt;li&gt;ce nombre est le dividende donné au début&lt;/li&gt;
&lt;li&gt;puis il est remplacé par la somme du quotient et du reste de la division par 4 du dividende actuel&lt;/li&gt;
&lt;li&gt;j'utiliserai pour ça le registre &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J'aurai aussi besoin d'autres registres pour la division intermédiaire par 4.&lt;/p&gt;
&lt;p&gt;Les opérations seront :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tant que&lt;/strong&gt; le dividende actuel (&lt;code&gt;A&lt;/code&gt;) est supérieur à &lt;code&gt;3&lt;/code&gt; :&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;sauve&lt;/strong&gt; le dividende dans &lt;code&gt;B&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;divise&lt;/strong&gt; &lt;code&gt;A&lt;/code&gt; par 4 (stocké temporairement dans &lt;code&gt;D&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;ajoute&lt;/strong&gt; &lt;code&gt;A&lt;/code&gt; au résultat intermédiaire &lt;code&gt;E&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;récupère&lt;/strong&gt; le dividende depuis &lt;code&gt;B&lt;/code&gt; vers &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On prend le &lt;strong&gt;reste de la division&lt;/strong&gt; de &lt;code&gt;A&lt;/code&gt; par 4, qui reste dans &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;ajoute&lt;/strong&gt; &lt;code&gt;D&lt;/code&gt; à &lt;code&gt;A&lt;/code&gt;, ce qui donne le nouveau dividende &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;A&lt;/code&gt; est &lt;strong&gt;égal à 3&lt;/strong&gt;, on ajoute 1 au résultat &lt;code&gt;E&lt;/code&gt;. Sinon rien.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette valse des registres est nécessaire car quelques opérations opérations utilisées ne sont possible, sur &lt;strong&gt;Z80&lt;/strong&gt;, que sur l'accumulateur, et pas sur les autres registres.&lt;/p&gt;
&lt;h4&gt;Le code&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3_4:&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie: valeur divisée par 3, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Utilisation des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Initialisation du diviseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Il est fixe dans cette implémentation&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; mais est nécessaire pour la comparaison&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Initialisation du résultat&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_4_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Comparaison de `C` et `A`&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; le registre `A` est implicite, le Z80&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; ne peut comparer qu&amp;#39;avec le registre A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_4_exit&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Branchement si A est inférieur à C (donc A &amp;lt; 3)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_4_end&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Branchement si A est égal à C (donc A = 3)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_4_cont:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; A est sauvé dans B&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;srl&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A est décalé d&amp;#39;un bit vers la droite&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;srl&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A est décalé d&amp;#39;un bit vers la droite&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Ces deux décalages forment une division par 4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le résultat de la division entière est&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; stockée dans D&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; A prend la valeur du résultat intermédiaire A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; C&amp;#39;est nécessaire pour faire l&amp;#39;addition suivante.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le Z80 ne sait additionner qu&amp;#39;avec l&amp;#39;accumulateur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; quand on traite des valeurs sur 8 bits.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On ajoute le résultat de la division et&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; le résultat intermédiaire.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Ce résultat intermédiaire et remis dans E&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le dividende actuel est mis dans A afin de faire&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; l&amp;#39;opération suivante.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Calcul du reste de la division par 4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; On ajoute à ce reste le quotient de la division&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Et donc A contient le nouveau dividende.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;div3_4_loop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; C&amp;#39;est donc reparti pour un tour.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_4_end:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; On arrive ici si le dernier dividende est 3.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; dans ce cas, on ajoute 1 au résultat final.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;div3_4_exit:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le résultat final est stocké dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Échange des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Retour à l&amp;#39;appelant.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Les instructions déjà utilisées dans les articles précédents ne sont pas répétées ici, les nouvelles sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;srl&lt;/code&gt; décale le registre indiqué de 1 bit vers la droite. Le bit sortant est stocké dans le drapeau de retenu, mais ici, on ne l'utilise pas.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;and&lt;/code&gt; effectue une opération bit à bit entre l'accumulateur et l'opérande. Le résultat de chaque bit est 1 uniquement si les bits de chaque terme étaient 1 sur la même position.&lt;ul&gt;
&lt;li&gt;Exemple : &lt;code&gt;11111000&lt;/code&gt; and &lt;code&gt;00011111&lt;/code&gt; donne &lt;code&gt;00011000&lt;/code&gt;, car seuls le 2 bits centraux sont à 1 dans les deux termes.&lt;/li&gt;
&lt;li&gt;Ici, on s'en sert pour prendre le reste de la division par 4. Pourquoi est-ce que ça donne ce résultat est laissé en exercice.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Bon alors, c'est mieux ?&lt;/h4&gt;
&lt;p&gt;Un &lt;strong&gt;petit calcul&lt;/strong&gt; donne pour cette troisième version :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;29 octets. Encore &lt;strong&gt;plus grand&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Le nombre d'étapes maximum à faire donne 84 cycles. C'est un peu mieux. Dans le domaine de définition de l'affichage d'un point, le nombre à diviser le plus grand est 75, et cela donne alors 56 cycles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui fait que la première version n'est plus rapide que pour les nombres jusqu'à 5. Cette version est &lt;strong&gt;intéressante&lt;/strong&gt; et offre un &lt;strong&gt;bon compromis&lt;/strong&gt; entre taille du code et vitesse d'exécution. Au &lt;strong&gt;détriment&lt;/strong&gt; de la &lt;strong&gt;flexibilité&lt;/strong&gt;, puisque le calcul n'est valable que pour une division par 3.&lt;/p&gt;
&lt;p&gt;Le principe de l'algorithme pourrait être étendu à plus de nombres, mais au prix d'un taille plus grande et d'un fonctionnement un petit peu plus long. De toute façon ici, on ne s’intéresse qu'à une division par 3.&lt;/p&gt;
&lt;p&gt;La fois &lt;strong&gt;prochaine&lt;/strong&gt;, on verra une &lt;strong&gt;dernière manière&lt;/strong&gt; de faire, et puis on reviendra à l'étape suivante de l'affichage d'un point.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>VG5000µ, SetPoint en ASM, diviser plus vite</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser-plus-vite.html" rel="alternate"></link><published>2018-03-29T00:00:00+02:00</published><updated>2018-03-29T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-03-29:/vg5000m-setpoint-en-asm-diviser-plus-vite.html</id><summary type="html">&lt;p&gt;Dans le &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser.html"&gt;dernier article&lt;/a&gt;, j'avais écrit une &lt;strong&gt;première manière&lt;/strong&gt; d'effectuer &lt;strong&gt;une division&lt;/strong&gt;, en spécialisant la routine pour une division &lt;strong&gt;par 3&lt;/strong&gt; puisque c'est ce qui m'intéresse pour &lt;strong&gt;afficher un point&lt;/strong&gt; à l'écran du VG5000µ.&lt;/p&gt;
&lt;p&gt;Pour référence, cette routine nécessitait 15 octets en mémoire et son exécution pouvait prendre jusqu'à 695 cycles, ce qui est plutôt grand.&lt;/p&gt;
&lt;h4&gt;Micro optimisation&lt;/h4&gt;
&lt;p&gt;La première optimisation est une micro optimisation. On appelle micro optimisation une &lt;strong&gt;amélioration&lt;/strong&gt; de la routine par un &lt;strong&gt;détail&lt;/strong&gt; de fonctionnement, plutôt que par une réflexion sur l'ensemble de la méthode.&lt;/p&gt;
&lt;p&gt;Ici, l'idée est de remplacer le couple &lt;code&gt;push bc&lt;/code&gt; / &lt;code&gt;pop bc&lt;/code&gt; en début et fin de la routine par un couple &lt;code&gt;exx&lt;/code&gt; / &lt;code&gt;exx&lt;/code&gt;. L'instruction &lt;code&gt;exx&lt;/code&gt; du Z80 effectue un &lt;strong&gt;renommage&lt;/strong&gt; des &lt;strong&gt;registres&lt;/strong&gt; &lt;code&gt;BC&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt;. Ces registres (ainsi que d'autres, mais qui ne sont pas touchés par cette instruction) existent en &lt;strong&gt;deux exemplaires&lt;/strong&gt; dans le Z80. Un exemplaire de chaque …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans le &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser.html"&gt;dernier article&lt;/a&gt;, j'avais écrit une &lt;strong&gt;première manière&lt;/strong&gt; d'effectuer &lt;strong&gt;une division&lt;/strong&gt;, en spécialisant la routine pour une division &lt;strong&gt;par 3&lt;/strong&gt; puisque c'est ce qui m'intéresse pour &lt;strong&gt;afficher un point&lt;/strong&gt; à l'écran du VG5000µ.&lt;/p&gt;
&lt;p&gt;Pour référence, cette routine nécessitait 15 octets en mémoire et son exécution pouvait prendre jusqu'à 695 cycles, ce qui est plutôt grand.&lt;/p&gt;
&lt;h4&gt;Micro optimisation&lt;/h4&gt;
&lt;p&gt;La première optimisation est une micro optimisation. On appelle micro optimisation une &lt;strong&gt;amélioration&lt;/strong&gt; de la routine par un &lt;strong&gt;détail&lt;/strong&gt; de fonctionnement, plutôt que par une réflexion sur l'ensemble de la méthode.&lt;/p&gt;
&lt;p&gt;Ici, l'idée est de remplacer le couple &lt;code&gt;push bc&lt;/code&gt; / &lt;code&gt;pop bc&lt;/code&gt; en début et fin de la routine par un couple &lt;code&gt;exx&lt;/code&gt; / &lt;code&gt;exx&lt;/code&gt;. L'instruction &lt;code&gt;exx&lt;/code&gt; du Z80 effectue un &lt;strong&gt;renommage&lt;/strong&gt; des &lt;strong&gt;registres&lt;/strong&gt; &lt;code&gt;BC&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt;. Ces registres (ainsi que d'autres, mais qui ne sont pas touchés par cette instruction) existent en &lt;strong&gt;deux exemplaires&lt;/strong&gt; dans le Z80. Un exemplaire de chaque registre est utilisé pendant que l'autre ne l'est pas. Il est possible &lt;strong&gt;d'échanger les rôles&lt;/strong&gt; de ces paires.&lt;/p&gt;
&lt;p&gt;On peut imaginer un &lt;strong&gt;aiguillage&lt;/strong&gt; devant les registres. Le flux de données est aiguillé soit vers l'un des registres de la paire, soit vers l'autre. L'instruction &lt;code&gt;exx&lt;/code&gt; s'occupe de modifier l'aiguillage des registres &lt;code&gt;BC&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt; et &lt;code&gt;HL&lt;/code&gt;. Les registres inactifs sont nommés &lt;code&gt;BC'&lt;/code&gt;, &lt;code&gt;DE'&lt;/code&gt; et &lt;code&gt;HL'&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Puisqu'en entrée de la routine, je n'utilise que le registre &lt;code&gt;A&lt;/code&gt;, mais que j'ai besoin des autres registres pour les calculs, je peux &lt;strong&gt;préserver les valeurs&lt;/strong&gt; que les registres ont en entrée de fonction en utilisant l'autre série de registres.&lt;/p&gt;
&lt;p&gt;Les instructions &lt;code&gt;push bc&lt;/code&gt; et &lt;code&gt;pop bc&lt;/code&gt; prennent chacun 3 cycles à s'exécuter. &lt;code&gt;exx&lt;/code&gt; n'en prend qu'un. On passe donc de 6 cycles à 2, pour un &lt;strong&gt;gain de 4&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ce n'est pas grand chose par rapport au temps d'exécution de la routine elle-même, c'est donc une micro optimisation. Mais elle est simple à faire. La routine passe de 15 octets à 13.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Une autre&lt;/strong&gt; micro optimisation consiste à éviter un test en initialisant &lt;code&gt;B&lt;/code&gt; à &lt;code&gt;-1&lt;/code&gt; plutôt que &lt;code&gt;0&lt;/code&gt;. Mais comme ce n'est pas sur cette routine avec des micros optimisations que l'on va vraiment gagner, je laisse de côté.&lt;/p&gt;
&lt;h4&gt;Division comme à l'école&lt;/h4&gt;
&lt;p&gt;La &lt;strong&gt;première méthode&lt;/strong&gt; de division, celle de l'article précédent, se faisait par &lt;strong&gt;soustractions successives&lt;/strong&gt;. Tant que l'on pouvait soustraire le diviseur du dividende, on le faisait, tout en comptant le nombre de fois que cette soustraction était faite. Ce &lt;strong&gt;nombre de soustractions&lt;/strong&gt; est le &lt;strong&gt;résultat&lt;/strong&gt; de la division.&lt;/p&gt;
&lt;p&gt;Ce n'est pas comme cela que vous avez appris à diviser à l'école. Si on a appris la même méthode, à quelque chose comme ce qui suit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour diviser&lt;/strong&gt; (en base 10), 424 par 3, on pose :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   421 | 3
       |---
       |
       |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Puis on regarde si l'on peut diviser le premier 4 du dividende par 3. Oui, cela donne 1. On pose donc 1 dans le résultat et le résultat de la soustraction sous le 4 :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   421 | 3
  -3   |---
   -   | 1
   1   |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On passe au chiffre suivant, que l'on descend au niveau du 1. Cela donne 12, que l'on essaye de diviser par 3. Ok, cela donne 4, que l'on note dans le résultat. Le reste de la soustraction est noté sur la gauche du trait vertical :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   421 | 3
  -3   |---
   -   | 14
   12  |
  -12  |
   --
    0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On passe au chiffre suivant, que l'on descend au niveau du 0. Cela donne 1. On essaye de diviser par 3. Cela donne 0, car 1 est plus petit que 3. On note donc 0 à la suite du résultat, on soustrait sur la gauche (on soustrait 0 du coup) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   421 | 3
  -3   |---
   -   | 140
   12  |
  -12  |
   --
    01
   - 0
    --
     1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il n'y a plus de chiffre à traiter au dividende. Le résultat de la division est dans 140, et le reste 1.&lt;/p&gt;
&lt;p&gt;Faire une division avec &lt;strong&gt;cette méthode&lt;/strong&gt;, c'est dérouler &lt;strong&gt;un algorithme&lt;/strong&gt;. Et on peut transposer ça à l'ordinateur. On ne peut pas utiliser de division en base 10 puisque c'est exactement ce qu'on essaie ici d'implémenter. Mais sous forme binaire, le processeur a les &lt;strong&gt;instructions nécessaires&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Faisons un essai&lt;/strong&gt;. Divisons $101_{2}$ par $10_{2}$ (en binaire, indiqué par le petit 2, donc 5 par 2 en décimal) selon la même méthode.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   101 | 10
       |----
       |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On commence donc par prendre $1_{2}$ et essayer de diviser par $10_{2}$. Mais... il n'y a pas d'instruction de division sur le Z80 ! Qu'à cela ne tienne, nous sommes en binaire, et les &lt;strong&gt;deux seuls résultats possibles&lt;/strong&gt; en binaire &lt;strong&gt;sont $0_{2}$ et $1_{2}$&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Autrement dit, &lt;strong&gt;soit le nombre&lt;/strong&gt; que l'on considère est &lt;strong&gt;plus petit&lt;/strong&gt; que le &lt;strong&gt;diviseur&lt;/strong&gt; et le résultat est $0_{2}$, ce qui implique que l'on &lt;strong&gt;ne soustrait rien du tout&lt;/strong&gt; au dividende. Soit le résultat est $1_{2}$, ce qui implique que l'on &lt;strong&gt;soustrait le diviseur&lt;/strong&gt; au dividende.&lt;/p&gt;
&lt;p&gt;Puis on adjoint à ce résultat le chiffre binaire suivant.&lt;/p&gt;
&lt;p&gt;Autrement dit, nous n'avons besoin que de &lt;strong&gt;décalages&lt;/strong&gt; et de &lt;strong&gt;soustractions&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   101 | 10
  -0   |----
   -   | 0
   10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On considère donc $10_{2}$ qui n'est pas plus petit que le diviseur (il est même égal). Le résultat à retenir est donc 1 et l'on soustrait le diviseur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   101 | 10
  -0   |----
   -   | 01
   10
  -10
   --
   001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On considère $1_{2}$, qui est plus petit que le diviseur. On ne soustrait donc rien, on note 0 et... &lt;strong&gt;c'est terminé&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   101 | 10
  -0   |----
   -   | 010
   10
  -10
   --
   001
    -0
     -
     1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le résultat de $101_{2}$ divisé par $10_{2}$ est donc $10_{2}$, reste $1_{2}$. Soit en base 10 : 5 divisé par 2 est égal à 2 reste 1.&lt;/p&gt;
&lt;h4&gt;Algorithme&lt;/h4&gt;
&lt;p&gt;Pour implémenter cet algorithme, j'ai besoin de plusieurs choses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;De quoi retenir le nombre à considérer en cours,&lt;/li&gt;
&lt;li&gt;De quoi retenir ce qu'il reste du dividende à considérer,&lt;/li&gt;
&lt;li&gt;Le diviseur,&lt;/li&gt;
&lt;li&gt;De quoi retenir le résultat en cours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour se &lt;strong&gt;simplifier la vie&lt;/strong&gt;, on va considérer les &lt;strong&gt;8 bits du dividende&lt;/strong&gt;, même s'ils commencent par des &lt;code&gt;0&lt;/code&gt;. Lorsque l'on pose une division manuellement, on sait que &lt;strong&gt;des zéros en début&lt;/strong&gt; de nombre donnent des zéros en début de &lt;strong&gt;résultat&lt;/strong&gt;. Aucun de ces zéros ne sont significatifs.&lt;/p&gt;
&lt;p&gt;Pour notre calcul, il est plus simple de dérouler l'algorithme sur &lt;strong&gt;l'intégralité&lt;/strong&gt; du nombre en binaire.&lt;/p&gt;
&lt;p&gt;Cela donne donc cela:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialiser un registre comme compteur de bits à 8 (on a 8 bits à traiter)&lt;/li&gt;
&lt;li&gt;Initialiser un registre contenant le diviseur&lt;/li&gt;
&lt;li&gt;Initialiser un registre contenant le dividende (il est initialement dans &lt;code&gt;A&lt;/code&gt;, mais ce registre, l'accumulateur, va être nécessaire pour certaines opérations)&lt;/li&gt;
&lt;li&gt;Initialiser un registre à 0 pour retenir le reste&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ensuite, tant que le compteur de bits est positif, on déroule ce qui suit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;décale&lt;/strong&gt; les bits du &lt;strong&gt;résultat&lt;/strong&gt; de 1 vers la gauche en insérant un 0 à droite&lt;ul&gt;
&lt;li&gt;par exemple, si le résultat est actuellement &lt;code&gt;101&lt;/code&gt;, il devient &lt;code&gt;1010&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;décale&lt;/strong&gt; les bits du &lt;strong&gt;dividende&lt;/strong&gt; de 1 vers la gauche aussi, en insérant un 0&lt;ul&gt;
&lt;li&gt;même chose&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;décale&lt;/strong&gt; les bits de l'accumulateur de 1 vers la gauche, mais en &lt;strong&gt;insérant&lt;/strong&gt; cette fois le bit qui est &lt;em&gt;sorti&lt;/em&gt; du dividende par la gauche lors de l'opération précédente&lt;ul&gt;
&lt;li&gt;par exemple, si le dividende était &lt;code&gt;11000000&lt;/code&gt;, il a été décalé en &lt;code&gt;10000000&lt;/code&gt; et le &lt;code&gt;1&lt;/code&gt; est &lt;em&gt;sorti&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;si l'accumulateur contenait &lt;code&gt;00000010&lt;/code&gt;, il est décalé en &lt;code&gt;00000101&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;compare&lt;/strong&gt; le contenu de l'accumulateur avec le diviseur.&lt;/li&gt;
&lt;li&gt;Si l'accumulateur est &lt;strong&gt;égal ou plus grand&lt;/strong&gt; que le diviseur:&lt;ul&gt;
&lt;li&gt;on soustrait le diviseur de l'accumulateur&lt;/li&gt;
&lt;li&gt;on ajoute &lt;code&gt;1&lt;/code&gt; au résultat courant&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sinon, rien... vu qu'on a décalé le résultat, il contient un &lt;code&gt;0&lt;/code&gt; en dernière position.&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;décrémente&lt;/strong&gt; le compteur de bits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Registres&lt;/h4&gt;
&lt;p&gt;Les registres utilisés sont les suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt; est utilisé pour le &lt;strong&gt;compteur de bits&lt;/strong&gt;.&lt;ul&gt;
&lt;li&gt;C'est un choix naturel sur le &lt;strong&gt;Z80&lt;/strong&gt; qui permet d'utiliser l'instruction &lt;code&gt;DJNZ&lt;/code&gt; qui décrémente &lt;code&gt;B&lt;/code&gt; et fait un saut conditionnel si &lt;code&gt;B&lt;/code&gt; n'est pas égal à &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C&lt;/code&gt; contient le &lt;strong&gt;diviseur&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;D&lt;/code&gt; contient le &lt;strong&gt;dividende&lt;/strong&gt; (il faut donc y transférer &lt;code&gt;A&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;E&lt;/code&gt; contient le &lt;strong&gt;résultat&lt;/strong&gt; (qu'il faut donc initialiser à &lt;code&gt;0&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Le code&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3_3:&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie: valeur divisée par 3, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Utilisation des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Initialisation du compteur de bits à 8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Initialisation du diviseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Transfert du dividende dans D&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Mise à 0 de l&amp;#39;accumulateur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Mise à 0 du résultat&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_3_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sla&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Décalage de E vers la gauche&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le drapeau `Carry` contient le bit fort de E (qui est 0)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sla&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Décalage de D vers la gauche&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le drapeau `Carry` contient le bit fort de D&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;rla&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Décalage de A vers la gauche, avec récupération de la&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; valeur de `Carry`&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Comparaison de C et A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_3_skip&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Si C est plus grand que A, saut plus loin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Sinon, A est réduit de la valeur de C&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Et E est augmenté de 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;div3_3_skip:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div3_3_loop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; B est décrémenté et s&amp;#39;il n&amp;#39;est pas égal à 0,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; on repart en début de boucle&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_3_end:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le résultat est transféré dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;exx&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Échange des registres secondaires&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Retour à l&amp;#39;appelant.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Les instructions déjà utilisées dans les articles précédents ne sont pas répétées ici, les nouvelles sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exx&lt;/code&gt; a déjà été expliqué en début d'article sur la micro optimisation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xor&lt;/code&gt; effectue une opération de &lt;strong&gt;ou exclusif&lt;/strong&gt; pour chaque bit de même position entre l'accumulateur et le registre mentionné.&lt;ul&gt;
&lt;li&gt;Dans un &lt;em&gt;ou exclusif&lt;/em&gt;, le résultat est &lt;code&gt;1&lt;/code&gt; uniquement si l'on des deux bits est à &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;C'est &lt;strong&gt;impossible ici&lt;/strong&gt; puisque l'opération est effectuée entre l'accumulateur et... l'accumulateur.&lt;/li&gt;
&lt;li&gt;Le résultat est de &lt;strong&gt;mettre l'accumulateur&lt;/strong&gt; à &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;C'est un &lt;strong&gt;idiome classique&lt;/strong&gt;, car un &lt;code&gt;LD A,0&lt;/code&gt; prend deux octets en mémoire et deux cycles, alors que &lt;code&gt;XOR A&lt;/code&gt; ne prend qu'un seul octet et 1 cycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xor a&lt;/code&gt; suivi de &lt;code&gt;ld ?,a&lt;/code&gt; entre registre. C'est aussi un &lt;strong&gt;schéma classique&lt;/strong&gt;.&lt;ul&gt;
&lt;li&gt;Transférer entre deux registres prend un octet et un cycle, on profite donc d'avoir initialisé l'accumulateur pour initialiser un autre registre à la même valeur de manière efficace.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;djnz&lt;/code&gt;, comme indiqué au-dessus, effectue plusieurs opérations. Tout d'abord, &lt;code&gt;B&lt;/code&gt; est décrémenté. Puis si &lt;code&gt;B&lt;/code&gt; est égal à zéro, l'instruction se termine. Sinon, un branchement à lieu à l'adresse indiquée en paramètre.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Et c'est mieux ?&lt;/h4&gt;
&lt;p&gt;Un &lt;strong&gt;petit calcul&lt;/strong&gt; donne pour cette nouvelle version :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;23 octets... c'est &lt;strong&gt;moins bien&lt;/strong&gt; que 12 octets avec les deux micro optimisations, certes.&lt;/li&gt;
&lt;li&gt;Entre &lt;strong&gt;103&lt;/strong&gt; et &lt;em&gt;111&lt;/em&gt; cycles en fonction du nombre de &lt;code&gt;1&lt;/code&gt; dans le résultat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Niveau vitesse, c'est beaucoup moins qu'avant la méthode précédente ! La routine est peut-être deux fois plus grosse, mais elle est beaucoup &lt;strong&gt;plus stable&lt;/strong&gt; en temps d'exécution et &lt;strong&gt;en moyenne plus rapide&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Oui mais &lt;strong&gt;attention&lt;/strong&gt; ! Si elle est plus rapide dans le cas général, dans le cadre de l'affichage d'un point, le nombre maximal à diviser est 75. Et pour 75, la vitesse de la première version est de 215. En fait, pour tout dividende inférieur à 36, la première version de la division par 3 est plus rapide.&lt;/p&gt;
&lt;p&gt;Note de fin d'article : on peut micro-optimiser le code ci-dessous en se passant de &lt;code&gt;E&lt;/code&gt; et en stockant le résultat dans &lt;code&gt;D&lt;/code&gt; au fur et à mesure de son décalage (qui libère de l'espace au fur et à mesure). Cela évite deux &lt;code&gt;LD&lt;/code&gt; et un &lt;code&gt;SLA&lt;/code&gt;, ce qui rend la fonction compétitive plutôt vers 34.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>Visite au Computer History Museum</title><link href="https://www.triceraprog.fr/visite-au-computer-history-museum.html" rel="alternate"></link><published>2018-03-28T00:00:00+02:00</published><updated>2018-03-28T00:00:00+02:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-03-28:/visite-au-computer-history-museum.html</id><summary type="html">&lt;p&gt;La semaine dernière, profitant d'un voyage à &lt;strong&gt;San Francisco&lt;/strong&gt;, j'ai allongé un peu mon séjour pour pousser jusqu'à &lt;strong&gt;Mountain View&lt;/strong&gt; et aller visiter un musée qui semblait fort intéressant. Le &lt;strong&gt;Musée de l'Histoire des Ordinateurs&lt;/strong&gt;, ou dans le texte « &lt;a href="http://www.computerhistory.org/"&gt;Computer History Museum&lt;/a&gt; »&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dépliant du musée" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_001_Depliant.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Première chose à savoir si vous êtes à San Francisco même, que vous choisissiez le &lt;strong&gt;train&lt;/strong&gt; (pas cher, mais long, avec changement) ou la &lt;strong&gt;voiture&lt;/strong&gt; (plus cher, un peu moins long), &lt;strong&gt;prévoyez le trajet&lt;/strong&gt; pour ne pas arriver trop tard. En effet, le musée &lt;strong&gt;ferme assez tôt&lt;/strong&gt; : 17h.&lt;/p&gt;
&lt;p&gt;En voiture, tant qu'à visiter, vous pourrez faire un détour par la &lt;strong&gt;280&lt;/strong&gt; pour passer par des endroits sympas ou la &lt;strong&gt;1&lt;/strong&gt; pour des endroits encore plus sympa, à l'aller ou au retour. Ou opter par la &lt;strong&gt;101&lt;/strong&gt; pour aller au plus direct (mais potentiellement aussi plus encombrée, vérifiez avant de partir).&lt;/p&gt;
&lt;p&gt;De notre côté (puisque nous étions deux), nous …&lt;/p&gt;</summary><content type="html">&lt;p&gt;La semaine dernière, profitant d'un voyage à &lt;strong&gt;San Francisco&lt;/strong&gt;, j'ai allongé un peu mon séjour pour pousser jusqu'à &lt;strong&gt;Mountain View&lt;/strong&gt; et aller visiter un musée qui semblait fort intéressant. Le &lt;strong&gt;Musée de l'Histoire des Ordinateurs&lt;/strong&gt;, ou dans le texte « &lt;a href="http://www.computerhistory.org/"&gt;Computer History Museum&lt;/a&gt; »&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dépliant du musée" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_001_Depliant.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Première chose à savoir si vous êtes à San Francisco même, que vous choisissiez le &lt;strong&gt;train&lt;/strong&gt; (pas cher, mais long, avec changement) ou la &lt;strong&gt;voiture&lt;/strong&gt; (plus cher, un peu moins long), &lt;strong&gt;prévoyez le trajet&lt;/strong&gt; pour ne pas arriver trop tard. En effet, le musée &lt;strong&gt;ferme assez tôt&lt;/strong&gt; : 17h.&lt;/p&gt;
&lt;p&gt;En voiture, tant qu'à visiter, vous pourrez faire un détour par la &lt;strong&gt;280&lt;/strong&gt; pour passer par des endroits sympas ou la &lt;strong&gt;1&lt;/strong&gt; pour des endroits encore plus sympa, à l'aller ou au retour. Ou opter par la &lt;strong&gt;101&lt;/strong&gt; pour aller au plus direct (mais potentiellement aussi plus encombrée, vérifiez avant de partir).&lt;/p&gt;
&lt;p&gt;De notre côté (puisque nous étions deux), nous avons opté par un peu de balade sur le chemin.&lt;/p&gt;
&lt;p&gt;&lt;img alt="La plage" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_002_Plage.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Arrivé au musée et ayant acquitté notre droit d'entrée, après une petite explication de l'agencement à l'accueil et la remise d'un plan, nous voici parti pour une &lt;strong&gt;aventure&lt;/strong&gt; d'environ &lt;strong&gt;quatre heures&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Coup de bol ? Ce jour là, des étudiants du coin faisaient une &lt;strong&gt;démonstration&lt;/strong&gt; à l'entrée d'&lt;strong&gt;appareils fonctionnels&lt;/strong&gt; et d'artefacts divers (comme un reste de Silicon après découpage de Wafers). Les visiteurs pouvaient donc goûter au plaisir de perforation d'une carte (c'est un plaisir quand c'est dans un musée...).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Performation de carte" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_003_Punch.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Puis la visite commence. Un petit &lt;strong&gt;film d'introduction&lt;/strong&gt; peut être visionné, mais je ne l'ai pas fait, j'avais hâte de voir du concret.&lt;/p&gt;
&lt;p&gt;L'exposition principale est divisée en &lt;strong&gt;20 zones thématiques&lt;/strong&gt; et globalement chronologique. Globalement car les époques recouvertes par les thèmes se superposent dans l'histoire des ordinateurs. La &lt;strong&gt;première zone&lt;/strong&gt; est consacrée au &lt;strong&gt;calcul&lt;/strong&gt;, le besoin initial à la base de tout ça. Règles à calcul, bouliers (que l'on peut manipuler), métier de « calculateur » permettant de dresser les tables de fonctions.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Règle à calcul" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_004_SlideRule.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Mais encore &lt;strong&gt;calculatrices&lt;/strong&gt;, mécaniques tout d'abord puis électroniques (mais non programmables). Et que serait cet endroit sans la réplique de la sous-partie de démonstration de la &lt;strong&gt;Machine à Différences&lt;/strong&gt; de &lt;strong&gt;Charles Babbage&lt;/strong&gt; ? Près de là, les plans de la &lt;strong&gt;Machine Analytique&lt;/strong&gt; du même inventeur, bien entendu avec mention des travaux d'&lt;strong&gt;Ada Lovelace&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Machine à Différences" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_005_DifferenceMachine.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Suit un très intéressant reportage sur la culture d'entreprise d'&lt;strong&gt;IBM&lt;/strong&gt; au début du XXième siècle. Le musée est comme cela ponctué de &lt;strong&gt;nombreux reportages&lt;/strong&gt; ou extraits de films, interviews et reportages d'époque. Il y en a vraiment beaucoup et malgré les quatre heures de visite, je n'ai pas tout pu regarder.&lt;/p&gt;
&lt;p&gt;Ce passage est dans la zone 2, consacrée aux &lt;strong&gt;cartes perforées&lt;/strong&gt;, dont IBM fut un grand fournisseur.&lt;/p&gt;
&lt;p&gt;&lt;img alt="IBM, think" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_006_IBM.jpg"&gt;&lt;/p&gt;
&lt;p&gt;De là, on passe en zone 3, consacrée aux &lt;strong&gt;calculateurs analogiques&lt;/strong&gt; et des « batailles » qui s'ensuivent entre les modèles numériques et les modèles analogiques, ainsi que des fusions entre les deux systèmes.&lt;/p&gt;
&lt;p&gt;Une machine analogique câblée nous montre bien la similitude avec l'état de certaines bases de code actuelles...&lt;/p&gt;
&lt;p&gt;&lt;img alt="Calculateur Analogique" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_007_AnalogComputer.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Peut-être préférez-vous le câblage suivant.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Autre calculateur Analogique" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_008_AnalogComputer_2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Les zones suivantes sont consacrées à la &lt;strong&gt;naissance des ordinateurs&lt;/strong&gt; ainsi qu'à l'histoire des &lt;strong&gt;premières compagnies&lt;/strong&gt; à se lancer dans le secteur. On y trouve quelques ordinateurs à lampes de dimensions conséquentes, comme des morceaux d'&lt;strong&gt;ENIAC&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le musée présente aussi des &lt;strong&gt;blocs de bases&lt;/strong&gt; d'un ordinateur dans leurs formes d'alors, et rappellent que des pistes initiales se tournaient vers la &lt;strong&gt;mécanique&lt;/strong&gt;. Sur l'image suivante, une porte logique mécanique à gauche (a priori un inverseur), et une additionneur/soustracteur à lampe à droite.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Portes" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_009_Gates.jpg"&gt;&lt;/p&gt;
&lt;p&gt;La zone suivante, la 6, nous amène aux besoins de calculs en temps réel et nous rappelle les besoins de l'&lt;strong&gt;armée&lt;/strong&gt;, toujours très gourmande en calculs pour la &lt;strong&gt;balistique&lt;/strong&gt;. Et très &lt;strong&gt;avide d'information&lt;/strong&gt; à des fins de surveillance dans une époque de &lt;strong&gt;guerre froide&lt;/strong&gt;. Des éléments du système &lt;a href="https://fr.wikipedia.org/wiki/Semi-Automatic_Ground_Environment"&gt;SAGE&lt;/a&gt; sont exposés.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Système SAGE" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_010_SAGE.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Tout cela demande de la &lt;strong&gt;puissance&lt;/strong&gt; de calcul &lt;strong&gt;grandissante&lt;/strong&gt;, et nous entrons à présent dans la zone 7, dédiée aux &lt;strong&gt;Mainframes&lt;/strong&gt;. L'&lt;strong&gt;IBM 360&lt;/strong&gt; y trône en bonne place, avec ses beaux dérouleurs de bande rouge et bleus.&lt;/p&gt;
&lt;p&gt;&lt;img alt="IBM 360" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_011_IBM360.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Et avec des possibilités de calculs grandissante vient les &lt;strong&gt;besoins en stockage&lt;/strong&gt; grandissants eux aussi. La zone 8 s'intéresse à &lt;strong&gt;la mémoire&lt;/strong&gt;, qu'elle soit persistante ou non. En partant de quelques artefacts très lointains, comme un système de stockage d'information &lt;strong&gt;Inca&lt;/strong&gt; utilisant &lt;strong&gt;des cordes&lt;/strong&gt;, on arrive sur des systèmes plus récents. Un mur de stockage présente de nombreux systèmes : lecteurs de disquettes, cartouches, cassettes, disques magnétiques...&lt;/p&gt;
&lt;p&gt;Tout ça, c'est bien beau, mais sans logiciel, cela ne va pas bien loin. C'est la zone 9 qui présente &lt;strong&gt;la programmation&lt;/strong&gt;. Le musée est principalement focalisé sur le matériel, et si le logiciel est toujours dans l'air, ce n'est pas sont point central (voir plus loin pour la section déportée du musée). À un mur, une &lt;strong&gt;fresque&lt;/strong&gt; généalogique des différents &lt;strong&gt;langages&lt;/strong&gt; de programmation s’étale sur quelques mètres. C'est une version cependant &lt;strong&gt;très simplifiée&lt;/strong&gt;, même si les jalons essentiels sont là.&lt;/p&gt;
&lt;p&gt;Une film explicatif constitue la principale attraction de la zone. Il faut dire que ce n'est pas si évident de montrer du logiciel dans un contexte de vieilles machines dont la plupart ne fonctionnent pas et qui étaient utilisées principalement pour des calculs scientifiques, militaires et des traitements administratifs.&lt;/p&gt;
&lt;p&gt;Ah si, tout de même, un badge &lt;a href="https://fr.wikipedia.org/wiki/DECUS"&gt;&lt;strong&gt;DECUS&lt;/strong&gt;&lt;/a&gt; rappelle que le principe du &lt;strong&gt;partage de logiciel&lt;/strong&gt; via des sources de code ouvertes ne date pas d'hier, puisque le groupe a été créé en 1961 et que la pratique le précédait.&lt;/p&gt;
&lt;p&gt;&lt;img alt="DECUS" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_012_DECUS.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Si les Mainframes, c'était du trop petit pour vous, la zone 10 en remet une couche avec une présentation de &lt;strong&gt;Super Ordinateurs&lt;/strong&gt;. Forcément, vu la place que cela prend, il n'y a pas beaucoup de pièces. On y trouve aussi un cluster de PCs. Bien entendu, que serait une section Super Ordinateurs sans &lt;strong&gt;Cray&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Un film rapide retrace au passage la vie de &lt;strong&gt;Seymour Cray&lt;/strong&gt; et des particularités de ses ordinateurs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cray" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_013_CRAY.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Ils ont plein de petites LEDs qui clignotent et des petits leviers tous sympas, ils sont tout minis se sont les... &lt;strong&gt;Minis Ordinateurs&lt;/strong&gt; de la zone 11. Des &lt;strong&gt;PDP-8&lt;/strong&gt;, &lt;strong&gt;PDP-11&lt;/strong&gt;, du &lt;strong&gt;HP&lt;/strong&gt;, du &lt;strong&gt;CDC&lt;/strong&gt;, un modèle de PDP-8 qui a servi pour des opérations chirurgicales du cerveau et a permis d'effectuer celles-ci avec endormissement du patient (car donc, apparemment, auparavant, le patient devait rester réveillé...)&lt;/p&gt;
&lt;p&gt;&lt;img alt="PDP-8" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_014_PDP8.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Bien évidemment, la section évoque &lt;strong&gt;UNIX&lt;/strong&gt; et présente un manuel d'époque.&lt;/p&gt;
&lt;p&gt;Puis l'on passe en zone 12, consacré à la &lt;strong&gt;logique numérique&lt;/strong&gt; au cœur du fonctionnement de toutes ces machines jusqu'à nos tablettes et téléphones actuels. Quelques &lt;strong&gt;portes logiques&lt;/strong&gt; peuvent être actionnées avec des interrupteurs (dommage, le Flip Flop ne fonctionnait pas à cause d'un bouton défectueux). Un film présente les &lt;strong&gt;étapes&lt;/strong&gt; de &lt;strong&gt;fabrication&lt;/strong&gt; d'un &lt;strong&gt;circuit intégré&lt;/strong&gt;, et l'on peut regarder à la loupe plusieurs générations de ces puces. Quelques &lt;strong&gt;wafers&lt;/strong&gt; de différentes tailles accompagnent le tout.&lt;/p&gt;
&lt;p&gt;La zone 13 est consacrée à la &lt;strong&gt;robotique&lt;/strong&gt; et à l'&lt;strong&gt;intelligence artificielle&lt;/strong&gt;, avec de nombreux robots vintage en exposition. Mes photos de cette section étant toutes floues, passons.&lt;/p&gt;
&lt;p&gt;En zone 14, on découvre la thématique de la &lt;strong&gt;création artistique&lt;/strong&gt; à travers l'outil informatique. Ici, à côté d'un cube de &lt;strong&gt;PIXAR&lt;/strong&gt;, de système &lt;strong&gt;SUN&lt;/strong&gt;, de &lt;strong&gt;tables traçantes&lt;/strong&gt; et de &lt;strong&gt;synthétiseurs&lt;/strong&gt;, on trouve une machine au logo qui aura marqué une époque en &lt;strong&gt;image numérique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Silicon Graphic" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_015_SGI.jpg"&gt;&lt;/p&gt;
&lt;p&gt;J'y ai découvert aussi un accessoire pour &lt;strong&gt;Commodore 64&lt;/strong&gt; que je ne connaissais pas du tout. Le &lt;strong&gt;Incredible Music Keyboard&lt;/strong&gt;, qui se place au dessus de la coque d'un C64 pour le transformer en synthétiseur. J'aurais du mieux regarder la chaîne &lt;a href="https://www.youtube.com/watch?v=RX4JfLCaBMU"&gt;8-Bit Keys&lt;/a&gt;, qui en fait une présentation.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Incredible Music Keyboard" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_016_IncredibleMusicKeyboard.jpg"&gt;&lt;/p&gt;
&lt;p&gt;La zone 15 s'intéresse au &lt;strong&gt;périphériques d'entrées et sorties&lt;/strong&gt;. Le coin est plutôt fourni en périphériques &lt;strong&gt;exotiques&lt;/strong&gt;, dont beaucoup étaient des idées... intéressantes. Et dont d'autres ont eu plus de succès. Et quoi de mieux pour accueillir le visiteur dans cette zone que le très à propos &lt;strong&gt;Xerox Alto&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Xerox Alto" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_017_XeroxAlto.jpg"&gt;&lt;/p&gt;
&lt;p&gt;La zone 16 est consacrée aux &lt;strong&gt;jeux vidéo&lt;/strong&gt;. Pas de trucs renversants à ce niveau-là, beaucoup de musées de vieilleries informatiques se focalisant essentiellement sur le matériel de jeu, il est &lt;strong&gt;difficile de faire original&lt;/strong&gt;. Trois pods de démonstrations permettent de jouer à des jeux assez différents : un jeu d'aventure textuel, Spacewar! et PAC-MAN. Les trois en « reproduction » (plutôt des recréations que de l'émulation j'ai l'impression... mais je n'en sais rien).&lt;/p&gt;
&lt;p&gt;Bref, passons ici aussi.&lt;/p&gt;
&lt;p&gt;La zone 17 présente l'&lt;strong&gt;ordinateur personnel&lt;/strong&gt;. Le Micro, ça y est, l'ère &lt;strong&gt;grand public&lt;/strong&gt; (ou presque) commence. C'est un &lt;strong&gt;IBM PC&lt;/strong&gt; qui nous reçoit dans la zone. Vu la taille de ces nouvelles machines, de &lt;strong&gt;nombreuses&lt;/strong&gt; pièces différentes sont &lt;strong&gt;présentées&lt;/strong&gt;. Apple I et II, TRS-80, Commodore PET, Atari 800XL, Lisa,...&lt;/p&gt;
&lt;p&gt;&lt;img alt="IBM PC" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_018_IBM-PC.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Mais aussi de l'&lt;strong&gt;exotisme&lt;/strong&gt; (vu des Etats-Unis), avec un Smaky, un Amstrad 464, du Spectrum,... Un clone russe de ZX Spectrum.&lt;/p&gt;
&lt;p&gt;Et un &lt;strong&gt;Thomson TO7-70&lt;/strong&gt; ! Malheureusement un peu dans l'ombre.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Thomson TO7-70" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_019_TO7-70.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Et puisqu'on est dans l'ordinateur français, un petit &lt;strong&gt;Micral&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Micral" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_020_Micral.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Toute une partie est à l'honneur du &lt;strong&gt;Do It Yourself&lt;/strong&gt; de l'époque : ces machines que l'on pouvait recevoir en &lt;strong&gt;kit&lt;/strong&gt;, ou bien dont on ne recevait que des parties essentielles, à compléter ensuite, en suivant éventuellement un &lt;strong&gt;plan&lt;/strong&gt; dans un &lt;strong&gt;magazine&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ici, un &lt;strong&gt;Altaïr 8800&lt;/strong&gt; côtoie (mais de pas trop près) un &lt;strong&gt;Imsai 8080&lt;/strong&gt;. Mais aussi un &lt;strong&gt;EDUC-8&lt;/strong&gt; Australien (que je ne connaissais pas), une carte &lt;strong&gt;KIM-1&lt;/strong&gt; et de nombreux autres.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Altair 8800" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_021_Altair.jpg"&gt;&lt;/p&gt;
&lt;p&gt;De la zone 17 on passe à la zone... 18 ! Celle-ci présente l'&lt;strong&gt;informatique mobile&lt;/strong&gt;. En partant des portatifs initiaux (et de publicités où l'on voit des utilisateurs suer avec le &lt;strong&gt;sourire&lt;/strong&gt; en traînant une mallette de plomb signe de leur &lt;strong&gt;modernité&lt;/strong&gt;), on passe par les ordinateurs portables de différentes époques et les organiseurs personnels.&lt;/p&gt;
&lt;p&gt;Le pôle &lt;strong&gt;interactif&lt;/strong&gt; offre de soulever un &lt;strong&gt;Osborne 1&lt;/strong&gt; dans sa malette, pour juger du temps pendant lequel nous aurions pu &lt;strong&gt;garder le sourire&lt;/strong&gt; en se baladant avec. On est loin des quelques centaines de grammes de tablettes actuelles.&lt;/p&gt;
&lt;p&gt;La zone 19 présente la &lt;strong&gt;mise en réseau&lt;/strong&gt;, en commençant par le commencement : la mise en relation de personnes à distance. &lt;strong&gt;Télégraphe&lt;/strong&gt;, puis &lt;strong&gt;téléphone&lt;/strong&gt;, avec des cartes de l'évolution des &lt;strong&gt;lignes&lt;/strong&gt; reliant les &lt;strong&gt;continents&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Un petit bouton permet de retrouver le délicieux &lt;strong&gt;son&lt;/strong&gt; d'une communication entre ordinateurs via &lt;strong&gt;Modem&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Modem" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_022_Modem.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Est exposée aussi une des premières armoire à &lt;strong&gt;serveurs de Google&lt;/strong&gt;, tout un tas de &lt;strong&gt;modems&lt;/strong&gt;, de &lt;strong&gt;routeurs&lt;/strong&gt; et autres matériels de communication. Des initiatives aussi, comme les &lt;strong&gt;ordinateurs communautaires&lt;/strong&gt; hippies.&lt;/p&gt;
&lt;p&gt;Côtés ordinateurs associés à cette thématique, un &lt;strong&gt;NeXT Cube&lt;/strong&gt;, mais aussi un &lt;strong&gt;Minitel&lt;/strong&gt;, expliquant que bien avant l'essor grand public d'Internet, en &lt;strong&gt;France&lt;/strong&gt;, il était possible d'aller &lt;strong&gt;chercher des renseignements&lt;/strong&gt; en ligne ou de &lt;strong&gt;réserver un train&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Minitel" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_023_Minitel.jpg"&gt;&lt;/p&gt;
&lt;p&gt;La dernière zone, la vingtième est une zone &lt;strong&gt;tournée vers l'avenir&lt;/strong&gt;. Principalement un &lt;strong&gt;film&lt;/strong&gt; interviewant quelques personnalités de la Silicon Valley. J'avoue ne pas l'avoir regardé. on sort avec cette zone de l'Histoire pour entrer dans l'actuel, et l'actuel est tous les jours.&lt;/p&gt;
&lt;p&gt;C'est ainsi que se termine la visite de l'exposition principale. Mais pas du musée.&lt;/p&gt;
&lt;h4&gt;PDP-1 et Spacewars!&lt;/h4&gt;
&lt;p&gt;Si la quasi totalité des machines exposées ne sont pas en fonctionnement, le musée possède &lt;strong&gt;deux salles&lt;/strong&gt; consacrées à deux &lt;strong&gt;machines emblématiques&lt;/strong&gt; restaurées et &lt;strong&gt;en état de fonctionnement&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La première salle est celle du &lt;strong&gt;PDP-1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La vénérable machine n'est cependant &lt;strong&gt;allumée&lt;/strong&gt; que &lt;strong&gt;deux fois par mois&lt;/strong&gt; à un horaire bien précis... Et le jour de ma visite n'était pas un jour de démonstration. C'est dommage, mais tant pis.&lt;/p&gt;
&lt;p&gt;La démonstration consiste, entre autre, à lancer le jeu &lt;strong&gt;Spacewars!&lt;/strong&gt; Il est même possible d'y jouer, avec des contrôles déportés dans la zone visiteur. Le &lt;strong&gt;stylo optique&lt;/strong&gt; est aussi fonctionnel.&lt;/p&gt;
&lt;p&gt;&lt;img alt="PDP-1" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_024_PDP-1.jpg"&gt;&lt;/p&gt;
&lt;h4&gt;IBM 1401&lt;/h4&gt;
&lt;p&gt;La &lt;strong&gt;seconde salle&lt;/strong&gt; est encore &lt;strong&gt;plus vaste&lt;/strong&gt; et est utilisée pour une installation d'&lt;strong&gt;IBM 1401&lt;/strong&gt;. Un film explique l'histoire de sa &lt;strong&gt;restauration&lt;/strong&gt;, qui aura été longue et fastidieuse.&lt;/p&gt;
&lt;p&gt;Là encore, il faut tomber le &lt;strong&gt;bon jour&lt;/strong&gt; et la &lt;strong&gt;bonne heure&lt;/strong&gt; pour la &lt;strong&gt;démonstration&lt;/strong&gt;. C'était le bon jour, mais nous sommes arrivés après la mise en route, qui a lieu le matin.&lt;/p&gt;
&lt;p&gt;Mais même éteinte, la machine est &lt;strong&gt;impressionnante&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="IBM 1401" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/CHM_025_1401.jpg"&gt;&lt;/p&gt;
&lt;h4&gt;Le reste&lt;/h4&gt;
&lt;p&gt;Et ce n'est pas fini. Mais le musée allait fermer 30 minutes après et j'ai parcouru le reste un peu plus rapidement. J'ai dédié la majeure partie du temps restant à l'exposition sur &lt;strong&gt;Ada Lovelace&lt;/strong&gt;, qui présente quelques manuscrits de sa main et lettres de Charles Babbage à son attention. Qui retrace aussi en quelques panneaux sa vie.&lt;/p&gt;
&lt;p&gt;À côté, une mini expo sur les &lt;strong&gt;transports automatisés&lt;/strong&gt;, qui me semble est surtout une excuse pour présenter la voiture toute ronde de chez Google.&lt;/p&gt;
&lt;p&gt;Le dernier grand espace est dédié au &lt;strong&gt;logiciel&lt;/strong&gt; sous différents aspects : jeu, musique, image, connaissance, simulation, industrie textile. Chaque poste montre &lt;strong&gt;l'évolution du travail&lt;/strong&gt; dans ces domaines avec l'arrivé de l'informatique. Par exemple en juxtaposant le développement de pellicule en chambre noir et Photoshop.&lt;/p&gt;
&lt;p&gt;Exposition plutôt bien faite, mais que j'ai traversée un peu en coup de vent. Je n'étais pas venu pour cela.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Ce musée est &lt;strong&gt;fantastique&lt;/strong&gt;. Les quatre heures passées, nullement suffisante pour tout voir dans les détails, sont passées très rapidement. Beaucoup de pièces intéressantes, des explications, des films d'archive, des reportages,... &lt;/p&gt;
&lt;p&gt;Si vous passez dans le coin, &lt;strong&gt;n'hésitez-pas&lt;/strong&gt; !&lt;/p&gt;</content><category term="Divers"></category><category term="Musée"></category><category term="Histoire"></category></entry><entry><title>VG5000µ, SetPoint en ASM, diviser</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-diviser.html" rel="alternate"></link><published>2018-03-06T00:00:00+01:00</published><updated>2018-03-06T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-03-06:/vg5000m-setpoint-en-asm-diviser.html</id><summary type="html">&lt;p&gt;À présent que j'ai un &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-les-resultats.html"&gt;garde fou&lt;/a&gt; pour vérifier que je ne fais pas d'erreur d'inattention, me voilà près à diviser des nombres. Pour rappel j'ai besoin de diviser des nombres afin de faire les calculs permettant d'affiche le bon pixel à l'écran.&lt;/p&gt;
&lt;p&gt;Pour second rappel, le &lt;strong&gt;Z80&lt;/strong&gt;, au cœur du &lt;strong&gt;VG5000µ&lt;/strong&gt; (et de beaucoup d'autres ordinateurs de l'époque) &lt;strong&gt;n'a pas&lt;/strong&gt; d'instruction de &lt;strong&gt;division&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;La division&lt;/h4&gt;
&lt;p&gt;Lorsque je &lt;strong&gt;divise&lt;/strong&gt; de manière &lt;strong&gt;entière&lt;/strong&gt; &lt;code&gt;a&lt;/code&gt; par &lt;code&gt;b&lt;/code&gt;, je veux &lt;strong&gt;trouver&lt;/strong&gt; le nombre &lt;code&gt;c&lt;/code&gt; tel quel $c * b = a$. Comme la division ne tombe pas toujours &lt;em&gt;juste&lt;/em&gt;, j'ai aussi &lt;strong&gt;un reste&lt;/strong&gt; &lt;code&gt;r&lt;/code&gt; tel que $c * b + r = a$.&lt;/p&gt;
&lt;p&gt;Autrement dit, combien de fois dois-je additionner &lt;code&gt;b&lt;/code&gt; pour obtenir &lt;code&gt;a&lt;/code&gt; (au reste près). Une &lt;strong&gt;manière&lt;/strong&gt; de trouver le &lt;strong&gt;résultat&lt;/strong&gt; est de &lt;strong&gt;soustraire&lt;/strong&gt; &lt;code&gt;b&lt;/code&gt; à &lt;code&gt;a&lt;/code&gt; autant de fois que l'on peut sans passer sous &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Par exemple, $\frac{21}{7}$ se trouve comme ceci …&lt;/p&gt;</summary><content type="html">&lt;p&gt;À présent que j'ai un &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-les-resultats.html"&gt;garde fou&lt;/a&gt; pour vérifier que je ne fais pas d'erreur d'inattention, me voilà près à diviser des nombres. Pour rappel j'ai besoin de diviser des nombres afin de faire les calculs permettant d'affiche le bon pixel à l'écran.&lt;/p&gt;
&lt;p&gt;Pour second rappel, le &lt;strong&gt;Z80&lt;/strong&gt;, au cœur du &lt;strong&gt;VG5000µ&lt;/strong&gt; (et de beaucoup d'autres ordinateurs de l'époque) &lt;strong&gt;n'a pas&lt;/strong&gt; d'instruction de &lt;strong&gt;division&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;La division&lt;/h4&gt;
&lt;p&gt;Lorsque je &lt;strong&gt;divise&lt;/strong&gt; de manière &lt;strong&gt;entière&lt;/strong&gt; &lt;code&gt;a&lt;/code&gt; par &lt;code&gt;b&lt;/code&gt;, je veux &lt;strong&gt;trouver&lt;/strong&gt; le nombre &lt;code&gt;c&lt;/code&gt; tel quel $c * b = a$. Comme la division ne tombe pas toujours &lt;em&gt;juste&lt;/em&gt;, j'ai aussi &lt;strong&gt;un reste&lt;/strong&gt; &lt;code&gt;r&lt;/code&gt; tel que $c * b + r = a$.&lt;/p&gt;
&lt;p&gt;Autrement dit, combien de fois dois-je additionner &lt;code&gt;b&lt;/code&gt; pour obtenir &lt;code&gt;a&lt;/code&gt; (au reste près). Une &lt;strong&gt;manière&lt;/strong&gt; de trouver le &lt;strong&gt;résultat&lt;/strong&gt; est de &lt;strong&gt;soustraire&lt;/strong&gt; &lt;code&gt;b&lt;/code&gt; à &lt;code&gt;a&lt;/code&gt; autant de fois que l'on peut sans passer sous &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Par exemple, $\frac{21}{7}$ se trouve comme ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il y a trois &lt;strong&gt;soustractions&lt;/strong&gt;, et donc $\frac{21}{7} = 3$&lt;/p&gt;
&lt;p&gt;Un autre exemple avec $\frac{17}{3}$ :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mf"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il y a cinq &lt;strong&gt;soustractions&lt;/strong&gt;, et il reste &lt;code&gt;2&lt;/code&gt; à la fin, dont la soustraction de &lt;code&gt;5&lt;/code&gt; donnerait &lt;code&gt;-3&lt;/code&gt;. On s'arrête donc et $\frac{17}{3} = 5 + \frac{2}{3}$&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;problème majeur&lt;/strong&gt; de cette façon de faire est que plus le &lt;strong&gt;résultat est grand&lt;/strong&gt;, plus il a fallu de &lt;strong&gt;calculs&lt;/strong&gt; pour le trouver. Si on divise de grands chiffres par de petits, cet &lt;strong&gt;algorithme est lent&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il est par contre &lt;strong&gt;très facile&lt;/strong&gt; à &lt;strong&gt;programmer&lt;/strong&gt;. La séquence donne ceci :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mettre le dividende (le nombre à diviser) dans &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mettre le diviseur dans &lt;code&gt;C&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mettre &lt;code&gt;0&lt;/code&gt; dans &lt;code&gt;B&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tant que &lt;code&gt;A&lt;/code&gt; est supérieur à &lt;code&gt;C&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;Soustraire &lt;code&gt;C&lt;/code&gt; à &lt;code&gt;A&lt;/code&gt; et mettre le résultat dans &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ajouter &lt;code&gt;1&lt;/code&gt; à &lt;code&gt;B&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Le quotient (le résultat de la division entière) est dans &lt;code&gt;B&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Le reste de la division entière est dans &lt;code&gt;A&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Implémentation par soustractions&lt;/h4&gt;
&lt;p&gt;Il y a des &lt;strong&gt;limitations&lt;/strong&gt; bien entendu à faire cette division sur des registres 8 bits. Je ne pourrai pas traiter des nombres supérieurs à &lt;code&gt;255&lt;/code&gt;. Pour afficher un point, je n'en ai pas besoin, c'est donc très bien.&lt;/p&gt;
&lt;p&gt;Tout d'abord, je renseigne mon &lt;strong&gt;système de tests&lt;/strong&gt; avec mes nouvelles &lt;strong&gt;informations&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3_input_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;div3_reference_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3_params:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div3_input_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div3_reference_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DIV3\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et j'&lt;strong&gt;ajoute&lt;/strong&gt; le &lt;strong&gt;test&lt;/strong&gt; à la liste :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;test_suite:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;id_params&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div2_params&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_params&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui me permet de &lt;strong&gt;mettre au point&lt;/strong&gt; le code et le &lt;strong&gt;vérifier&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div3:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie: valeur divisée par 3, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; J&amp;#39;utilise les registres B et C, je les préserve&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le temps de l&amp;#39;opération&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le registre C contient le diviseur&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le compteur B est préparé pour retenir&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Le nombre de soustractions effectuées&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;cp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; A et C sont comparés&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div3_end&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Si A était plus petit que C, alors une retenue a eu lieu&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; le calcul est terminé&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Attention, ici C signifie Carry (retenue)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; C est soustrait de A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; B est augmenté de 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;div3_loop&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; La boucle est relancée&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div3_end:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Le résultat de la division est dans B, il est placé dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; À noter que A contenait le reste de la division.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; Cela pourra être intéressant pour plus tard.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Les registres B et C sont restaurés&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; Et la fonction est terminée&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Les instructions déjà utilisées dans les articles précédents ne sont pas répétées ici, les nouvelles sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cp&lt;/code&gt;: permet de &lt;strong&gt;comparer&lt;/strong&gt; le registre &lt;code&gt;A&lt;/code&gt; (qui est implicite et donc non noté) et le registre indiqué (ici, &lt;code&gt;C&lt;/code&gt;). La comparaison se fait par soustraction de &lt;code&gt;A&lt;/code&gt; et du registre, mais le résultat n'est pas retenu, seuls les drapeaux de résultat de l'opération le sont. Ainsi, en cas d'égalité par exemple, le drapeau &lt;code&gt;Z&lt;/code&gt; sera à 1 (Zéro, car la soustraction de deux nombres égaux donne zéro). Ici, on cherche s'il y a eu une retenue, ce qui indique que le nombre dans le registre spécifié était plus grand que le nombre dans &lt;code&gt;A&lt;/code&gt;, et donc le résultat de la soustraction était négatif.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub&lt;/code&gt;: effectue une soustraction simple. On avait précédemment vu &lt;code&gt;sbc&lt;/code&gt;, qui faisait une soustraction en tenant compte de la retenue du calcul précédent. &lt;code&gt;sub&lt;/code&gt; n'en tient pas compte et soustrait simplement le registre mentionné du registre &lt;code&gt;A&lt;/code&gt;, qui est implicite.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Résultat&lt;/h4&gt;
&lt;p&gt;Voici donc une &lt;strong&gt;première implémentation&lt;/strong&gt; de &lt;strong&gt;division par 3&lt;/strong&gt;, qui peut être &lt;strong&gt;généralisée&lt;/strong&gt; à une division par &lt;strong&gt;n'importe quel nombre&lt;/strong&gt; (inférieur à 255)&lt;/p&gt;
&lt;p&gt;Pour référence futur, le &lt;strong&gt;code&lt;/strong&gt; de la fonction nécessite &lt;strong&gt;15 octets&lt;/strong&gt; de langage machine. &lt;strong&gt;L'exécution&lt;/strong&gt; de la fonction nécessite $15 + 8 * q$ cycles processeur, où $q$ est le quotient, résultat de la division. Au pire, pour $\frac{255}{3}$, la fonction prend donc &lt;strong&gt;695&lt;/strong&gt; cycles. Ce qui n'est pas négligeable.&lt;/p&gt;
&lt;p&gt;Nous verrons plus tard si l'on peut faire mieux.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Affichage des résultats de tests dans MAME avec la division par 3" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201803/VG5000-TestFramework-2.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Calculs"></category></entry><entry><title>VG5000µ, SetPoint en ASM, vérifier les résultats</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-les-resultats.html" rel="alternate"></link><published>2018-02-21T00:00:00+01:00</published><updated>2018-02-21T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-02-21:/vg5000m-setpoint-en-asm-verifier-les-resultats.html</id><summary type="html">&lt;p&gt;Après avoir &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-la-pile.html"&gt;mis en place&lt;/a&gt; une vérification (légère) de l'&lt;strong&gt;intégrité de la pile&lt;/strong&gt;, je passe à la &lt;strong&gt;vérification&lt;/strong&gt; de la &lt;strong&gt;validité&lt;/strong&gt; de l'appel d'une &lt;strong&gt;fonction&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le fonctionnement du test est assez simple : je prends une &lt;strong&gt;suite de nombres&lt;/strong&gt;, j'appelle une fonction avec en paramètre chacun de ces nombres, je vérifie que le &lt;strong&gt;résultat&lt;/strong&gt; est &lt;strong&gt;conforme&lt;/strong&gt; à ce que j'attendais.&lt;/p&gt;
&lt;p&gt;Par exemple, si je veux tester une fonction &lt;strong&gt;diviser par 2&lt;/strong&gt; (division entière), je peux utiliser la suite de nombre &lt;code&gt;0, 10, 32, 255&lt;/code&gt; et comparer les résultats respectifs avec &lt;code&gt;0, 5, 16, 127&lt;/code&gt; (255 étant impair, le résultat de la division entière est 127, avec un reste égal à 1).&lt;/p&gt;
&lt;p&gt;Encore plus simple qu'une division par 2, il y a la &lt;strong&gt;fonction identité&lt;/strong&gt; : celle qui renvoie le paramètre sans le toucher. Tester cette fonction permet de se concentrer sur le développement du test.&lt;/p&gt;
&lt;p&gt;La fonction en elle-même est &lt;strong&gt;très …&lt;/strong&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Après avoir &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-la-pile.html"&gt;mis en place&lt;/a&gt; une vérification (légère) de l'&lt;strong&gt;intégrité de la pile&lt;/strong&gt;, je passe à la &lt;strong&gt;vérification&lt;/strong&gt; de la &lt;strong&gt;validité&lt;/strong&gt; de l'appel d'une &lt;strong&gt;fonction&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le fonctionnement du test est assez simple : je prends une &lt;strong&gt;suite de nombres&lt;/strong&gt;, j'appelle une fonction avec en paramètre chacun de ces nombres, je vérifie que le &lt;strong&gt;résultat&lt;/strong&gt; est &lt;strong&gt;conforme&lt;/strong&gt; à ce que j'attendais.&lt;/p&gt;
&lt;p&gt;Par exemple, si je veux tester une fonction &lt;strong&gt;diviser par 2&lt;/strong&gt; (division entière), je peux utiliser la suite de nombre &lt;code&gt;0, 10, 32, 255&lt;/code&gt; et comparer les résultats respectifs avec &lt;code&gt;0, 5, 16, 127&lt;/code&gt; (255 étant impair, le résultat de la division entière est 127, avec un reste égal à 1).&lt;/p&gt;
&lt;p&gt;Encore plus simple qu'une division par 2, il y a la &lt;strong&gt;fonction identité&lt;/strong&gt; : celle qui renvoie le paramètre sans le toucher. Tester cette fonction permet de se concentrer sur le développement du test.&lt;/p&gt;
&lt;p&gt;La fonction en elle-même est &lt;strong&gt;très simple&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;identity:&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie : registre A, inchangé&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Retour immédiat, on ne touche à rien&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;La boucle de test&lt;/h4&gt;
&lt;p&gt;La boucle de test initialise deux &lt;strong&gt;pointeurs&lt;/strong&gt; de données qui vont être augmentés en parallèle. La donnée source sera envoyée à la fonction, via le registre &lt;code&gt;A&lt;/code&gt;, puis le résultat, mis dans le registre &lt;code&gt;A&lt;/code&gt; aussi, sera &lt;strong&gt;comparé&lt;/strong&gt; à la &lt;strong&gt;valeur attendue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il nous faut donc en premier lieu la liste de ces valeurs :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;identity_input_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;identity_reference_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La boucle en elle-même ressemble à cela :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Fonction de test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;test:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;identity_reference_data&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; HL pointe sur les résultats de références&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;identity_input_data&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; DE pointe sur les données en entrées&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; Effacement du drapeau de retenue (voir article précédent)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Par soustraction des deux valeurs, on obtient le nombre de valeurs&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="c1"&gt;; de la série.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; BC contient le nombre de valeurs à tester&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;identity_reference_data&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; HL est pointe à nouveau sur le résultat de référence&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;test_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Chargement dans l&amp;#39;accumulateur de la valeur pointée par DE&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;identity&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Appel de la fonction&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="c1"&gt;; Au retour de la fonction, A contient le résultat de la fonction&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;cpi&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Compare A avec (HL), incrémente HL et décrémente BC&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Si BC passe à 0, le bit d&amp;#39;overflow (V) est mis à 0 ; 1 sinon&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Si A et (HL) sont identique, le flag Zero est mis à 1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_failed&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Si A et (HL) étaient différent, saute à test_failed&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Sinon, incrémente DE manuellement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_loop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; S&amp;#39;il reste des valeurs (BC &amp;gt; 0), on boucle&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;; DE et HL pointant à présent sur la paire de valeurs suivantes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_pass_msg&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Arrivée ici, toutes les paires de valeurs ont été&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="c1"&gt;; vérifiée avec succès. HL pointe donc sur le message&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="c1"&gt;; de succès.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;print_test_result_msg&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Et on saute à l&amp;#39;affichage.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;test_failed:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_fail_msg&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Arrivée ici, une comparaison a échouée, HL pointe&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="c1"&gt;; donc sur le message d&amp;#39;échec.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;print_test_result_msg:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; On affiche le message contenu dans HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="c1"&gt;; Le test est fini !&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;test_pass_msg:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Pass!\r\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;test_fail_msg:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Fail!\r\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Les instructions déjà utilisées dans l'article précédent ne sont pas répétées ici, les nouvelles sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;defb&lt;/code&gt; : qui est une &lt;strong&gt;directive&lt;/strong&gt; pour l'assembleur, indiquant de réserver de la place mémoire et de l'initialiser avec les octets qui suivent,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cpi&lt;/code&gt; : instruction de &lt;strong&gt;comparaison&lt;/strong&gt; qui effectue plusieurs actions d'un coup, comme indiqué dans le commentaire ci-dessus. Cela contraint l'utilisation des registres &lt;code&gt;HL&lt;/code&gt;, &lt;code&gt;BC&lt;/code&gt; et &lt;code&gt;A&lt;/code&gt;, qui sont spécialisés ainsi (&lt;code&gt;HL&lt;/code&gt; pour un pointeur de mémoire, &lt;code&gt;BC&lt;/code&gt; comme compteur et &lt;code&gt;A&lt;/code&gt; pour l'accumulateur).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inc&lt;/code&gt; : &lt;strong&gt;incrémente&lt;/strong&gt; la valeur du registre en paramètre, c'est-à-dire lui ajoute &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jp&lt;/code&gt; : &lt;strong&gt;saut&lt;/strong&gt; (&lt;strong&gt;jump&lt;/strong&gt;) au label indiqué. La différence avec l'utilisation de &lt;code&gt;jr&lt;/code&gt; est dans l'encodage de l'adresse de destination. Sans entrer dans le détail, &lt;code&gt;jr&lt;/code&gt; est plus condensé que &lt;code&gt;jp&lt;/code&gt;, car il n'encode pas l'adresse complète mais seulement un déplacement &lt;strong&gt;court&lt;/strong&gt;. Cependant, il n'est pas possible d'utiliser le drapeau de dépassement de capacité (&lt;code&gt;V&lt;/code&gt;) n'est pas utilisable avec &lt;code&gt;jr&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Et la division par 2 ?&lt;/h4&gt;
&lt;p&gt;À présent, il devient facile de &lt;strong&gt;tester&lt;/strong&gt; différentes fonctions. Il suffit de la &lt;strong&gt;fonction&lt;/strong&gt; elle-même, de la paire de liste de valeurs, et de remplacer l'appel de le fonction dans le test.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;div2:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;; Entrée: registre A, Sortie : valeur divisée par 2, dans A&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; Effacement du drapeau de retenue&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;rra&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;; Rotation du registre A vers la droite, en passant par la retenue&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div2_input_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;div2_reference_data:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defb&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et par exemple, si vous aviez, par étourderie comme moi, utilisé &lt;code&gt;rrca&lt;/code&gt; plutôt que &lt;code&gt;rra&lt;/code&gt;, le test échoue sur la division par 255.&lt;/p&gt;
&lt;h4&gt;Généralisation&lt;/h4&gt;
&lt;p&gt;Mais &lt;strong&gt;changer&lt;/strong&gt; les &lt;strong&gt;pointeurs&lt;/strong&gt; à &lt;strong&gt;chaque test&lt;/strong&gt; de fonction, ça n'est &lt;strong&gt;pas pratique&lt;/strong&gt;. C'est la grande différence entre des tests automatisés, qui peuvent rester à demeure et que l'on peut lancer régulièrement pour s'assurer que l'on construit un programme sur des fondations solides, et le test manuel, de temps en temps, pour s'assurer du fonctionnement en un point donné, et que l'on doit remettre en place manuellement à chaque fois.&lt;/p&gt;
&lt;p&gt;Bref, il me faut &lt;strong&gt;généraliser&lt;/strong&gt; ça avec, par exemple, la boucle de test qui prendrait en entrée les &lt;strong&gt;pointeurs nécessaires&lt;/strong&gt;. Et pourquoi pas, même, un nom explicatif de la fonction testée sur le moment.&lt;/p&gt;
&lt;p&gt;Ce que je voudrais, c'est quelque chose comme ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;test_suite:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;id_params&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;div2_params&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;id_params:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;identity_input_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;identity_reference_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDENTITY\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;div2_params:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div2_input_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defw&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;div2_reference_data&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DIV2\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il faut pour cela adapter un peut la routine &lt;code&gt;test&lt;/code&gt; pour aller piocher les valeurs depuis &lt;code&gt;HL&lt;/code&gt;, qui devient le paramètre d'entrée.&lt;/p&gt;
&lt;p&gt;Tout d'abord, la préparation des paramètres du test va mettre sur la pile les paramètres indiqués.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : il y a de multiples choix pour passer les paramètres des tests à la fonction. Mais aussi beaucoup de contraintes sur les instructions disponibles. Passer par la pile grâce à une fonction d'aide est assez simple à implémenter et lisible. Mais loin d'être le plus rapide.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;prepare_test:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; B sert de compteur, on va mettre les trois premières adresses sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;prepare_test_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de la première partie de l&amp;#39;adresse&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de la seconde partie de l&amp;#39;adresse&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; DE contient l&amp;#39;adresse, qui est poussée sur la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;djnz&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;prepare_test_loop&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; DJNZ décrémente B et, si B n&amp;#39;est pas égal à zéro, retourne au label indiqué&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; C&amp;#39;est la manière canonique d&amp;#39;effectuer des boucles&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; La dernière adresse est poussée directement, car elle pointe sur la chaîne de caractères,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; sans indirection.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jp&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;; ici, on devrait faire un CALL à la routine de test. Mais ce CALL serait immédiatement&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; suivi d&amp;#39;un RET. Dans ce cas-ci, on peut remplacer le CALL par un JP.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Si vous avez bien compris ce que font CALL, RET et JP, alors vous devriez comprendre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; pourquoi.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À présent, à l'appel de la routine test, il y a sur la pile, dans l'autre du plus « &lt;strong&gt;haut&lt;/strong&gt; » vers le plus « &lt;strong&gt;bas&lt;/strong&gt; » : l'identifiant sous forme de chaîne de caractères, l'adresse de la fonction à appeler, le pointeur de données de références, le pointeur de données en entrée.&lt;/p&gt;
&lt;p&gt;Il s'agit de récupérer tout cela.&lt;/p&gt;
&lt;p&gt;Voici le début de la routine modifiée, le reste ne change pas :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;test_sep_msg:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: \0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Une chaîne de caractère, voir plus loin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;test:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; La première opération consiste à afficher l&amp;#39;identifiant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;test_sep_msg&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Suivi de la nouvelle chaîne de caractère, pour afficher les deux points&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; La valeur suivante récupérée est l&amp;#39;adresse d&amp;#39;appel de la fonction&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Les appels indirects sur un Z80 ne sont pas naturels, il n&amp;#39;existe pas de CALL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; à une adresse non préalablement fixée.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;call_func&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Du coup, on profite du fait d&amp;#39;être en RAM pour modifier le code à la volée&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; en modifiant directement l&amp;#39;adresse du CALL à la fonction.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Cela ne serait pas possible avec un programme en ROM par exemple, mais il&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; existe plusieurs autres possibilités (utilisation de vecteurs et&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; modification manuelle de la pile par exemple)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Ce genre de manipulation vient avec des contraintes, mais qui dans notre cas&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; sont tout à fait acceptables.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de l&amp;#39;adresse des données de référence&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de l&amp;#39;adresse des données en entrée&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Sauvegarde temporaire de HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Le calcul du nombre de données, comment avant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de la sauvegarde temporaire de HL&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;test_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;call_func:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Ici, le CALL à l&amp;#39;adresse $0000 sera modifié dynamiquement par&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; la manipulation décrite ci-dessus. Lors de l&amp;#39;exécution de cette instruction,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; c&amp;#39;est donc bien la fonction spécifiée qui sera appelée.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Résultats&lt;/h4&gt;
&lt;p&gt;En situation réelle, il est très peu probable que j'utilise des fonctions &lt;strong&gt;identité&lt;/strong&gt; ou &lt;strong&gt;division par 2&lt;/strong&gt;. Les calculs seront faits sur place. Cependant, tester ces fonctions m'ont permis de développer mon petit framework de tests, assez minimaliste, et cela va m'être bien utile pour la suite, pour attaquer la division.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Affichage des résultats de tests dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201802/VG5000-TestFramework.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>VG5000µ, SetPoint en ASM, vérifier la pile</title><link href="https://www.triceraprog.fr/vg5000m-setpoint-en-asm-verifier-la-pile.html" rel="alternate"></link><published>2018-02-18T00:00:00+01:00</published><updated>2018-02-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-02-18:/vg5000m-setpoint-en-asm-verifier-la-pile.html</id><summary type="html">&lt;p&gt;Il y a maintenant pas mal de temps, j'avais implémenté, en &lt;strong&gt;BASIC&lt;/strong&gt;, une routine pour &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-basic-limplementation.html"&gt;afficher un point&lt;/a&gt; à l'écran. Puis de là, une routine pour tracer &lt;a href="https://www.triceraprog.fr/vg5000m-tracer-une-ligne-en-basic.html"&gt;&lt;strong&gt;une ligne&lt;/strong&gt;&lt;/a&gt;, puis &lt;a href="https://www.triceraprog.fr/trace-dun-cercle-en-basic-sur-vg5000m.html"&gt;&lt;strong&gt;un cercle&lt;/strong&gt;&lt;/a&gt;. Le constat était que &lt;strong&gt;c'était très lent&lt;/strong&gt;. Le &lt;strong&gt;BASIC&lt;/strong&gt; interprété est déjà plutôt lent de manière générale, et celui du VG5000µ n'est pas particulièrement rapide.&lt;/p&gt;
&lt;p&gt;Il y a plusieurs raisons à cela, et ce sera peut-être le contenu d'articles futurs.&lt;/p&gt;
&lt;p&gt;Mais en attendant, et après tous les efforts pour se confectionner un environnement de travail pour développer en assembleur, je repars sur l'implémentation du tracé d'un &lt;strong&gt;point à l'écran&lt;/strong&gt;, et cette fois-ci, &lt;strong&gt;en assembleur&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'avantage d'un programme écrit dans un langage de « &lt;strong&gt;haut niveau&lt;/strong&gt; », comme le &lt;strong&gt;BASIC&lt;/strong&gt;, est de simplifier bien des choses. Faire une division d'une variable &lt;code&gt;A&lt;/code&gt; par 3 par exemple, peut s'écrire &lt;code&gt;B = A/3&lt;/code&gt;. C'est simple, concis, lisible.&lt;/p&gt;
&lt;p&gt;Traduire cela en assembleur n'est pas …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Il y a maintenant pas mal de temps, j'avais implémenté, en &lt;strong&gt;BASIC&lt;/strong&gt;, une routine pour &lt;a href="https://www.triceraprog.fr/vg5000m-setpoint-en-basic-limplementation.html"&gt;afficher un point&lt;/a&gt; à l'écran. Puis de là, une routine pour tracer &lt;a href="https://www.triceraprog.fr/vg5000m-tracer-une-ligne-en-basic.html"&gt;&lt;strong&gt;une ligne&lt;/strong&gt;&lt;/a&gt;, puis &lt;a href="https://www.triceraprog.fr/trace-dun-cercle-en-basic-sur-vg5000m.html"&gt;&lt;strong&gt;un cercle&lt;/strong&gt;&lt;/a&gt;. Le constat était que &lt;strong&gt;c'était très lent&lt;/strong&gt;. Le &lt;strong&gt;BASIC&lt;/strong&gt; interprété est déjà plutôt lent de manière générale, et celui du VG5000µ n'est pas particulièrement rapide.&lt;/p&gt;
&lt;p&gt;Il y a plusieurs raisons à cela, et ce sera peut-être le contenu d'articles futurs.&lt;/p&gt;
&lt;p&gt;Mais en attendant, et après tous les efforts pour se confectionner un environnement de travail pour développer en assembleur, je repars sur l'implémentation du tracé d'un &lt;strong&gt;point à l'écran&lt;/strong&gt;, et cette fois-ci, &lt;strong&gt;en assembleur&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'avantage d'un programme écrit dans un langage de « &lt;strong&gt;haut niveau&lt;/strong&gt; », comme le &lt;strong&gt;BASIC&lt;/strong&gt;, est de simplifier bien des choses. Faire une division d'une variable &lt;code&gt;A&lt;/code&gt; par 3 par exemple, peut s'écrire &lt;code&gt;B = A/3&lt;/code&gt;. C'est simple, concis, lisible.&lt;/p&gt;
&lt;p&gt;Traduire cela en assembleur n'est pas toujours simple. &lt;strong&gt;Diviser&lt;/strong&gt; par un nombre quelconque n'est pas direct car le processeur &lt;strong&gt;Z80&lt;/strong&gt; n'a &lt;strong&gt;pas&lt;/strong&gt; d'instruction &lt;strong&gt;de division&lt;/strong&gt;. Le processeur possède des instructions pour additionner et soustraire, mais pas pour multiplier, ni de diviser.&lt;/p&gt;
&lt;p&gt;Diviser par des nombres en particuliers est parfois simple, comme &lt;strong&gt;diviser par 2&lt;/strong&gt;, qui consiste à décaler tous les bits d'un nombre binaire « vers la droite », tout comme &lt;strong&gt;diviser par 10&lt;/strong&gt; dans notre arithmétique courante consiste à décaler tous les chiffres vers la droite (ou supprimer l'unité, si vous préférez).&lt;/p&gt;
&lt;p&gt;Pour &lt;code&gt;30&lt;/code&gt; par exemple, en décimal, une vision par &lt;code&gt;10&lt;/code&gt; donne &lt;code&gt;3&lt;/code&gt;. En binaire, le même nombre s'écrit &lt;code&gt;00011110&lt;/code&gt; (sur 8 bits) et sa division par &lt;code&gt;2&lt;/code&gt; donne &lt;code&gt;00001111&lt;/code&gt;, c'est-à-dire &lt;code&gt;15&lt;/code&gt; en décimal. Diviser (ou multiplier) par des multiples de la base dans laquelle on représente les nombres est simple.&lt;/p&gt;
&lt;p&gt;Cependant, dans le calcul du pixel à afficher, j'avais une division par &lt;code&gt;3&lt;/code&gt;. Et là... c'est plus &lt;strong&gt;compliqué&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La première étape, puisque je pars de zéro est d'implémenter une division. Puisque le calcul n'a besoin que de diviser par &lt;code&gt;2&lt;/code&gt; et par &lt;code&gt;3&lt;/code&gt;, et que la division par &lt;code&gt;2&lt;/code&gt; est simple, je vais me contenter d'une division par &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Mais &lt;strong&gt;STOP&lt;/strong&gt;. Si vous suivez ce blog, vous avez peut-être vu que j'aime essayer de transposer des techniques modernes sur d'anciennes machines. C'est de la rétro-programmation anachronique, mais qui peut convenir au fait que, de toute façon, programmer ce genre de machines depuis un ordinateur actuel est anachronique.&lt;/p&gt;
&lt;p&gt;Une &lt;strong&gt;technique moderne&lt;/strong&gt; de développement (qui a ses détracteurs) est de guider sa programmation à travers des &lt;strong&gt;tests&lt;/strong&gt; qui peuvent, à chaque instant, indiquer si une erreur apparaît. La méthode est globalement de : 1/ écrire un test... qui échoue 2/ écrire le minimum pour faire passer ce test 3/ améliorer (sans ajouter de nouvelle fonctionnalité).&lt;/p&gt;
&lt;p&gt;Le point 3/ en particulier, permet de tester des choses en étant certain que ce que l'on a programmé ne « casse » pas. Suite à une optimisation un peu trop cavalière par exemple. Je ne suis pas un spécialiste de l'écriture de programmes en assembleur Z80, et un outil qui me permet de vérifier que mon changement ne casse pas tout m'intéresse.&lt;/p&gt;
&lt;p&gt;Puisque je vais &lt;strong&gt;implémenter une fonction&lt;/strong&gt;, mon environnement de test prendra en entrée une &lt;strong&gt;suite de nombres&lt;/strong&gt;, y &lt;strong&gt;appliquera&lt;/strong&gt; la &lt;strong&gt;fonction&lt;/strong&gt; puis, testera que &lt;strong&gt;les résultats&lt;/strong&gt; sont ceux que j'attends. J'affiche ensuite le résultat de la comparaison.&lt;/p&gt;
&lt;p&gt;Techniquement, un tel système de tests devrait lui-même être testé... mais à si bas niveau, c'est aller un peu trop loin pour ce que je veux faire.&lt;/p&gt;
&lt;h4&gt;Le premier test&lt;/h4&gt;
&lt;p&gt;La première chose dont je veux m'assurer, c'est que &lt;strong&gt;la pile&lt;/strong&gt; à la sortie de mon traitement soit dans le &lt;strong&gt;même état&lt;/strong&gt; qu'au &lt;strong&gt;début&lt;/strong&gt;. En effet, si ce n'est pas le cas, il va se passer des choses probablement à classer dans le domaine du « mal ». Dans le meilleur des cas une erreur bizarre, dans le pire (et souvent), un &lt;em&gt;reboot&lt;/em&gt; de la machine.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Aparté&lt;/em&gt;: je crois n'avoir jamais parlé de &lt;strong&gt;la pile&lt;/strong&gt; dans un article précédent. Très rapidement, c'est un endroit en mémoire où l'on peut stocker des informations sous forme de &lt;strong&gt;pile&lt;/strong&gt; (imaginez une pile d'assiettes). La &lt;strong&gt;dernière&lt;/strong&gt; donnée &lt;strong&gt;mise&lt;/strong&gt; sur le pile est aussi la &lt;strong&gt;première&lt;/strong&gt; que l'on &lt;strong&gt;lira&lt;/strong&gt; par la suite. Cette pile est entre autre la moyen lors de l'appelle d'une routine d'en revenir. À l'appel, l'adresse du code appelant est mis sur la pile. Pour retrouver cette adresse, il faut donc que l'état de la pile soit le même en entrée et en sortie de fonction.&lt;/p&gt;
&lt;p&gt;Voilà la première partie de la vérification de l'état de la pile.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Il n&amp;#39;est pas possible sur Z80 de prendre le pointeur de pile pour le mettre dans un registre&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; l&amp;#39;astuce est donc d&amp;#39;ajouter à 0 la valeur du pointeur de pile, en deux étapes.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Et je pousse la valeur du pointeur de pile dans la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il y a à présent en haut de la pile une valeur arbitraire suivi de l'adresse de la pile en début de fonction.&lt;/p&gt;
&lt;p&gt;Voici ensuite la seconde partie de la vérification de l'état de la pile. C'est un peu plus long car il y a la vérification ainsi que l'affichage du résultat.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Récupération de la valeur depuis la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Reset de la retenue&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; Soustraction de cette valeur avec le pointeur de pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;print_stk_fail&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Si le résultat n&amp;#39;est pas zéro, c&amp;#39;est qu&amp;#39;on n&amp;#39;a pas trouvé la bonne valeur dans la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Dans ce cas, saut à print_stk_fail&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Si tout ce passe bien, c&amp;#39;est à dire que la pile n&amp;#39;a pas été corrompue et qu&amp;#39;elle&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; est au même « niveau » qu&amp;#39;au début, alors...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stack_ok&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; on charge dans HL le message de succès&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; et on l&amp;#39;affiche&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; [...]                     ; On verra plus tard ce qui est ici.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;print_stk_fail:&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;; On arrive ici en cas d&amp;#39;échec&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stack_fail&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; On charge dans HL le message d’échec&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;; et on l&amp;#39;affiche&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Mais on ne peut pas sortir comme ça de la fonction. Puisque la pile n&amp;#39;est pas dans&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; le même état qu&amp;#39;au début, l&amp;#39;instruction `RET` ne va pas trouver l&amp;#39;adresse ramenant&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; au programme appelant, et cela ne va rien amener de bon (un reboot très souvent)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;endless_loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;halt&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; Alors on arrête tout... ou presque. L&amp;#39;instruction HALT va arrêter le système jusqu&amp;#39;à&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; la prochaine interruption, qui est, sur VG5000µ, l&amp;#39;interruption d&amp;#39;affichage.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;endless_loop&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Puis à la fin de l&amp;#39;affichage, ou boucle à l&amp;#39;infinie.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;; Cela permet de voir le message d&amp;#39;erreur.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;stack_ok:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Stack Pass!\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;stack_fail:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Stack Fail!\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Les instructions utilisées&lt;/h4&gt;
&lt;p&gt;Lire de l'assembleur peut être un peu déroutant au premier abord. Les explications fonctionnelles sont disponibles en commentaire dans le code ci-dessous, voici à présent les instructions utilisées dans l'ordre de leur apparition :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ld&lt;/code&gt; : abréviation de &lt;strong&gt;load&lt;/strong&gt;, c'est-à-dire &lt;strong&gt;charge&lt;/strong&gt;. La valeur à droite de la virgule est &lt;strong&gt;chargée&lt;/strong&gt; dans le registre à gauche. Par exemple, après &lt;code&gt;ld hl,0&lt;/code&gt;, le registre &lt;code&gt;HL&lt;/code&gt; contiendra la valeur &lt;code&gt;0&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;add&lt;/code&gt; : la valeur de droite (ou le contenu du registre à droite) de la virgule est &lt;strong&gt;additionné&lt;/strong&gt; (&lt;strong&gt;add&lt;/strong&gt;) dans le registre à gauche. Arès &lt;code&gt;add hl,sp&lt;/code&gt;, le contenu de &lt;code&gt;HL&lt;/code&gt; sera augmenté de la valeur de &lt;code&gt;SP&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;push&lt;/code&gt; : &lt;strong&gt;pousse&lt;/strong&gt; la valeur contenu dans le registre sur la pile, après &lt;strong&gt;push hl&lt;/strong&gt;, le contenu de &lt;code&gt;HL&lt;/code&gt; est &lt;strong&gt;en haut&lt;/strong&gt; de la pile, &lt;code&gt;HL&lt;/code&gt; n'est pas modifié,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop&lt;/code&gt; : est le contraire de &lt;code&gt;push&lt;/code&gt;. La valeur &lt;strong&gt;en haut&lt;/strong&gt; de la pile est &lt;strong&gt;chargée&lt;/strong&gt; dans le registre en paramètre, puis la pile est positionné sur l'élément &lt;strong&gt;au-dessous&lt;/strong&gt;. Après &lt;strong&gt;pop hl&lt;/strong&gt;, &lt;code&gt;HL&lt;/code&gt; contient le contenu qui était &lt;strong&gt;en haut&lt;/strong&gt; de la pile,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;or&lt;/code&gt; : permet d'effectuer une opération &lt;strong&gt;ou&lt;/strong&gt;. Ici, cependant, cette instruction est utilisée uniquement pour mettre le &lt;strong&gt;drapeau&lt;/strong&gt; de retenue à zéro, à cause de l'instruction suivante,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbc&lt;/code&gt; : &lt;strong&gt;soustraction avec retenue&lt;/strong&gt;, la valeur du registre de droite est soustraite de la valeur du registre de gauche. Il n'est pas possible sur Z80 de faire une soustraction sans retenue entre deux registres 16 bits. De là vient la nécessité d'effacer la retenue, au cas où, avec le &lt;code&gt;or&lt;/code&gt; précédent. Le résultat est &lt;strong&gt;chargé&lt;/strong&gt; dans le registre de gauche.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jr&lt;/code&gt; : &lt;strong&gt;saut relatif&lt;/strong&gt;, un branchement, c'est-à-dire une modification d'ordre d'exécution, va être effectué au &lt;strong&gt;label&lt;/strong&gt; indiqué. Dans le code ci-dessus, &lt;code&gt;nz&lt;/code&gt; à gauche de la virgule indique que le saut sera conditionné par le résultat du calcul précédent si celui-ci n'était pas nul (&lt;code&gt;not zero&lt;/code&gt;). Après &lt;code&gt;jr nz,print_stk_fail&lt;/code&gt;, le processeur continuera son exécution à l'emplacement indiqué par &lt;code&gt;print_stk_fail&lt;/code&gt; si le résultat n'est pas &lt;code&gt;0&lt;/code&gt;. Dans le cas contraire, le branchement n'a pas lieu et l'exécution continue à l'instruction suivante,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;call&lt;/code&gt; : est un &lt;strong&gt;appel&lt;/strong&gt; de sous-routine. L'emplacement de l'instruction suivante est mise sur la pile (équivalent d'un &lt;strong&gt;push&lt;/strong&gt;) puis un branchement est fait au &lt;strong&gt;label&lt;/strong&gt; indiqué,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ret&lt;/code&gt; : est le pendant de &lt;strong&gt;call&lt;/strong&gt;, la valeur &lt;strong&gt;en haut&lt;/strong&gt; de la pile est prise pour prochaine instruction grâce à l'équivalent d'un &lt;strong&gt;pop&lt;/strong&gt;. L'exécution continue donc là d'où avait été appelée la routine,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;halt&lt;/code&gt; : &lt;strong&gt;arrête&lt;/strong&gt; l'exécution du processeur. Lorsqu'une interruption matérielle est reçue, le processeur se remet en route.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defm&lt;/code&gt; : ce n'est pas une instruction du processeur mais une directive pour l'assembleur. Une zone mémoire est réservée et initialisée avec la chaîne de caractères qui suit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Garder le contexte&lt;/h4&gt;
&lt;p&gt;Cette routine de vérification de la pile modifie quelques registres. Pour laisser les choses dans l'était où elles étaient lorsque ce code sera appelé, il est de bon ton de sauvegarder l'état des registres et de les restituer à la fin. Cela peut se faire par une série de &lt;code&gt;push&lt;/code&gt; et de &lt;code&gt;pop&lt;/code&gt;. Ce qui donne au final :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Vérification de pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;defc&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Sauve le contexte&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Enregistre la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Opérations futures...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Vérification de la pile&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;sbc&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;nz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;print_stk_fail&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Message en cas de succès&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stack_ok&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Restitution du contexte&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;af&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;print_stk_fail:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ld&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;stack_fail&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;print_str&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;loop:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;halt&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jr&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;loop&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;stack_ok:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Stack Pass!\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nl"&gt;stack_fail:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;defm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Stack Fail!\0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Résultat&lt;/h4&gt;
&lt;p&gt;Pour le moment, pas grand chose, tout se passe bien et un message est affiché indiquant que... la pile est ok.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Affichage du test de pile dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201802/VG5000-StackPass.jpeg"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Affichage"></category><category term="ASM"></category><category term="Z80"></category></entry><entry><title>Automatisation : utilisation de Sublime Text 3</title><link href="https://www.triceraprog.fr/automatisation-utilisation-de-sublime-text-3.html" rel="alternate"></link><published>2018-02-12T00:00:00+01:00</published><updated>2018-02-12T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-02-12:/automatisation-utilisation-de-sublime-text-3.html</id><summary type="html">&lt;p&gt;Dans les articles précédents sur l'&lt;strong&gt;automatisation&lt;/strong&gt; au niveau des outils de développement, j'avais vu comment &lt;strong&gt;injecter un programme&lt;/strong&gt; dans MAME en émulation &lt;strong&gt;VG5000µ&lt;/strong&gt; d'abord &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m.html"&gt;grâce au debuggeur&lt;/a&gt; manuellement, puis avec &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html"&gt;un script LUA&lt;/a&gt; grâce aux possibilité d'extensions de &lt;strong&gt;MAME&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ce n'est toujours &lt;strong&gt;pas suffisant&lt;/strong&gt; pour moi. Comme je l'ai déjà écrit dans ces autres articles, je ne veux pas faire ce qu'une automatisation peut faire bien &lt;strong&gt;plus facilement&lt;/strong&gt;, et &lt;strong&gt;sans se tromper&lt;/strong&gt;. Lancer l'assembleur en ligne de commande, puis lancer &lt;strong&gt;MAME&lt;/strong&gt; avec les bons paramètres, cela n'est pas bien compliqué avec un &lt;code&gt;shell&lt;/code&gt; moderne (comme &lt;code&gt;fish&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Un des &lt;strong&gt;principaux problèmes&lt;/strong&gt; que j'y vois, outre que ce sont des &lt;strong&gt;opérations manuelles&lt;/strong&gt;, c'est que ce sont des opérations &lt;strong&gt;non documentées&lt;/strong&gt;. Si je fais une pause dans un projet et que j'y reviens deux mois après (ça arrive bien souvent, surtout pour du hobby), il y a de bonnes chances que je …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dans les articles précédents sur l'&lt;strong&gt;automatisation&lt;/strong&gt; au niveau des outils de développement, j'avais vu comment &lt;strong&gt;injecter un programme&lt;/strong&gt; dans MAME en émulation &lt;strong&gt;VG5000µ&lt;/strong&gt; d'abord &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m.html"&gt;grâce au debuggeur&lt;/a&gt; manuellement, puis avec &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html"&gt;un script LUA&lt;/a&gt; grâce aux possibilité d'extensions de &lt;strong&gt;MAME&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ce n'est toujours &lt;strong&gt;pas suffisant&lt;/strong&gt; pour moi. Comme je l'ai déjà écrit dans ces autres articles, je ne veux pas faire ce qu'une automatisation peut faire bien &lt;strong&gt;plus facilement&lt;/strong&gt;, et &lt;strong&gt;sans se tromper&lt;/strong&gt;. Lancer l'assembleur en ligne de commande, puis lancer &lt;strong&gt;MAME&lt;/strong&gt; avec les bons paramètres, cela n'est pas bien compliqué avec un &lt;code&gt;shell&lt;/code&gt; moderne (comme &lt;code&gt;fish&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Un des &lt;strong&gt;principaux problèmes&lt;/strong&gt; que j'y vois, outre que ce sont des &lt;strong&gt;opérations manuelles&lt;/strong&gt;, c'est que ce sont des opérations &lt;strong&gt;non documentées&lt;/strong&gt;. Si je fais une pause dans un projet et que j'y reviens deux mois après (ça arrive bien souvent, surtout pour du hobby), il y a de bonnes chances que je ne me &lt;strong&gt;souvienne plus&lt;/strong&gt; des opérations exactes à faire. J'ai pu prendre des notes, laisser des instructions, écrire un article même. Mais quoi de mieux comme instructions que de laisser des &lt;strong&gt;outils qui fonctionneront&lt;/strong&gt; et seront une &lt;strong&gt;source de documentation&lt;/strong&gt; si besoin ?&lt;/p&gt;
&lt;p&gt;Un premier script assez simple serait de regrouper l'assemblage et le lancement dans un même script. Ou pourquoi pas dans un &lt;code&gt;Makefile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;J'ai choisi d'ajouter les outils à un environnement &lt;code&gt;Sublime Text 3&lt;/code&gt;, qui est l'un des deux éditeurs de texte que j'utilise le plus souvent.&lt;/p&gt;
&lt;h4&gt;De la couleur&lt;/h4&gt;
&lt;p&gt;Et puisque j'en étais à créer un petit environnement confortable pour mettre au point des &lt;strong&gt;programmes en assembleurs&lt;/strong&gt; pour &lt;code&gt;Z80&lt;/code&gt;, j'ai fait un petit détour par la &lt;strong&gt;colorisation syntaxique&lt;/strong&gt;. N'ayant pas trouvé de colorisation adéquat à de l'assembleur tel qu'attendu par &lt;code&gt;z80asm&lt;/code&gt;, j'ai écrit une &lt;strong&gt;description simpliste&lt;/strong&gt; que vous trouverez dans le package en fin d'article.&lt;/p&gt;
&lt;p&gt;Il ne gère pas tous les cas, et je pense l'améliorer en fonction des besoins.&lt;/p&gt;
&lt;p&gt;Au passage, &lt;code&gt;Sublime Text 3&lt;/code&gt; a un système de tests pour la colorisation syntaxique qui est extrêmement pratique pour mettre au point le fichier. Le fichier de test est disponible dans le paquetage au côté des autres, pour référence.&lt;/p&gt;
&lt;h4&gt;Un système de build&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Deuxième étape&lt;/strong&gt;, la plus importante, celle qui permet de &lt;strong&gt;construire un code objet&lt;/strong&gt; à partir d'un &lt;strong&gt;code source&lt;/strong&gt; en assembleur. La mise en place de la colorisation syntaxique n'a pas amené que des couleurs à l'affichage. Elle a aussi permis de déclarer l'existence d'un &lt;strong&gt;format spécifique&lt;/strong&gt;, que j'ai appelé &lt;strong&gt;z80asm&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Lorsque l'éditeur de texte ouvrira un fichier &lt;code&gt;.asm&lt;/code&gt;, il l'associera par défaut à ce format (sauf si vous avez d'autres associations pour &lt;code&gt;.asm&lt;/code&gt;, auquel cas cela sera un choix possible).&lt;/p&gt;
&lt;p&gt;Pour créer un nouveau système de &lt;code&gt;build&lt;/code&gt; avec Sublime Text 3, il suffit d'aller dans &lt;code&gt;Tools&lt;/code&gt; -&amp;gt; &lt;code&gt;Build System&lt;/code&gt; -&amp;gt; &lt;code&gt;New Build System&lt;/code&gt;. Un nouveau fichier de description, en &lt;code&gt;JSON&lt;/code&gt;, permettra d'indiquer à l'éditeur les actions qu'il devra effectuer lors de la construction du fichier.&lt;/p&gt;
&lt;p&gt;Pour une &lt;strong&gt;construction simple&lt;/strong&gt;, qui appel l'assembleur &lt;code&gt;z80asm&lt;/code&gt; se trouvant dans vos chemin de recherche d'exécutables, cela peut donner ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;selector&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;source.asm.z80&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;z80asm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;file_patterns&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.asm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;file_regex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^Error at file &amp;#39;([^&amp;#39;]+)&amp;#39; line (\\d+): ()(.+)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;selector&lt;/code&gt;: indique que ce type de construction est valable pour le type de fichier associé au format &lt;code&gt;source.asm.z80&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmd&lt;/code&gt;: indique la commande à exécuter. &lt;code&gt;$file&lt;/code&gt; indiquant le fichier actif au moment du lancement de la construction.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file_patterns&lt;/code&gt;: indique le type de fichier valable pour ce type de construction aussi, au cas où le format de &lt;code&gt;selector&lt;/code&gt; n'aurait pas été appliqué&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file_regex&lt;/code&gt;: est une expression régulière identifiant les erreurs de construction, et permettant à l'éditeur de texte d'indiquer ces erreurs directement dans le fichier édité.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avec ceci, un &lt;code&gt;Ctrl-B&lt;/code&gt; (sous Linux et Windows) transforme votre fichier &lt;code&gt;.asm&lt;/code&gt; en fichier du même nom &lt;code&gt;.bin&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Lancer MAME après le build&lt;/h4&gt;
&lt;p&gt;Je voulais aller &lt;strong&gt;un peu plus loin&lt;/strong&gt; et avoir la possibilité de lancer &lt;code&gt;MAME&lt;/code&gt; depuis &lt;code&gt;Sublime Text&lt;/code&gt; si l'assemblage était un succès. Pour cela, il m'a fallu écrire un script &lt;code&gt;python&lt;/code&gt; un peu plus complexe qui lance l'assemblage de la même manière que ce qui est indiqué au paragraphe précédent, et en cas de succès, lance &lt;code&gt;MAME&lt;/code&gt; avec les bons paramètres.&lt;/p&gt;
&lt;p&gt;Il aurait été aussi &lt;strong&gt;tout à fait possible&lt;/strong&gt;, et probablement &lt;strong&gt;plus simple&lt;/strong&gt;, d'appeler un fichier &lt;strong&gt;script shell&lt;/strong&gt; (ou batch). Mais j'avais depuis quelques temps envie de comprendre comment écrire un plugin de build pour &lt;code&gt;Sublime Text&lt;/code&gt;, j'ai donc fait un détour.&lt;/p&gt;
&lt;p&gt;Je ne rentrerai pas dans le détail du fonctionnement du &lt;strong&gt;plugin&lt;/strong&gt; de build que vous pourrez trouver dans le paquetage à la fin de l'article.&lt;/p&gt;
&lt;p&gt;Le système est améliorable. Pour le moment, l'adresse de démarrage du code objet est fixé par le script &lt;code&gt;vgboot.lua&lt;/code&gt;. Il faudra donc changer cette adresse dans le script à l'endroit de l'injection du code et au moment du &lt;code&gt;CALL&lt;/code&gt; si votre code objet est situé à une autre adresse mémoire.&lt;/p&gt;
&lt;p&gt;Dans le fichier &lt;code&gt;README.md&lt;/code&gt;, vous trouverez les instructions pour créer le système de build correspondant. Je le reprends ici pour l'expliquer :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;selector&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;source.asm.z80&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;z80asm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;file_patterns&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.asm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;file_regex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^Error at file &amp;#39;([^&amp;#39;]+)&amp;#39; line (\\d+): ()(.+)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;variants&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;target&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;z80_asm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;run&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;mame_path&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mame&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;script&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vgboot.lua&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Outre le début, qui est identique à la version du paragraphe précédent, une section &lt;code&gt;variants&lt;/code&gt; a fait son apparition. Cette section indique des &lt;strong&gt;versions alternatives&lt;/strong&gt; de construction. Le paramètre &lt;code&gt;target&lt;/code&gt; indique quel est le &lt;strong&gt;plugin&lt;/strong&gt; à invoquer. Les autres paramètres sont passés tel quel au plugin.&lt;/p&gt;
&lt;p&gt;Les variantes hérites aussi des paramètres principaux, mais mon &lt;strong&gt;plugin&lt;/strong&gt; se contente de les ignorer pour tout gérer seul.&lt;/p&gt;
&lt;p&gt;Pour sélectionner une &lt;strong&gt;variante&lt;/strong&gt; dans &lt;code&gt;Sublime Text 3&lt;/code&gt;, le raccourci est &lt;code&gt;Ctrl-Shift-B&lt;/code&gt; (sous Linux et Windows).&lt;/p&gt;
&lt;h4&gt;Le paquetage&lt;/h4&gt;
&lt;p&gt;Les sources du paquetages sont &lt;a href="https://github.com/Triceraprog/z80asm.sublime-package"&gt;disponibles sur Github&lt;/a&gt; mais aussi sous forme de paquetage &lt;code&gt;Sublime Text 3&lt;/code&gt; (qui est en fait un fichier zip) &lt;a href="https://www.triceraprog.fr/files/201802/z80asm.sublime-package"&gt;directement ici&lt;/a&gt; (à la version lors de la publication de l'article).&lt;/p&gt;
&lt;h4&gt;Le résultat&lt;/h4&gt;
&lt;p&gt;À présent, je peux &lt;strong&gt;écrire de l'assembleur&lt;/strong&gt; dans mon éditeur de texte et, par un seul &lt;strong&gt;raccourci&lt;/strong&gt;, lancer l'&lt;strong&gt;assemblage&lt;/strong&gt;, avoir un &lt;strong&gt;retour d'erreur&lt;/strong&gt; annoté directement dans le code source, et en cas de réussite, le &lt;strong&gt;programme&lt;/strong&gt; lancé directement &lt;strong&gt;dans l'émulateur&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On pourrait aller encore plus loin, avec le script &lt;code&gt;MAME&lt;/code&gt; qui ouvrirait un canal de communication afin d'injecter le code sans relancer l'émulateur... Mais je vais m'arrêter ici et revenir sur le sujet qui a entraîné tout cela.&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Émulation"></category><category term="Debug"></category><category term="Outils"></category></entry><entry><title>Scripter MAME pour explorer la machine</title><link href="https://www.triceraprog.fr/scripter-mame-pour-explorer-la-machine.html" rel="alternate"></link><published>2018-01-18T00:00:00+01:00</published><updated>2018-01-18T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-01-18:/scripter-mame-pour-explorer-la-machine.html</id><summary type="html">&lt;p&gt;Puisque je suis actuellement dans l'utilisation de &lt;a href="https://www.lua.org/"&gt;LUA&lt;/a&gt; pour scripter MAME, faisons un petit détour pour &lt;strong&gt;explorer&lt;/strong&gt; quelques &lt;strong&gt;possibilités&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;fonctions accessibles&lt;/strong&gt; aux scripts LUA sont assez nombreuses. Je n'en connais pas de &lt;strong&gt;documentation&lt;/strong&gt; complète si ce n'est dans les &lt;strong&gt;sources du programme&lt;/strong&gt; lui-même à cet endroit : &lt;code&gt;mame/src/frontend/mame/luaengine.cpp&lt;/code&gt;. Des groupes de &lt;strong&gt;commentaires&lt;/strong&gt; indiquent les fonctions et &lt;strong&gt;leur usage&lt;/strong&gt;. Reste à utiliser la &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m.html"&gt;console&lt;/a&gt; pour &lt;strong&gt;expérimenter&lt;/strong&gt; un peu la façon de les appeler.&lt;/p&gt;
&lt;p&gt;L'une des possibilités intéressantes est de pouvoir &lt;strong&gt;agir sur l'affichage&lt;/strong&gt; de l'émulateur. Cela peut être assez pratique pour suivre certaines valeurs en mémoire, pour afficher des informations sur le comportement de la machine, voire d'ajouter des fonctionnalités interactives à l'émulateur facilement.&lt;/p&gt;
&lt;h4&gt;Affichage à l'écran&lt;/h4&gt;
&lt;p&gt;La &lt;strong&gt;première chose&lt;/strong&gt; à faire pour afficher quelque chose à l'écran est de récupérer un objet permettant de le manipuler. Pour cela, en passant par l'objet &lt;code&gt;manager&lt;/code&gt;, on récupère …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Puisque je suis actuellement dans l'utilisation de &lt;a href="https://www.lua.org/"&gt;LUA&lt;/a&gt; pour scripter MAME, faisons un petit détour pour &lt;strong&gt;explorer&lt;/strong&gt; quelques &lt;strong&gt;possibilités&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;fonctions accessibles&lt;/strong&gt; aux scripts LUA sont assez nombreuses. Je n'en connais pas de &lt;strong&gt;documentation&lt;/strong&gt; complète si ce n'est dans les &lt;strong&gt;sources du programme&lt;/strong&gt; lui-même à cet endroit : &lt;code&gt;mame/src/frontend/mame/luaengine.cpp&lt;/code&gt;. Des groupes de &lt;strong&gt;commentaires&lt;/strong&gt; indiquent les fonctions et &lt;strong&gt;leur usage&lt;/strong&gt;. Reste à utiliser la &lt;a href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m.html"&gt;console&lt;/a&gt; pour &lt;strong&gt;expérimenter&lt;/strong&gt; un peu la façon de les appeler.&lt;/p&gt;
&lt;p&gt;L'une des possibilités intéressantes est de pouvoir &lt;strong&gt;agir sur l'affichage&lt;/strong&gt; de l'émulateur. Cela peut être assez pratique pour suivre certaines valeurs en mémoire, pour afficher des informations sur le comportement de la machine, voire d'ajouter des fonctionnalités interactives à l'émulateur facilement.&lt;/p&gt;
&lt;h4&gt;Affichage à l'écran&lt;/h4&gt;
&lt;p&gt;La &lt;strong&gt;première chose&lt;/strong&gt; à faire pour afficher quelque chose à l'écran est de récupérer un objet permettant de le manipuler. Pour cela, en passant par l'objet &lt;code&gt;manager&lt;/code&gt;, on récupère la machine, puis un écran qui dans notre cas se nomme &lt;code&gt;:screen&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Grâce à cet objet, il est ensuite possible d'&lt;strong&gt;afficher du texte&lt;/strong&gt;, de &lt;strong&gt;tracer des lignes&lt;/strong&gt; et des boites. C'est limité, mais déjà pas mal.&lt;/p&gt;
&lt;p&gt;Ce qui suit est un &lt;strong&gt;exemple&lt;/strong&gt; d'utilisation dans lequel je vais &lt;strong&gt;chercher&lt;/strong&gt; directement &lt;strong&gt;en mémoire&lt;/strong&gt; les &lt;strong&gt;coordonnées&lt;/strong&gt; X et Y &lt;strong&gt;du curseur&lt;/strong&gt; du VG5000µ, qui sont situées aux emplacement mémoire fixes &lt;code&gt;$4805&lt;/code&gt; et &lt;code&gt;$4806&lt;/code&gt;. Par un objet donnant accès à la mémoire et l'utilisation des fonctions &lt;code&gt;read_u8&lt;/code&gt; (comme &lt;strong&gt;lecture d'un entier non signé sur 8 bits&lt;/strong&gt;), je récupère les valeurs et je les affiche.&lt;/p&gt;
&lt;p&gt;Simple et efficace. Je peux à présent, si le script est dans un fichier nommé &lt;code&gt;vgdisplay.lua&lt;/code&gt;, lancer la commande suivant pour suivre les évolutions des coordonnées du curseur.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -nomax -window -autoboot_delay 0 -autoboot_script vgdisplay.lua&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Le script&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Script for MAME that launches the vg5k emulator&lt;/span&gt;
&lt;span class="c1"&gt;-- and continuously displays the position of the cursor&lt;/span&gt;

&lt;span class="c1"&gt;-- Get the only screen of the VG-5000µ&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:screen&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;-- Get access to the memory&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:maincpu&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spaces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;program&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;draw_hud&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cursor_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;read_u8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x4805&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cursor_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;read_u8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x4806&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;draw_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;X: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;cursor_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xffff0000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;draw_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;cursor_y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xffff0000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;emu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_frame_done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draw_hud&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Le résultat&lt;/h4&gt;
&lt;p&gt;&lt;img alt="Affichage en surimpression dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201801/MameAffichageCurseur-750.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Émulation"></category><category term="Debug"></category><category term="Automatisation"></category></entry><entry><title>Injecter un programme dans un émulateur VG5000µ, partie II</title><link href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html" rel="alternate"></link><published>2018-01-10T00:00:00+01:00</published><updated>2018-01-10T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-01-10:/injecter-un-programme-dans-un-emulateur-vg5000m-partie-ii.html</id><summary type="html">&lt;p&gt;La &lt;a href="({filename}/Machines/20180103-VG5000-MameAutomation.md)"&gt;fois dernière&lt;/a&gt; était consacrée au &lt;strong&gt;lancement&lt;/strong&gt; d'un programme sur &lt;strong&gt;VG5000µ&lt;/strong&gt; avec l'émulateur &lt;strong&gt;MAME&lt;/strong&gt; de manière à injecter un programme binaire directement en mémoire puis à l'appeler. Tout cela &lt;strong&gt;automatiquement&lt;/strong&gt;. Pour rappel, l'idée derrière cela est d'éviter les erreurs de manipulations qui arrivent de temps en temps.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;première option&lt;/strong&gt; utilisée dans l'article précédent était d'&lt;strong&gt;utiliser un script&lt;/strong&gt; pour le debuggeur d'une part, et la capacité de &lt;strong&gt;MAME&lt;/strong&gt; à &lt;strong&gt;entrer au clavier&lt;/strong&gt; de la machine émulée une suite de frappes de touches.&lt;/p&gt;
&lt;p&gt;Cette méthode fonctionne mais a ses limites : il faut régler le délai avant la frappe de touches de manière empirique, et le script est linéaire. Dans cet article, je vais utiliser une autre possibilité de &lt;strong&gt;MAME&lt;/strong&gt; pour résoudre ces deux écueils.&lt;/p&gt;
&lt;h4&gt;La console&lt;/h4&gt;
&lt;p&gt;Commençons par une première manipulation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -nomax -window -debug -debugger none -console&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Dans le &lt;strong&gt;shell&lt;/strong&gt; depuis lequel vous avez entré cette …&lt;/p&gt;</summary><content type="html">&lt;p&gt;La &lt;a href="({filename}/Machines/20180103-VG5000-MameAutomation.md)"&gt;fois dernière&lt;/a&gt; était consacrée au &lt;strong&gt;lancement&lt;/strong&gt; d'un programme sur &lt;strong&gt;VG5000µ&lt;/strong&gt; avec l'émulateur &lt;strong&gt;MAME&lt;/strong&gt; de manière à injecter un programme binaire directement en mémoire puis à l'appeler. Tout cela &lt;strong&gt;automatiquement&lt;/strong&gt;. Pour rappel, l'idée derrière cela est d'éviter les erreurs de manipulations qui arrivent de temps en temps.&lt;/p&gt;
&lt;p&gt;La &lt;strong&gt;première option&lt;/strong&gt; utilisée dans l'article précédent était d'&lt;strong&gt;utiliser un script&lt;/strong&gt; pour le debuggeur d'une part, et la capacité de &lt;strong&gt;MAME&lt;/strong&gt; à &lt;strong&gt;entrer au clavier&lt;/strong&gt; de la machine émulée une suite de frappes de touches.&lt;/p&gt;
&lt;p&gt;Cette méthode fonctionne mais a ses limites : il faut régler le délai avant la frappe de touches de manière empirique, et le script est linéaire. Dans cet article, je vais utiliser une autre possibilité de &lt;strong&gt;MAME&lt;/strong&gt; pour résoudre ces deux écueils.&lt;/p&gt;
&lt;h4&gt;La console&lt;/h4&gt;
&lt;p&gt;Commençons par une première manipulation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -nomax -window -debug -debugger none -console&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Dans le &lt;strong&gt;shell&lt;/strong&gt; depuis lequel vous avez entré cette commande s'affiche un bandeau et une invite &lt;code&gt;[MAME]&amp;gt;&lt;/code&gt;. Vous avez à présent accès à une &lt;strong&gt;console&lt;/strong&gt; qui comprend le &lt;a href="https://www.lua.org/"&gt;LUA&lt;/a&gt;. C'est bien entendu le paramètre &lt;code&gt;-console&lt;/code&gt; qui a permis cela.&lt;/p&gt;
&lt;p&gt;Le couple &lt;code&gt;-debug&lt;/code&gt; &lt;code&gt;-debugger none&lt;/code&gt; est plus surprenant. Il indique que le &lt;strong&gt;debuggeur&lt;/strong&gt; est &lt;strong&gt;activé&lt;/strong&gt;, mais &lt;strong&gt;sans interface graphique&lt;/strong&gt;. Le debuggeur est donc utilisable depuis la console, et c'est parfait. Au passage, vous remarquerez que, en l'absence d'interface graphique pour le debuggeur, l'émulateur ne s'est pas mis en pause.&lt;/p&gt;
&lt;p&gt;Depuis la console, vous pouvez essayer ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;m = manager:machine()
md = m:debugger()
print(md)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Vous devez voir quelque chose comme &lt;code&gt;sol.debugger_manager*: 0xf9de9a8&lt;/code&gt; qui indique que &lt;code&gt;md&lt;/code&gt; contient bien un debuggeur (l'adresse sera différente). Si vous obtenez &lt;code&gt;nil&lt;/code&gt;, c'est que le debuggeur n'est pas actif.&lt;/p&gt;
&lt;p&gt;L'object &lt;code&gt;md&lt;/code&gt; permet de s'adresser au debuggueur.&lt;/p&gt;
&lt;p&gt;Par exemple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et l'aide du debuggeur s'affiche. Nous &lt;strong&gt;communiquons&lt;/strong&gt; bien avec le &lt;strong&gt;debuggeur&lt;/strong&gt;. C'est pratique.&lt;/p&gt;
&lt;h4&gt;Script LUA&lt;/h4&gt;
&lt;p&gt;Mais si une console est pratique pour essayer des choses, ce n'est pas ce que je recherche au final. Ce que je recherche à faire est toujours automatiser le démarrage d'un programme pour sa mise au point.&lt;/p&gt;
&lt;p&gt;Et &lt;strong&gt;MAME&lt;/strong&gt; a la commande qu'il me faut : &lt;code&gt;-autoboot_script&lt;/code&gt;. Cette commande, suivie par un nom de fichier, va &lt;strong&gt;exécuter un script&lt;/strong&gt; écrit en &lt;strong&gt;LUA&lt;/strong&gt; qui aura accès au fonctionnement de l'émulateur.&lt;/p&gt;
&lt;p&gt;La commande pourra ressembler à quelque chose comme ça :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -nomax -window -debug -debugger none -autoboot_delay 0 -autoboot_script vgboot.lua&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-autoboot_delay 0&lt;/code&gt; indique que le script doit être lancé dès le démarrage de l'émulation de la machine. La première chose (ou presque) à faire dans le script si vous voulez contrôler la machine cible dès le début est alors un &lt;code&gt;emu.pause()&lt;/code&gt; que vous pourrez balancer avec un &lt;code&gt;emu.unpause()&lt;/code&gt; lorsque votre script sera prêt.&lt;/p&gt;
&lt;p&gt;Le script que j'utilise est trop long pour s'afficher sur cette page. Vous pouvez le &lt;a href="https://www.triceraprog.fr/files/201801/20180108-vgboot.lua"&gt;trouver ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Des choses intéressantes à savoir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;manager:machine()&lt;/code&gt; renvoie l'objet contrôlant machine émulée,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;manager:machine():debugger()&lt;/code&gt; renvoie l'objet de contrôle du debuggeur,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;manager:machine():debugger().consolelog&lt;/code&gt; est le log du debuggeur, pratique pour vérifier les retours de commandes,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;manager:machine().devices[":maincpu"]&lt;/code&gt; renvoie l'objet contrôlant le CPU principal de la machine (le Z80 pour le VG5000µ),&lt;/li&gt;
&lt;li&gt;&lt;code&gt;manager:machine().devices[":maincpu"]:debug()&lt;/code&gt; renvoie l'objet de commande du debuggeur sur ce CPU (qui offre des facilités sur les commandes du debuggeur pour ce processeur en particulier).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sur l'objet renvoyé par &lt;code&gt;debug()&lt;/code&gt; sur le CPU, par exemple, on peut appeler &lt;code&gt;bpset()&lt;/code&gt; pour placer un &lt;strong&gt;point d'arrêt&lt;/strong&gt;. Sur l'objet renvoyé par &lt;code&gt;debugger()&lt;/code&gt;, on peut envoyer tous les &lt;strong&gt;commandes&lt;/strong&gt; que l'on entrerait dans l'interface graphique avec &lt;code&gt;command()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ainsi &lt;code&gt;...:debugger():command("go")&lt;/code&gt; a le même effet, sur cette machine, que &lt;code&gt;...:debug():go()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L'objet &lt;code&gt;emu&lt;/code&gt; qui permet de faire &lt;code&gt;pause()&lt;/code&gt; et &lt;code&gt;unpause()&lt;/code&gt; permet aussi de &lt;strong&gt;simuler&lt;/strong&gt; les appuis sur les &lt;strong&gt;touches&lt;/strong&gt; du &lt;strong&gt;clavier&lt;/strong&gt; émulé. Par exemple &lt;code&gt;emu.keypost('CALL &amp;amp;"7000"\n')&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;C'est plus complexe !&lt;/h4&gt;
&lt;p&gt;Oui, cette méthode est plus complexe, plus longue à écrire. Elle permet aussi un meilleur contrôle et des choses que ne permettent pas un script de debuggeur simple. À vous de choisir !&lt;/p&gt;
&lt;p&gt;&lt;img alt="La console LUA dans MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201801/MameConsole.png"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Émulation"></category><category term="Debug"></category><category term="Automatisation"></category></entry><entry><title>Injecter un programme dans un émulateur VG5000µ</title><link href="https://www.triceraprog.fr/injecter-un-programme-dans-un-emulateur-vg5000m.html" rel="alternate"></link><published>2018-01-03T00:00:00+01:00</published><updated>2018-01-03T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-01-03:/injecter-un-programme-dans-un-emulateur-vg5000m.html</id><summary type="html">&lt;p&gt;Reprenons sur la &lt;strong&gt;programmation en assembleur&lt;/strong&gt; sur &lt;strong&gt;VG5000µ&lt;/strong&gt; depuis un ordinateur actuel. Car s'il est possible et tout à fait légitime, par hobby, de programmer directement sur la machine, à l'ancienne, pour &lt;strong&gt;« retro programmer »&lt;/strong&gt; comme il y a du « retro gaming » en éprouvant les sensations originelles, ce n'est pas mon but ici.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mon but&lt;/strong&gt;, c'est de pouvoir programmer &lt;strong&gt;depuis un éditeur de texte&lt;/strong&gt; simple, mais pas trop, et de pouvoir mettre au point avec certaines facilités comme un &lt;strong&gt;retour d'erreur&lt;/strong&gt; d'assemblage et l'accès à un &lt;strong&gt;debuggeur&lt;/strong&gt;. Et tout ceci avec une chaîne qui minimise les manipulations répétitives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Minimiser&lt;/strong&gt; les &lt;strong&gt;manipulations répétitives&lt;/strong&gt; permet de rester concentré au maximum sur ce que je fais. Je n'ai pas envie, à chaque lancement, de taper des commandes particulières ou de faire quelques clics souris, toujours les mêmes, avec un &lt;strong&gt;risque de me tromper&lt;/strong&gt; et de chasser un bug que je crois être là alors …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Reprenons sur la &lt;strong&gt;programmation en assembleur&lt;/strong&gt; sur &lt;strong&gt;VG5000µ&lt;/strong&gt; depuis un ordinateur actuel. Car s'il est possible et tout à fait légitime, par hobby, de programmer directement sur la machine, à l'ancienne, pour &lt;strong&gt;« retro programmer »&lt;/strong&gt; comme il y a du « retro gaming » en éprouvant les sensations originelles, ce n'est pas mon but ici.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mon but&lt;/strong&gt;, c'est de pouvoir programmer &lt;strong&gt;depuis un éditeur de texte&lt;/strong&gt; simple, mais pas trop, et de pouvoir mettre au point avec certaines facilités comme un &lt;strong&gt;retour d'erreur&lt;/strong&gt; d'assemblage et l'accès à un &lt;strong&gt;debuggeur&lt;/strong&gt;. Et tout ceci avec une chaîne qui minimise les manipulations répétitives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Minimiser&lt;/strong&gt; les &lt;strong&gt;manipulations répétitives&lt;/strong&gt; permet de rester concentré au maximum sur ce que je fais. Je n'ai pas envie, à chaque lancement, de taper des commandes particulières ou de faire quelques clics souris, toujours les mêmes, avec un &lt;strong&gt;risque de me tromper&lt;/strong&gt; et de chasser un bug que je crois être là alors que je me suis juste trompé dans une manipulation.&lt;/p&gt;
&lt;p&gt;Il y a de nombreuses manière d'automatiser une chaîne de construction de programme. Certains choix sont contraints par les outils que l'on utilise. D'autres sont des choix par préférences.&lt;/p&gt;
&lt;p&gt;Après avoir fait mon travail de reflexion, lorsque je passe à la partie d'entrée au clavier, les données sont les suivantes&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;j'entre le &lt;strong&gt;code source&lt;/strong&gt; dans un éditeur,&lt;/li&gt;
&lt;li&gt;j'effectue une action qui produit un &lt;strong&gt;fichier binaire&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;ce fichier binaire doit se lancer dans un &lt;strong&gt;émulateur&lt;/strong&gt; et/ou produire un fichier pour chargement sur &lt;strong&gt;machine réelle&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;s'il y a des &lt;strong&gt;erreurs&lt;/strong&gt;, les &lt;strong&gt;afficher&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;s'il n'y a pas d'erreurs l'&lt;strong&gt;émulateur&lt;/strong&gt; se lance &lt;strong&gt;automatiquement&lt;/strong&gt; et lance à son tour le programme.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette dernière &lt;strong&gt;opération&lt;/strong&gt; est mon &lt;strong&gt;point de départ&lt;/strong&gt; et le sujet de cet article. Vous aurez compris au passage, et suite à &lt;a href="https://www.triceraprog.fr/travailler-sur-emulateur-et-dump-de-la-rom-vg5000m.html"&gt;l'article précédent&lt;/a&gt;, que j'utiliserai un &lt;strong&gt;émulateur&lt;/strong&gt; pour la &lt;strong&gt;mise au point&lt;/strong&gt;, avant de passer sur &lt;strong&gt;machine réelle&lt;/strong&gt; pour &lt;strong&gt;confirmation&lt;/strong&gt; du fonctionnement.&lt;/p&gt;
&lt;h4&gt;Choix de l'émulateur&lt;/h4&gt;
&lt;p&gt;Au niveau &lt;strong&gt;VG5000µ&lt;/strong&gt;, au moment de l'écriture, il n'y a pas beaucoup de choix : soit &lt;a href="http://dcvg5k.free.fr/"&gt;DCVG5K&lt;/a&gt;, soit &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt;. Les &lt;strong&gt;deux&lt;/strong&gt; possèdent un &lt;strong&gt;debuggeur&lt;/strong&gt; et le moyen d'injecter un binaire en mémoire.&lt;/p&gt;
&lt;p&gt;Je vois en &lt;strong&gt;MAME&lt;/strong&gt; deux avantages pour moi : la possibilité de &lt;strong&gt;scripter le debuggeur&lt;/strong&gt; et le lancement en &lt;strong&gt;natif sous Linux&lt;/strong&gt;, qui est derrière le système d'exploitation que j'utilise (Ubuntu). &lt;strong&gt;DCVG5K&lt;/strong&gt; a l'avantage de la &lt;strong&gt;légèreté&lt;/strong&gt; dû au fait qu'il est dédié à une seule machine, ainsi que de la &lt;strong&gt;simplicité d'utilisation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour savoir comment utiliser &lt;strong&gt;MAME&lt;/strong&gt;, c'est très simple, il suffit de taper &lt;code&gt;mame -showusage&lt;/code&gt; en ligne de commande... &lt;strong&gt;Ooops&lt;/strong&gt;... 462 lignes d'explication de paramètres... Et ce n'est qu'un résumé.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MAME&lt;/strong&gt; est un &lt;strong&gt;gros morceau&lt;/strong&gt; et j'espère qu'avec les &lt;strong&gt;renseignements&lt;/strong&gt; de cet article, je vous aurait &lt;strong&gt;débrousaillé&lt;/strong&gt; le terrain.&lt;/p&gt;
&lt;h4&gt;Lancement de l'émulation&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Avant toute chose&lt;/em&gt; : tout ce que j'explique est du lancement en &lt;strong&gt;ligne de commande&lt;/strong&gt;. Il est possible de faire la même chose à travers des fichiers de configuration ou des raccourcis Windows avec paramètres mais le but final est d'inclure ça à un script de lancement. La ligne de commande est aussi la manière la &lt;strong&gt;plus simple&lt;/strong&gt; de jouer avec les paramètres (pour peu qu'on utilise un &lt;strong&gt;shell moderne&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Pour lancer l'émulation du &lt;strong&gt;VG5000µ&lt;/strong&gt;, c'est tout simplement :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : l'exécutable s'appelle mame64 pour quoi car je compile la version depuis les sources. Suivant les distributions de MAME, il peut avoir un autre nom.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : Si MAME vous annonce qu'il vous manque une ROM, revenez à mon &lt;a href="https://www.triceraprog.fr/travailler-sur-emulateur-et-dump-de-la-rom-vg5000m.html"&gt;article précédent&lt;/a&gt;, &lt;strong&gt;dumpez votre ROM&lt;/strong&gt;, placez-là dans le répertoire attendu par MAME et c'est reparti.&lt;/p&gt;
&lt;p&gt;Le lancement de l'émulateur dans cette configuration &lt;strong&gt;lance la machine&lt;/strong&gt; après un bandeau la présentant et, à l'heure actuelle, un bandeau rouge indiquant que l'émulation ne fonctionne pas. En effet, l'émulation n'est pas considérée comme terminée ; mais en ce qui nous concerne, cela sera suffisant.&lt;/p&gt;
&lt;p&gt;J'ai évoqué un &lt;strong&gt;debuggeur&lt;/strong&gt;. Il est accessible sous plusieurs formes et je vais laisser celle par défaut :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -nomax -window -debug&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;J'ai ajouté au passage quelques options supplémentaires :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-ramsize 48k&lt;/code&gt; indique que je veux l'extension RAM maximale disponible sur le VG5000µ (l'autre option est 32k, et par défaut, la machine aura ses 16k)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-nomax&lt;/code&gt; indique que je ne veux pas maximiser la fenêtre&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-window&lt;/code&gt; indique que je veux lancer l'émulateur dans une fenêtre et non en plein écran&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-debug&lt;/code&gt;, bien entendu, lance le debugger&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En &lt;strong&gt;mode debugger&lt;/strong&gt; par défaut, l'émulation ne se lance pas tout de suite. Elle est immédiatement &lt;strong&gt;mise en pause&lt;/strong&gt;. Sur l'image suivante, vous pouvez voir que le &lt;code&gt;PC&lt;/code&gt; est à &lt;code&gt;$0000&lt;/code&gt;, sur la première instruction qui sera exécutée par le processeur de la machine &lt;code&gt;jp $1000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Debugger par défaut (Qt) sur MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201801/VG5000-Mame-Debug-Qt.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;Ce &lt;strong&gt;debugger&lt;/strong&gt; accepte des &lt;strong&gt;raccourcis clavier&lt;/strong&gt; mais peut aussi accepter des &lt;strong&gt;commandes&lt;/strong&gt;. Le debugger peut aussi prendre ses commandes &lt;strong&gt;depuis un fichier&lt;/strong&gt; texte grace à la commande &lt;code&gt;source&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je vous invite à entrer le texte suivant dans un fichier &lt;code&gt;debug.txt&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;adf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : &lt;code&gt;go $2adf&lt;/code&gt; indique de lancer l'émulation avec un point d'arrêt temporaire à l'adresse $2adf, qui est une addresse qui, lorsqu'elle est atteinte, garanti que le VG5000µ a terminé son initialisation.&lt;/p&gt;
&lt;p&gt;Puis d'avoir un &lt;strong&gt;fichier binaire&lt;/strong&gt; au nom de &lt;code&gt;hello.bin&lt;/code&gt; de mettre ces deux fichiers dans le répertoire de travail de MAME.&lt;/p&gt;
&lt;p&gt;Et enfin, depuis le debuggeur, taper &lt;code&gt;source debug.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Le debuggeur devrait afficher :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;adf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temporary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;breakpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;ADF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CPU&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:maincpu&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;7000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loaded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;successfully&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7018&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Suivant votre fichier, l'addresse &lt;code&gt;0x7018&lt;/code&gt; peut varier. Dans mon cas, le fichier provient du résultat de l'assembleur &lt;a href="https://www.triceraprog.fr/du-langage-machine-a-lassembleur-sur-vg5000m.html"&gt;d'un article précédent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dans le debuggeur, vous pouvez ouvrir une fenêtre de &lt;strong&gt;visualisation de mémoire&lt;/strong&gt; pour vérifier que le fichier binaire a été injecté. Et si votre fichier est le même que le mien, vous pouvez entrer &lt;code&gt;CALL &amp;amp;"7000"&lt;/code&gt; dans la machine émulée pour voir apparaître &lt;code&gt;Bonjour!&lt;/code&gt; à l'écran.&lt;/p&gt;
&lt;p&gt;C'est &lt;strong&gt;déjà bien&lt;/strong&gt;, non ?&lt;/p&gt;
&lt;h4&gt;Automatique on a dit !&lt;/h4&gt;
&lt;p&gt;C'est bien... mais taper &lt;code&gt;source&lt;/code&gt; à chaque lancement, c'est long, &lt;strong&gt;on peut se tromper&lt;/strong&gt; et cela serait mieux si cela pouvait être automatique.&lt;/p&gt;
&lt;p&gt;Et c'est tout à fait possible :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -window -nomax -debug -debugscript debug.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-debugscript&lt;/code&gt;, comme son nom l'indique, fourni un nom de script pour le debugger qui sera &lt;strong&gt;exécuté au démarrage&lt;/strong&gt;. Juste après le lancement de l'émulateur, le fichier binaire est donc injecté &lt;strong&gt;sans manipulation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;D'accord, mais il faut encore taper la commande &lt;code&gt;CALL &amp;amp;"7000"&lt;/code&gt; pour lancer le programme, et avec la disposition d'un clavier qui change entre la machine émulée et la machine hôte, personnellement, &lt;strong&gt;je trouve cela fastidieux&lt;/strong&gt; (surtout pour la touche ", qui est une touche morte dans ma configuration par défaut).&lt;/p&gt;
&lt;p&gt;Pas de problème :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -window -nomax -debug -debugscript debug.txt -autoboot_command 'CALL &amp;amp;"7000"\n' -autoboot_delay 2&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-autoboot_command&lt;/code&gt; indique la &lt;strong&gt;chaîne&lt;/strong&gt; à passer à l'émulateur comme si les &lt;strong&gt;touches&lt;/strong&gt; étaient &lt;strong&gt;appuyées&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-autoboot_delay&lt;/code&gt; pose un &lt;strong&gt;délai&lt;/strong&gt; de 2 secondes avant de lancer les commandes, ce qui laisse le temps au script de s'exécuter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À vrai dire, le délai de 2 secondes est la valeur par défaut, mais l'idée était de montrer la commande, pour pouvoir ajuster le délai.&lt;/p&gt;
&lt;p&gt;Là, ça commence à être pas mal.&lt;/p&gt;
&lt;h4&gt;Mais...&lt;/h4&gt;
&lt;p&gt;Mais il y a &lt;strong&gt;deux choses&lt;/strong&gt; encore qui me &lt;strong&gt;chiffonnent&lt;/strong&gt;. Tout d'abord, la fenêtre du debuggeur se place au-dessus de ma fenêtre d'émulation, et je dois &lt;strong&gt;systématiquement la bouger&lt;/strong&gt; pour voir le résultat. Il y a bien la possibilité d'utiliser la commande &lt;code&gt;-debugger none&lt;/code&gt;, mais alors le script n'est plus exécuté.&lt;/p&gt;
&lt;p&gt;Il y a la possibilité d'utiliser un debuggeur qui utilise la bibliothèque &lt;code&gt;imgui&lt;/code&gt; et qui s'affiche dans la fenêtre d'émulation. Je vous suggère alors de passer &lt;code&gt;-nomax&lt;/code&gt; en &lt;code&gt;-max&lt;/code&gt;. Possibilité aussi pour le debugger par défaut (mais imgui est semi-transparent, le debugger par défaut opaque).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mame64 vg5k -ramsize 48k -window -max -debug -debugscript debug.txt -autoboot_command 'CALL &amp;amp;"7000"\n' -autoboot_delay 2 -debugger imgui -video bgfx&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cela donne déjà &lt;strong&gt;de quoi s'amuser&lt;/strong&gt; et &lt;strong&gt;automatiser&lt;/strong&gt; la chaîne de développement. Il y a cependant moyen d'aller encore plus loin avec &lt;strong&gt;MAME&lt;/strong&gt;. Ça sera pour la prochaine fois.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Debugger utilisant ImGUI sur MAME" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201801/VG5000-Debug-imgui.jpeg"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="ASM"></category><category term="Z80"></category><category term="Émulation"></category><category term="Debug"></category><category term="Automatisation"></category></entry><entry><title>Travailler sur émulateur et dump de la ROM VG5000µ</title><link href="https://www.triceraprog.fr/travailler-sur-emulateur-et-dump-de-la-rom-vg5000m.html" rel="alternate"></link><published>2018-01-01T00:00:00+01:00</published><updated>2018-01-01T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2018-01-01:/travailler-sur-emulateur-et-dump-de-la-rom-vg5000m.html</id><summary type="html">&lt;p&gt;&lt;a href="https://www.triceraprog.fr/des-outils-pour-programmer-en-assembleur-sur-vg5000m.html"&gt;Précédemment&lt;/a&gt;, j'ai commencé à parler d'une chaîne d'assemblage pour développer un programme depuis un &lt;strong&gt;ordinateur actuel&lt;/strong&gt; vers une &lt;strong&gt;machine ancienne&lt;/strong&gt;, le VG5000µ qui est l'ordinateur qui nous suit depuis le début de ces articles.&lt;/p&gt;
&lt;p&gt;Un des avantages d'utiliser une machine de développement &lt;strong&gt;différente&lt;/strong&gt; de la machine cible est de ne pas souffrir des erreurs, plantages et reboot provoquées par des &lt;strong&gt;erreurs&lt;/strong&gt;. Imaginez, développer sur la machine que l'on programme elle-même, à une époque où le &lt;strong&gt;système d'exploitation&lt;/strong&gt; ne protège rien du tout : une erreur, un reboot et si vous n'avez pas sauvé, &lt;strong&gt;il faut recommencer&lt;/strong&gt;. Et si vous avez sauvé, les temps de chargements et de sauvegardes sont &lt;strong&gt;assez long&lt;/strong&gt;, surtout sur une machine qui n'a pour mémoire externe qu'un &lt;strong&gt;magnétophone à cassettes&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;Bref, développer sur une &lt;strong&gt;machine annexe&lt;/strong&gt; et envoyer sur la machine cible, c'est &lt;strong&gt;plus simple&lt;/strong&gt;, cela permet de profiter d'outils modernes mais... &lt;strong&gt;ça reste lent&lt;/strong&gt; dans la …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.triceraprog.fr/des-outils-pour-programmer-en-assembleur-sur-vg5000m.html"&gt;Précédemment&lt;/a&gt;, j'ai commencé à parler d'une chaîne d'assemblage pour développer un programme depuis un &lt;strong&gt;ordinateur actuel&lt;/strong&gt; vers une &lt;strong&gt;machine ancienne&lt;/strong&gt;, le VG5000µ qui est l'ordinateur qui nous suit depuis le début de ces articles.&lt;/p&gt;
&lt;p&gt;Un des avantages d'utiliser une machine de développement &lt;strong&gt;différente&lt;/strong&gt; de la machine cible est de ne pas souffrir des erreurs, plantages et reboot provoquées par des &lt;strong&gt;erreurs&lt;/strong&gt;. Imaginez, développer sur la machine que l'on programme elle-même, à une époque où le &lt;strong&gt;système d'exploitation&lt;/strong&gt; ne protège rien du tout : une erreur, un reboot et si vous n'avez pas sauvé, &lt;strong&gt;il faut recommencer&lt;/strong&gt;. Et si vous avez sauvé, les temps de chargements et de sauvegardes sont &lt;strong&gt;assez long&lt;/strong&gt;, surtout sur une machine qui n'a pour mémoire externe qu'un &lt;strong&gt;magnétophone à cassettes&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;Bref, développer sur une &lt;strong&gt;machine annexe&lt;/strong&gt; et envoyer sur la machine cible, c'est &lt;strong&gt;plus simple&lt;/strong&gt;, cela permet de profiter d'outils modernes mais... &lt;strong&gt;ça reste lent&lt;/strong&gt; dans la plupart des cas. En tout cas sur une machine comme le VG5000µ qui n'a pas eu de développement spécifique qui pourrait injecter du code depuis une autre machine (pour le moment tout du moins, car c'est possible et j'ai cru comprendre qu'une carte était à l'étude).&lt;/p&gt;
&lt;p&gt;Viens la solution de l'émulation. Un &lt;strong&gt;émulateur&lt;/strong&gt; est un logiciel qui va reproduire le fonctionnement de la machine cible. Étant énormément plus lente que la machine hôte, la machine cible pourra être émulée de manière tout à fait satisfaisante. Un émulateur pourra aussi facilement et rapidement &lt;strong&gt;charger un programme&lt;/strong&gt; depuis la machine hôte pour la mise au point, réduisant la fréquence d'essai sur machine véritable.&lt;/p&gt;
&lt;p&gt;Mais pour &lt;strong&gt;utiliser&lt;/strong&gt; un émulateur, dans la majorité des cas, il faut &lt;strong&gt;fournir la ROM&lt;/strong&gt;, c'est-à-dire le programme résident de la machine. Ce n'est pas nécessaire pour &lt;a href="http://dcvg5k.free.fr/"&gt;DCVG5K&lt;/a&gt;, l'émulateur développé par Daniel Coulom. Par contre, c'est nécessaire pour l'utilisation de &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt; (plus exactement sa sous-partie MESS, qui émule les ordinateurs). De manière générale, vous êtes supposés avoir une copie de votre &lt;strong&gt;propre version de la ROM&lt;/strong&gt;. Passons sur la partie un peu ridicule de cette restriction puisque le fichier que vous allez obtenir sera en tout point identique à celui obtenu par extraction depuis une autre machine...&lt;/p&gt;
&lt;p&gt;Toujours est-il qu'il est très simple de copier (dumper) le contenu de la ROM d'une machine de ce type, puisqu'elle est visible et complètement adressable par l'utilisateur.&lt;/p&gt;
&lt;h4&gt;La méthode&lt;/h4&gt;
&lt;p&gt;Le VG5000µ doit être &lt;strong&gt;branché&lt;/strong&gt;, bien entendu, et &lt;strong&gt;relié&lt;/strong&gt; à une carte d'acquisition audio. Cela peut être tout simplement &lt;strong&gt;l'entrée son de votre ordinateur&lt;/strong&gt;, certains utilisent des enregistreurs séparés.&lt;/p&gt;
&lt;p&gt;L'idée est donc de sauver le contenu de la &lt;strong&gt;ROM&lt;/strong&gt;, tel quel, dans un fichier. Rien de plus simple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="vg"&gt;CSAVEM&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ROM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;16384&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;CSAVEM&lt;/code&gt; est la commande pour sauver un fichier depuis la &lt;strong&gt;M&lt;/strong&gt;émoire. Le nom du fichier est entre guillemets. &lt;code&gt;0&lt;/code&gt; est l'adresse de départ et 16384 la taille en octets de la plage à sauvegarder. La ROM faisant 16 kio, la sauvegarde contiendra l'intégralité de la &lt;strong&gt;ROM&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Avant d'appuyer sur la touche &lt;code&gt;ENTRÉE&lt;/code&gt; du VG5000µ, il faudra démarrer l'enregistrement sur l'ordinateur. J'utilise &lt;a href="http://audacity.fr/"&gt;&lt;code&gt;Audacity&lt;/code&gt;&lt;/a&gt; pour cela. Un logiciel libre de manipulation audio.&lt;/p&gt;
&lt;p&gt;Assurez-vous au niveau du niveau d'entrée que le signal sature, cela sera plus facile pour le décodage. N'oublions pas qu'on est-ici dans un codage de &lt;strong&gt;signal numérique&lt;/strong&gt;, pas dans de l'écoutable, ce qui est important, c'est que les signaux soient &lt;strong&gt;distinguables&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L'opération est assez longue, environ 2 minutes 30.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Signal audio d'un enregistrement sur K7" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201712/RomSignalAudio.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;Une fois le &lt;strong&gt;signal enregistré&lt;/strong&gt;, il faut l'exporter en format &lt;code&gt;WAV&lt;/code&gt; puis le décoder. Comment décoder un signal en sortie de VG5000µ sera l'objet d'un futur article ou je décrirai le programme que j'utilise (et que je publierai sur GitHub). En attendant, l'outil &lt;a href="http://dcvg5k.free.fr/"&gt;DCToolBox&lt;/a&gt; de Daniel Coulom fonctionne bien, et se lance tout à fait avec Wine sous Ubuntu si vous n'êtes pas sous Windows.&lt;/p&gt;
&lt;p&gt;Avec mon outil, le contenu binaire intéressant est extrait simplement.&lt;/p&gt;
&lt;p&gt;Avec DCToolBox, il vous faudra transformer le &lt;code&gt;WAV&lt;/code&gt; en format &lt;code&gt;K7&lt;/code&gt; et en extraire les informations. Le format &lt;code&gt;K7&lt;/code&gt; est extrêmement simple, il contient l'ensemble des &lt;strong&gt;données encodées&lt;/strong&gt; dans le &lt;strong&gt;signal numérique&lt;/strong&gt; produit par la machine. Tout d'abord les 32 octets d'&lt;strong&gt;en-tête&lt;/strong&gt;, qui ne nous intéressent pas ici, puis 10 octets d'amorce du contenu sauvé, puis le &lt;strong&gt;contenu&lt;/strong&gt; lui-même. La taille, nous la connaissons, est de 16384 octets.&lt;/p&gt;
&lt;p&gt;Il faut donc aller chercher les 16384 octets à partir du 42ième, ce qui s'écrit très simplement dans un &lt;strong&gt;shell Unix&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tail -c+43 dump.k7 &lt;span class="p"&gt;|&lt;/span&gt; head -c &lt;span class="m"&gt;16384&lt;/span&gt; &amp;gt; dump.rom
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;dump.k7&lt;/code&gt; étant le nom du fichier au format &lt;code&gt;K7&lt;/code&gt; et &lt;code&gt;dump.rom&lt;/code&gt; le fichier résultat.&lt;/p&gt;
&lt;p&gt;Si vous n'avez pas accès à un shell Unix... je suis preneur d'une méthode simple pour l'ajouter à l'article.&lt;/p&gt;
&lt;h4&gt;Et voilà !&lt;/h4&gt;
&lt;p&gt;Vous avez à présent une extraction de la &lt;strong&gt;ROM&lt;/strong&gt; d'une machine &lt;strong&gt;VG5000µ&lt;/strong&gt;, utilisable par les émulateurs la nécessitant.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Sauver la ROM sur K7" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201712/DumpRomVG5k.jpg"&gt;&lt;/p&gt;</content><category term="Machines"></category><category term="VG5000"></category><category term="Émulation"></category></entry><entry><title>Joyeuses fêtes en haute résolution</title><link href="https://www.triceraprog.fr/joyeuses-fetes-en-haute-resolution.html" rel="alternate"></link><published>2017-12-30T00:00:00+01:00</published><updated>2017-12-30T00:00:00+01:00</updated><author><name>Sylvain Glaize</name></author><id>tag:www.triceraprog.fr,2017-12-30:/joyeuses-fetes-en-haute-resolution.html</id><summary type="html">&lt;p&gt;Puisque la fin de l'année approche et que les fêtes dites de fin d'années ainsi que le nouvel an sont d'actualités, j'ai ressorti mon convertisseur d'image vers le &lt;strong&gt;VG5000µ&lt;/strong&gt; publié &lt;a href="https://github.com/Triceraprog/ImgToVG5000"&gt;ici&lt;/a&gt; et décrit &lt;a href="https://www.triceraprog.fr/vg5000m-haute-resolution.html"&gt;ici&lt;/a&gt; pour une image « haute résolution » sur la machine.&lt;/p&gt;
&lt;p&gt;L'astuce pour que la compression passe bien a été de positionner le maximum de motifs identiques sur une grille. Pour les dates et l'adresse du site, j'ai ajouté dans le programme &lt;strong&gt;BASIC&lt;/strong&gt; à la main l'affichage en texte.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;91&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;J$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;22001177--22001188&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;92&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX15:CURSORY17:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;PRINTJ$&lt;/span&gt;
&lt;span class="nl"&gt;93&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX15:CURSORY18:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;PRINTJ$&lt;/span&gt;
&lt;span class="nl"&gt;95&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX23:CURSORY23:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TRICERAPROG.FR&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On y voit que pour écrire en double hauteur, il faut doubler l'affichage sur la ligne suivante. Et pour écrire en largeur, il faut doubler les lettres à afficher. Le tout en précisant &lt;strong&gt;3&lt;/strong&gt; en second paramètre de l'instruction &lt;code&gt;TX&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le dithering qu'effectue la conversion malheureusement n'a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Puisque la fin de l'année approche et que les fêtes dites de fin d'années ainsi que le nouvel an sont d'actualités, j'ai ressorti mon convertisseur d'image vers le &lt;strong&gt;VG5000µ&lt;/strong&gt; publié &lt;a href="https://github.com/Triceraprog/ImgToVG5000"&gt;ici&lt;/a&gt; et décrit &lt;a href="https://www.triceraprog.fr/vg5000m-haute-resolution.html"&gt;ici&lt;/a&gt; pour une image « haute résolution » sur la machine.&lt;/p&gt;
&lt;p&gt;L'astuce pour que la compression passe bien a été de positionner le maximum de motifs identiques sur une grille. Pour les dates et l'adresse du site, j'ai ajouté dans le programme &lt;strong&gt;BASIC&lt;/strong&gt; à la main l'affichage en texte.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;91&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;J$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;22001177--22001188&amp;quot;&lt;/span&gt;
&lt;span class="nl"&gt;92&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX15:CURSORY17:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;PRINTJ$&lt;/span&gt;
&lt;span class="nl"&gt;93&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX15:CURSORY18:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;PRINTJ$&lt;/span&gt;
&lt;span class="nl"&gt;95&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;CURSORX23:CURSORY23:&lt;/span&gt;&lt;span class="vg"&gt;TX6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="il"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;PRINT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TRICERAPROG.FR&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On y voit que pour écrire en double hauteur, il faut doubler l'affichage sur la ligne suivante. Et pour écrire en largeur, il faut doubler les lettres à afficher. Le tout en précisant &lt;strong&gt;3&lt;/strong&gt; en second paramètre de l'instruction &lt;code&gt;TX&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le dithering qu'effectue la conversion malheureusement n'a pas été des plus heureux sur l'un des &lt;strong&gt;e&lt;/strong&gt;, ce qui fait que la palette aurait pu être plus petite qu'elle ne l'est.&lt;/p&gt;
&lt;p&gt;Voici l'image tramée :&lt;/p&gt;
&lt;p&gt;&lt;img alt="L'image tramées" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201712/dithered_fetes.png"&gt;&lt;/p&gt;
&lt;p&gt;Ainsi que la palette obtenue :&lt;/p&gt;
&lt;p&gt;&lt;img alt="La palette" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201712/palette_fetes.png"&gt;&lt;/p&gt;
&lt;p&gt;Avant de passer au résultat, un &lt;a href="https://www.triceraprog.fr/files/201712/fetesvg5k17.zip"&gt;fichier zip&lt;/a&gt; est disponible contenant le programme en format &lt;code&gt;.k7&lt;/code&gt; ainsi qu'en &lt;code&gt;.wav&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Petit détail&lt;/em&gt; : sur un &lt;strong&gt;émulateur&lt;/strong&gt;, l'écran reste noir pendant la construction de l'image, puis celle-ci &lt;strong&gt;apparaît&lt;/strong&gt; lorsque dans la deuxième partie du programme, les caractères étendus sont construits.&lt;/p&gt;
&lt;p&gt;Par contre, sur une &lt;strong&gt;machine réelle&lt;/strong&gt;, la mémoire du processeur graphique n'étant &lt;strong&gt;pas effacée&lt;/strong&gt; au démarrage, on commence par voir s'afficher des bandes verticales mêlées à un peu de bruit, puis le message apparaît lorsque les caractères étendus sont construits.&lt;/p&gt;
&lt;p&gt;Dans les deux cas, après un &lt;strong&gt;redémarrage&lt;/strong&gt; à chaud (le programme &lt;strong&gt;BASIC&lt;/strong&gt; n'est pas effacé de la mémoire), l'affichage se fait progressivement, car les caractères étendus sont déjà construits.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le résultat" class="img-responsive center-block img-rounded" src="https://www.triceraprog.fr/images/201712/JoyeusesFetes1718.jpeg"&gt;&lt;/p&gt;</content><category term="Divers"></category><category term="Image"></category><category term="Dithering"></category><category term="VG5000"></category></entry></feed>