<?xml version="1.0" encoding="UTF-8" ?>
<!-- RSS generated by PHPBoost on Sat, 04 Apr 2026 06:11:19 +0200 -->

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Wiki MSX Village]]></title>
		<atom:link href="https://msxvillage.fr/syndication/rss/wiki/128" rel="self" type="application/rss+xml"/>
		<link>https://msxvillage.fr</link>
		<description><![CDATA[Derniers articles de la catégorie Programmation Assembleur]]></description>
		<copyright>(C) 2005-2026 PHPBoost</copyright>
		<language>fr</language>
		<generator>PHPBoost</generator>
		
		
		<item>
			<title><![CDATA[Temps d'accès à la VRAM]]></title>
			<link>https://msxvillage.fr/wiki/temps-d-acces-a-la-vram</link>
			<guid>https://msxvillage.fr/wiki/temps-d-acces-a-la-vram</guid>
			<description><![CDATA[<h2 class="formatter-title wiki-paragraph-2" id="paragraph-problematique">Problématique</h2><br />

<br />
Le processeur graphique du MSX (appelé VDP) fonctionne de façon autonome du processeur central (CPU), le Z80.<br />
<br />
Le CPU communique avec le VDP à travers des ports d'entrée/sortie (ports I/O).<br />
Ces ports I/O permettent de lire et/ou d'écrire dans les registres qui contrôlent le fonctionnement du VDP (choix du mode graphique, taille des sprites, etc.), mais aussi de lire ou écrire dans la mémoire vidéo (VRAM) du VDP.<br />
<br />
La lecture/écriture en VRAM se fait de façon indirect : on configure les registres du VDP (pour indiquer notamment l'adresse à accéder en VRAM), puis on lit/écrit la VRAM à travers les ports I/O.<br />
Le VDP doit traiter ces demandes d'accès de son coté.<br />
Hors, quand il est occupé à afficher une image à l'écran, le VDP peut prendre plus de temps à répondre à ces demandes que de temps qu'il faut au CPU pour les faire.<br />
Il peut donc arriver que le CPU envois des données trop rapidement au VDP et que certaines soient perdues, faute de temps pour les traiter.<br />
Il en résulte un affichage incorrect des données que le programme souhaitait envoyer.<br />
Idem si le CPU essaye de lire trop vite des données en VRAM : Les valeurs récupérées peuvent être incorrectes.<br />
<br />
Le temps de traitements des demandes d'accès à la VRAM dépend de certains paramètres :<br />
- La génération du VDP,<br />
- Le mode écran (screen mode) actuel,<br />
- L'activité du VDP au moment de la demande.<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-generation-et-mode-ecran">Génération et mode écran</h3><br />

<br />
Durant la période commerciale du MSX, 3 générations de VDP ont été utilisés :<br />
- Texas Instrument TMS9918 (MSX1),<br />
- Yamaha V9938 (MSX2),<br />
- Yamaha V9958 (MSX2+ et turbo R).<br />
<br />
Voici l'intervalle de temps minimale à respecter entre des accès au VDP en fonction des modes écrans (exprimé en nombre de cycles du CPU).<br />
<table class="formatter-table">
    <tr class="formatter-table-row">
        <th class="formatter-table-head">Screen mode</th>
        <th class="formatter-table-head">VDP mode</th>
        <th class="formatter-table-head">MSX1 cycles</th>
        <th class="formatter-table-head">MSX2/2+ cycles</th>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">0,W40</td>
        <td class="formatter-table-col">T1</td>
        <td class="formatter-table-col">12</td>
        <td class="formatter-table-col">20</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">0,W80</td>
        <td class="formatter-table-col">T2</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">20</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">1</td>
        <td class="formatter-table-col">G1</td>
        <td class="formatter-table-col">29</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">2</td>
        <td class="formatter-table-col">G2</td>
        <td class="formatter-table-col">29</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">3</td>
        <td class="formatter-table-col">MC</td>
        <td class="formatter-table-col">13</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">4</td>
        <td class="formatter-table-col">G3</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">5</td>
        <td class="formatter-table-col">G4</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">6</td>
        <td class="formatter-table-col">G5</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">7</td>
        <td class="formatter-table-col">G3</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">15</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">8</td>
        <td class="formatter-table-col">G7</td>
        <td class="formatter-table-col">--</td>
        <td class="formatter-table-col">15</td>
    </tr>
</table><br />
<i class="fa fa-warning" aria-hidden="true" title="warning"></i> Bien que plus moderne, le V9938 est moins réactifs que le TMS9918 dans le modes textuel 1 (Screen 0) et multi-couleur (Screen 3).<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-activite-du-vdp">Activité du VDP</h3><br />

<br />
L'activité du VDP au moment de la demande d'accès à un gros impact sur son temps de réaction.<br />
Par ex., lorsque le VDP est en train de "dessiner" les bordures, son temps de réaction est plus rapide que le temps minimum nécessaire pour le CPU pour faire une demande d'accès à la VRAM.<br />
<br />
Ainsi, dans certains cas, il n'y a aucun contrainte de temps d'accès à la VRAM :<br />
- Quand le VDP est dans le H-Blank (bordure droite/gauche), ou le V-Blank (bordure bas/haut). <span style="text-decoration: underline;">Note</span> : Le V-Blank étant relativement long, il est possible d'utiliser ce temps pour lire/écrire des données en VRAM a une vitesse maximale.<br />
- Quand l'affichage est désactivé. <span style="text-decoration: underline;">Note</span> : Par ex., on peut utiliser un écran noir (affichage désactivé) pour charger plus rapidement un niveau de jeu.<br />
<br />
L'activation ou non des sprites a un impact sur la réactivité du VDP, mais l'impact chiffré exacte sur les temps d'accès n'est pas connu.<br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-acces-au-vdp-en-assembleur">Accès au VDP en assembleur </h2><br />

<br />
Le BIOS permet d'accéder au VDP de façon sécurisé et standard. Cependant, le surcout en performant de passer par le BIOS est loin d'être négligeable et dès l'époque commercial du MSX, les développeurs ont utilisé les accès direct en assembleur pour pouvoir tirer pleinement parti de la puissance du VDP.<br />
<br />
Le CPU communiquant avec le VDP via les ports I/O, ce sont les instructions <!-- START HTML -->
<tt>in</tt>
<!-- END HTML --> et <!-- START HTML -->
<tt>out</tt>
<!-- END HTML --> (et leurs dérivés) qui sont utilisés.<br />
<br />
Dans la suite de ce chapitre, nous n'allons aborder que les accès en écriture de la VRAM (cas le plus fréquent), mais toutes les contraintes décrites ci-dessous s'applique exactement de la même façon pour la lecture en VRAM.<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-remplissage">Remplissage</h3><br />

<br />
Après la configuration des registres pour accéder à la VRAM de façon séquentielle (qui n'est pas expliqué ici), le moyen le plus rapide d'écrire 4 octets en VRAM est :<br />
<br />
<!-- START HTML -->
<pre>; Ecrire la valeur de A dans 4 octets consécutif en VRAM
out (0x98), a
out (0x98), a
out (0x98), a
out (0x98), a</pre>
<!-- END HTML --><br />
<br />
L'instruction <!-- START HTML -->
<tt>out (n),a</tt>
<!-- END HTML --> prenant 12 cycles sur MSX, elle est trop rapide pour la plus part des modes d'affichage (en dehors du V-Blank).<br />
<br />
L'instruction <!-- START HTML -->
<tt>out (c),a</tt>
<!-- END HTML --> (ou le numéro de port I/O se trouve dans le registre C) prend elle 14 cycles sur MSX. Ce qui est un chouilla trop rapide pour la plupart des modes d'affichage. Ajouter un <!-- START HTML -->
<tt>nop</tt>
<!-- END HTML --> entre chaque <!-- START HTML -->
<tt>out (c),a</tt>
<!-- END HTML --> permet d'arriver à 15 cycles, l'intervalle minimale d'accès à la VRAM des modes bitmap du MSX2 (comme le Screen 5 par ex.).<br />
<br />
Par contre, cette solution est encore trop rapide pour les modes graphiques sur MSX1 (29 cycles) ou les modes textes sur MSX2 (20 cycles). Dans ces cas, le mieux est d'intercaler d'autres instructions entre les <!-- START HTML -->
<tt>out</tt>
<!-- END HTML --> pour les écarter suffisamment dans le temps, sans perdre du temps CPU à ne rien faire avec une longue série de <!-- START HTML -->
<tt>nop</tt>
<!-- END HTML -->.<br />
<br />
<h4 class="formatter-title wiki-paragraph-4" id="paragraph-code-optimal">Code optimal</h4><br />

<br />
Codes les plus rapides pour remplir la VRAM avec une valeur donnée en fonction des mode d'affichages :<br />
<table class="formatter-table">
    <tr class="formatter-table-row">
        <th class="formatter-table-head">Screen 0 MSX1</th>
        <th class="formatter-table-head">Screen 3 MSX1</th>
        <th class="formatter-table-head">Screen 1~8 MSX2</th>
        <th class="formatter-table-head">Screen 0 MSX2</th>
        <th class="formatter-table-head">Screen 1~2 MSX1</th>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 12 cycles
   out (0x98),a
   out (0x98),a
   out (0x98),a
   out (0x98),a
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 13 cycles
   out (0x98),a
   nop
   out (0x98),a
   nop
   out (0x98),a
   nop
   out (0x98),a
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 15 cycles
   ld c, 0x98
   out (c),a
   nop
   out (c),a
   nop
   out (c),a
   nop
   out (c),a
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 20 cycles
   ld c, 0x98
   out (c),a
   nop
   nop
   nop
   nop
   nop
   nop
   out (c),a
   nop
   nop
   nop
   nop
   nop
   nop
   out (c),a
   nop
   nop
   nop
   nop
   nop
   nop
   out (c),a
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 29 cycles
   ld c, 0x98
   ld b, #4
loop:
   out (c),a
   nop
   djnz loop
        </pre>
<!-- END HTML --></td>
    </tr>
</table><br />
<br />
Si le nombre de donnée à envoyer est variable ou si la taille du programme est primordiale, la boucle la plus rapide pour remplir la VRAM fonctionne avec un intervalle de 26 cycles et est donc compatible avec la plupart des modes d'affichage :<br />
<br />
<!-- START HTML -->
<pre>; 26 cycles
   ld b, #100
loop:
   out (0x98),a
   djnz loop</pre>
<!-- END HTML --><br />
<br />
Cette boucle permet d'écrire jusqu'à 256 octets. Pour plus, il faut soit créer une double boucle (boucle 16-bits, qui permet jusqu'à 65536 itérations) ou utiliser un boucle dépliée (cf. le chapitre dédié).<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-copie">Copie</h3><br />

<br />
Les exemples précédent ne permettent que de remplir une zone de VRAM avec une valeur unique. C'est utile pour effacer une zone de VRAM par ex., mais la plus part du temps, le programme va vouloir envoyer des données graphiques qui viennent de la mémoire du CPU (un image, un sprite, etc.) et il faut donc utiliser les instructions Z80 qui le permettent.<br />
<br />
<!-- START HTML -->
<tt>outi</tt>
<!-- END HTML --> et <!-- START HTML -->
<tt>outd</tt>
<!-- END HTML --> permettent d'envoyer vers le VDP la valeur contenu à l'adresse pointé par le registre HL puis incrémente/décréemente HL.<br />
<br />
Une fois avoir configuré HL pour pointer vers ses données en mémoire et les registres du VDP pour pointer vers la destination dans la VRAM, le moyen le plus rapide de transférer des données est :<br />
<br />
<!-- START HTML -->
<pre>; Ecrire la valeur de (HL++) dans 4 octets consécutif en VRAM
outi
outi
outi
outi</pre>
<!-- END HTML --><br />
<br />
L'instruction <!-- START HTML -->
<tt>outi</tt>
<!-- END HTML --> prend 18 cycles, ce qui est suffisant pour tous les modes sauf les modes graphiques sur MSX1 (29 cycles) ou les modes textes sur MSX2 (20 cycles).<br />
<!-- START HTML -->
<tt>outir</tt>
<!-- END HTML --> prend 23 cycles mais permet de choisir un nombre variable d'accès à la VRAM avec une seule instruction (le nombre d'itération se trouvant dans le registre B).<br />
<br />
Pour les modes textes sur MSX2, il suffit d'ajouter 2 <!-- START HTML -->
<tt>nop</tt>
<!-- END HTML --> entre chaque <!-- START HTML -->
<tt>outi</tt>
<!-- END HTML --> pour respecter l'intervalle de temps minimale d'accès.<br />
<br />
<!-- START HTML -->
<tt>outir</tt>
<!-- END HTML --> ne peut être "ralenti" avec des <!-- START HTML -->
<tt>nop</tt>
<!-- END HTML --> vu que la boucle est géré en interne par le Z80.<br />
Pour avoir une boucle qui respecte l'intervalle de 29 cycles nécessaires pour les modes graphiques sur MSX1, vous pouvez utiliser :<br />
<br />
<!-- START HTML -->
<pre>; Boucle de 29 cycles (18 + 11)
OutiToVram:
    outi              ; send (HL) ; HL++ ; B--
    jp nz, OutiToVram ; while register B not 0
</pre>
<!-- END HTML --><br />
<br />
<h4 class="formatter-title wiki-paragraph-4" id="paragraph-code-optimal">Code optimal</h4><br />

<br />
Codes les plus rapides pour copier des données en VRAM fonction des mode d'affichages (adresse des données à copier en mémoire dans le registre HL) :<br />
<table class="formatter-table">
    <tr class="formatter-table-row">
        <th class="formatter-table-head">Screen 0 et 3 MSX1<br />
Screen 1~8 MSX2</th>
        <th class="formatter-table-head">Screen 0 MSX2</th>
        <th class="formatter-table-head">Screen 1~2 MSX1</th>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 18 cycles
   ld c, 0x98
   outi
   outi
   outi
   outi
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 20 cycles
   ld c, 0x98
   outi
   nop
   nop
   outi
   nop
   nop
   outi
   nop
   nop
   outi
        </pre>
<!-- END HTML --></td>
        <td class="formatter-table-col"><!-- START HTML -->
<pre style="text-align:left; vertical-align:top;">; 29 cycles
   ld c, 0x98
   ld b, 4
loop:
    outi
    jp nz, loop
        </pre>
<!-- END HTML --></td>
    </tr>
</table><br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-temps-d-execution-des-instructions-de-io">Temps d'exécution des instructions de I/O</h2><br />

<br />
<table class="formatter-table">
    <tr class="formatter-table-row">
        <th class="formatter-table-head">Instruction</th>
        <th class="formatter-table-head">Cycles (T-States)</th>
        <th class="formatter-table-head">Timing I/O</th>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">in a,(n)</td>
        <td class="formatter-table-col">12</td>
        <td class="formatter-table-col">9|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">out (n),a</td>
        <td class="formatter-table-col">12</td>
        <td class="formatter-table-col">9|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">in a,(c)</td>
        <td class="formatter-table-col">14</td>
        <td class="formatter-table-col">11|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">out (c),a</td>
        <td class="formatter-table-col">14</td>
        <td class="formatter-table-col">11|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">outi</td>
        <td class="formatter-table-col">18</td>
        <td class="formatter-table-col">15|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">outd</td>
        <td class="formatter-table-col">18</td>
        <td class="formatter-table-col">15|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">ini</td>
        <td class="formatter-table-col">18</td>
        <td class="formatter-table-col">12|6</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">ind</td>
        <td class="formatter-table-col">18</td>
        <td class="formatter-table-col">12|6</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">otir</td>
        <td class="formatter-table-col">23 (loop)<br />
        18 (last)</td>
        <td class="formatter-table-col">15|8<br />
        15|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">otdr</td>
        <td class="formatter-table-col">23 (loop)<br />
        18 (last)</td>
        <td class="formatter-table-col">15|8<br />
        15|3</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">inir</td>
        <td class="formatter-table-col">23 (loop)<br />
        18 (last)</td>
        <td class="formatter-table-col">12|11<br />
        12|6</td>
    </tr>
    <tr class="formatter-table-row">
        <td class="formatter-table-col">indr</td>
        <td class="formatter-table-col">23 (loop)<br />
        18 (last)</td>
        <td class="formatter-table-col">12|11<br />
        12|6</td>
    </tr>
</table><br />
<br />
Tant qu'un programme n'enchaine qu'une même instruction à intervalle régulier, seule le temps d'exécution de cette instruction compte. Par contre, si on enchaine des instructions différentes, il est important de savoir à quel cycle de l'exécution de l'instruction l'I/O a lieu. Voir la dernière colonne du tableau ci-dessus. Les timing sont définies sous la forme <!-- START HTML -->
<tt>X | Y</tt>
<!-- END HTML --> avec X = nombre de cycle avant l'I/O et Y = nombre de cycle entre après l'I/O.<br />
<br />
Par ex., si on enchaine les instructions <!-- START HTML -->
<tt>outi</tt>
<!-- END HTML --> (15|3) et <!-- START HTML -->
<tt>ini</tt>
<!-- END HTML --> (12|6), l'intervalle de temps entre deux I/O est alors de 15 cycles (3 + 12).<br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-boucle-deroule">Boucle déroulé</h2><br />

<br />
La plupart du temps, un programme va vouloir remplir ou copier un grand nombre de donnée en VRAM. La méthode la plus simple pour dépasser la limite des 256 octets d'une boucle classique est de créer une double boucle (décrémentation automatique du registre B via <!-- START HTML -->
<tt>djnz</tt>
<!-- END HTML --> et manuelle d'un autre registre). Cette méthode (boucle 16-bits) est presque aussi rapide qu'une boucle 8-bits puisse que le surcout de la 2e boucle (16 cycles) est amortie par le fait qu'elle n'est exécuté qu'une fois tous les 256 octets.<br />
<br />
L'instruction <!-- START HTML -->
<tt>otir</tt>
<!-- END HTML --> est plus rapide (23 cycles) mais également limité à 256 octets (limite qu'on peut également dépasser avec un double boucle 16-bits).<br />
<br />
Mais il y a une méthode qui allie vitesse et grande quantité de donnée : Il s'agit de « dérouler » une partie de la boucle.<br />
Par ex., on peut avoir 16 instructions d'I/O consécutive dans une boucle et ainsi diviser le nombre d'itération de la boucle par 16.<br />
<br />
Le temps d'initialisation de la boucle sera plus lent, mais les itérations beaucoup plus rapide (gain ~18%).<br />
Il y a donc un nombre minimal d'itération à partir duquel cette méthode devient rentable.<br />
Pour une centaine d'octet à envoyer au VDP, cette méthode est déjà très largement rentable.<br />
<br />
Dans l'exemple suivant, la première itération peut couter jusqu'à 130 cycles dans le pire des cas, mais pour un grand nombre de donnée, la vitesse tend assez rapidement vers des accès I/O de 18,7 cycles !<br />
<br />
<!-- START HTML -->
<pre>
        ; HL: Source address in RAM
        ; DE: Destination address in VRAM
        ; BC: Bytes to copy (4096 max in this example)
        di
        ; Setup destination address ...
        ; ... in VRAM
    fastcopy_setup:
        ; Setup fast OUTI loop
        xor     a                       ;  5 cc
        sub     c                       ;  5 cc
        and     #15                     ;  8 cc
        jp      z, fastcopy_loop        ; 11 cc - total 29 cc (break-even at 16 loops)
        add     a                       ;  5 cc
        exx                             ;  5 cc
        add     a, #fastcopy_loop       ;  8 cc
        ld      l, a                    ;  5 cc
        ld      a, #0                   ;  8 cc
        adc     a, #fastcopy_loop >> 8  ;  8 cc
        ld      h, a                    ;  5 cc
        push    hl                      ; 12 cc
        exx                             ;  5 cc
        ret                             ; 11 cc - total 101 cc (break-even at 25 loops)
    fastcopy_loop:
        ; Fast OUTIR (with 16x unrolled OUTI)
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        outi                            ; 18 cc
        jp      pe, fastcopy_loop       ; 11 cc (0,6875 cc per outi)
    fastcopy_end:
        ei</pre>
<!-- END HTML --><br />
<br />
La seule astuce de ce code, c'est que la première itération de la boucle ne commence pas à <!-- START HTML -->
<tt>fastcopy_loop</tt>
<!-- END HTML --> si le nombre d'octet à copier n'est pas multiple de 16.<br />
Dans ce cas, on calcul l'adresse à laquelle doit commencer la première itération. Par exemple, si on veut copier 1030 octets (1024 + 6), la première itération sautera à la 10e instruction <!-- START HTML -->
<tt>outi</tt>
<!-- END HTML --> pour que la première boucle n'est fasse que 6, puis les suivantes se feront toutes 16 octets par 16 octets.]]></description>
			<pubDate>Sat, 28 Jan 2023 11:15:14 +0100</pubDate>
			
		</item>
		
		<item>
			<title><![CDATA[Initiation à l'assembleur]]></title>
			<link>https://msxvillage.fr/wiki/initiation-a-l-assembleur</link>
			<guid>https://msxvillage.fr/wiki/initiation-a-l-assembleur</guid>
			<description><![CDATA[<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-l-assembleur-ca-se-mange-e">L'assembleur, ça se mange ?</h2><br />

<br />
<br />
Avant de commencer l'initiation proprement dite, il est intéressant de savoir ce qui fait tout l'intérêt d'apprendre un langage comme l'assembleur, et ce qu'il est nécessaire de connaître un minimum avant de se lancer dans le grand bain !<br />
<br />
<h3 class="formatter-title">Aperçu rapide de l'architecture des MSX</h3><br />
<br />
Comme vous le savez sans doute, l'intérieur de votre MSX est composé de plein de choses qui sont sensées communiquer entre elles. Je vais vous faire ici une petite liste de ce qui va nous intéresser par la suite :<br />
<br />
- un micro-processeur <strong>Z80A</strong> et sa mémoire dédiée (<strong>RAM</strong>) et (<strong>ROM</strong>) (il y a aussi un R800 sur les Turbo-R, mais c'est une autre histoire que nous n'aborderons pas ici, du moins pas dans un premier temps ! <img src="https://msxvillage.fr/images/smileys/smile.png" alt=":)" class="smiley" /> )<br />
- un processeur graphique, que nous appellerons <strong>VDP</strong>, et sa mémoire vive dédiée (<strong>VRAM</strong>)<br />
- un processeur sonore, désigné par <strong>PSG </strong>(rien à voir avec le foot hein... <img src="https://msxvillage.fr/images/smileys/tongue.png" alt=":p" class="smiley" />)<br />
- un circuit d'interface (lui c'est le <strong>PPI</strong>)<br />
<br />
Tous ces composants interagissent entre eux, tel un ensemble de musiciens jouant ensemble un morceau de musique. Ici, le Z80 a le rôle du chef d'orchestre. C'est lui qui va tout piloter. Le but de l'assembleur, c'est de parler directement au Z80. Votre code sera la partition que fera jouer le chef d'orchestre !<br />
<br />
<br />
<h3 class="formatter-title">L'assembleur, un langage à compiler</h3><br />
<br />
Vous me direz que vous pouvez parler au Z80 avec le MSX-Basic. Certes, mais le résultat sera nettement moins rapide.<br />
<br />
Pour simplifier les choses, le Z80 ne connaît qu'une langue : le langage machine. Il ne comprend que les chiffres binaires, des suites de 0 et de 1 (que l'on écrit souvent en hexadécimal dans les programmes pour simplifier). Quand vous lui parlez en MSX-Basic, il a besoin d'un interprète ! Et le temps que votre programme soit interprété et traduit en langage machine à ce bon vieux Z80, il y a pas mal de temps qui s'écoule... Le problème du MSX-Basic est donc que la traduction se fait en direct, ce qui induit beaucoup plus de lenteur.<br />
<br />
L'assembleur quant à lui est un langage à compiler ! La traduction du programme se fait une seule fois, ce qui veut dire qu'une fois celle-ci effectuée, vous parlerez directement, sans interprète au Z80. Le gain de rapidité est juste... énorme !! <img src="https://msxvillage.fr/images/smileys/straight.png" alt=":|" class="smiley" /><br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-apercu-du-z80">Aperçu du Z80</h2><br />

<br />
Avant d'entrer dans le vif du sujet, il va être nécessaire de se pencher un peu sur ce bon vieux Z80. En effet, il est indispensable d'en savoir un minimum sur sa structure proprement dite... et sur ce qu'il sait faire.<br />
<br />
Et vous vous rendrez compte que finalement... Ben il ne sait pas faire grand-chose !! <img src="https://msxvillage.fr/images/smileys/grin.png" alt=":D" class="smiley" /><br />
<br />
Son boulot, c'est de travailler sur des bits, regroupés en octets (si ça ne vous parle pas, je vous invite à lire le<a href="https://msxvillage.fr/wiki/wiki.php?title=initiation-au-binaire"> cours sur le binaire</a>). Ce qu'il va faire avec ces octets, c'est s'en servir pour adresser des cases mémoire (Aïe, ça parle un peu en chinois là... <img src="https://msxvillage.fr/images/smileys/sad.png" alt=":(" class="smiley" /> j'y reviendrai plus tard), définir des numéros de port (euh... pareil qu'avant <img src="https://msxvillage.fr/images/smileys/top.png" alt=":oups" class="smiley" />), faire des calculs élémentaires (addition, soustraction, opérations logiques) et envoyer des données.<br />
<br />
Bon alors, l'adressage de cases mémoire : comme vous le savez (ou pas), le MSX a de la mémoire. Celle-ci peut être représentée sous forme d'une looooongue pile de cases, chacune d'elle ne pouvant contenir qu'un et un seul octet. C'est pour ça d'ailleurs qu'on chiffre les mémoires en X-octets (remplacez X par ce que vous voulez, Kilo, Mega, Giga, Tera).]]></description>
			<pubDate>Fri, 03 Sep 2021 11:08:16 +0200</pubDate>
			
		</item>
		
		<item>
			<title><![CDATA[Programmation Assembleur]]></title>
			<link>https://msxvillage.fr/wiki/programmation-assembleur</link>
			<guid>https://msxvillage.fr/wiki/programmation-assembleur</guid>
			<description><![CDATA[Articles sur la programmation en assembleur]]></description>
			<pubDate>Fri, 26 Feb 2021 21:49:53 +0100</pubDate>
			
		</item>
		
	</channel>
</rss>
