jeudi 23 octobre 2014

CHIPcon partie 2, machine virtuelle

Dans ce deuxième article du projet CHIPcon j'explique ce qu'est une machine virtuelle et plus spécifiquement celle du projet.

Mais d'Abord

Avant de débuter le sujet principal voici un photo du montage du prototype de CHIPcon v1.0. et un vidéo de la console en action.

Émulateur, interpréteur et machine virtuelle

Quel est la différence entre ces 3 termes. On utilise le mot émulateur pour désigner un logiciel qui implémente le fonctionnement d'un circuit matériel, par exemple si on veut faire tourner un logiciel pour un MCU particulier mais qu'on a pas le MCU en main on peut le faire tourner à l'intérieur d'un émulateur logiciel qui fonctionne sur le PC. Ainsi l'environnement MPLABX offre des émulateurs pour chaque MCU PIC 8 bits vendu par Microchip. On peut donc tester un logiciel avant de le mettre en mémoire flash du MCU.

On utilise le terme interpréteur pour désigner le compilateur d'un langage de haut-niveau qui au lieu de générer du code binaire pour un CPU génère du code pour une machine virtuelle (bytecode) et exécute ce programme sur cette machine virtuelle. Par exemple Java et Python compile pour une machine virtuelle et non du binaire pour un microprocesseur.

Une machine virtuelle est un logiciel qui exécute du bytecode pour un modèle d'exécution particulier. Cette machine est semblable à un microprocesseur sauf qu'elle n'est pas gravé dans le silicium, d'où le qualificatif de virtuelle.

Par modèle d'exécution on entend l'ensemble des registres, de l'espace mémoire et des instructions que peut exécuter cette machine.

CHIP-8 et SCHIP sont des machines virtuelles qui partagent le modèle d'exécution suivant.

  • Une banque de 16 registres de 8 bits notés V0-VF. Le registre VF est utilisé pour sauvegarder l'indicateur de débordement (carry flag).
  • Un compteur ordinal pouvant adresser 4096 octets (12 bits)
  • Un pointeur de donnée pouvant adresser 4096 octets (12 bits)
  • Une minuterie de délais de 8 bits cadencé à 60Hertz.
  • Une générateur de tonalité avec compteur de duré de 8 bits cadencé à 60Hertz.
  • L'espace d'adressage mémoire est de 4096 octets, mais les programmes à exécuter doivent-être chargés à l'adresse 512 (0x200). Leur taille est donc limité à 3584 octets.
  • Le jeux d'instructions de la machine virtuelle est codé sur 16 bits
  • Le système possède une police de caractère hexadécimal 3x5 pixels.
  • Le système possède une police de caractère décimal de 8x10 pixels.
  • CHIP-8 a une capacité graphique de 64x32 pixels (mémoire vidéo 256 octets).
  • SCHIP a une capacité graphique de 128x64 pixels (mémoire vidéo de 1024 octets).
  • SCHIP a une compatilibilité ascendante avec CHIP-8 sauf pour l'instruction 0NNN (syscall).
  • SCHIP ajoute 10 instructions au jeux d'instructions de CHIP-8 qui a 35 instructions.
  • SCHIP possède une deuxième banque de 16 registres appellée RPL. Un transfert de données peut-être fait entre les 2 banques.
Si on fabriquait cette machine dans du silicium son diagramme bloc ressemblerais à ceci.

Jeux d'instructions de SCHIP

Dans la table ci-bas NNN représente un nombre de 12 bits en hexadécimal (000-FFF).
KK représente une constante de 8 bits en hexadécimal (00-FF).
X et Y représentent un registre V en hexadécimal (0-F).
Les instructions suivies d'un * sont spécifiques à SCHIP.
Les instructions suivies de ** sont spécifiques à CHIPcon.

OPCODEMnémoniqueDescription
00CN*SCD Ndéfile l'affichage vers le bas de N lignes.
00E0CLSEfface l'affichage.
00EERETQuitte une sous-routine.
00FB*SCRDéfile l'écran vers la droite de 4 pixels.
00FC*SCLDéfile l'écran vers la gauche de 4 pixels.
00FD*EXITFin de programme, quitte la machine virtuelle.
00FE*LOWDésactive le mode SCHIP, retour au mode CHIP-8 de 64x32 pixels. Instruction ignorée par CHIPcon.
00FF*HIGHActive le mode étendu, 128x64 pixels. Instruction ignorée par CHIPcon qui demeure toujours dans ce mode.
1NNNJP NNNSaute à l'adresse NNN.
2NNNCALL NNNExécute la sous-routine à l'adresse NNN.
3XKKSE VX, KKSaute l'instruction suivante si VX == KK
4XKKSNE VX, KKSaute l'instruction suivante si VX <> KK
5XY0SE VX, VYSaute l'instruction suivante si VX == VY
6XKKLD VX, KKVX := KK
7XKKADD VX, KKVX := VX + KK
8XY0LD VX, VYVX := VY
8XY1OR VX, VYVX := VX or VY
8XY2AND VX, VYVX := VX and VY
8XY3XOR VX, VYVX := VX xor VY
8XY4ADD VX, VYVX := VX + VY, VF := carry
8XY5SUB VX, VYVX := VX - VY, VF := not borrow
8XY6SHR VXVX := VX shr 1, VF := carry
8XY7SUBN VX, VYVX := VY - VX, VF := not borrow
8XYESHL VXVX := VX shl 1, VF := carry
9XY0SNE VX, VYSaute l'instruction suivante si VX <> VY
9XY1**TONE VX, VYFais entendre une note de la gamme tempérée. VX note entre 0-F. 0=DO4, F=RÉ5#. VY durée.
9XY2**PRT VX, VYimprime une chaîne texte à l'écran. Les coordonnées du coin supérieur gauche sont indiquées par VX,VY. Le texte est pointé par I. I est incrémenté.
9XY3**PIXI VX, VYInverse le pixel aux coordonnées indiquées par VX,VY.
9XY5**TONE VX, VY, WAITFais entendre une note de la gamme tempérée. VX note entre 0-F. 0=DO4, F=RÉ5#. VY durée. Attend la fin de la note avant de poursuivre.
ANNNLD I, NNNI := NNN
BNNNJP V0, NNNsaute à l'adresse NNN+V0
CXKKRND VX, KKVX := nombre aléatoire and KK
DXYN*DRW VX, VY, NAffiche un sprite de N-octets aux coordonnées d'écran VX, VY.
Le contenu du sprite se trouve à l'adresse débutan M(I).
VF := 1 si il y a collision.
Si N==0 indique un sprite de 16x16 pixels.
EX9ESKP VXSaute l'instruction suivante si la touche dont la valeur est indiquée dans VX est enfoncée.
EXA1SKNP VXSaute l'instruction suivante si la touche dont la valeur est indiquée dans VX n'est pas enfoncée.
FX07LD VX, DTVX := valeur de la minuterie délais.
FX0ALD VX, KAttend qu'une touche sois enfoncée et met sa valeur dans VX.
FX15LD DT, VXminuterie de délais := VX, elle est décrémentée jusqu'à zéro 60 fois par seconde.
FX18LD ST, VXminuterie son := VX, La minuterie est décrémentée, le son s'arrête lorsqu'elle atteint zéro.
FX1EADD I, VXI := I + VX
FX29LD F, VXVX contient une valeur entre 0 et 15. La valeur du registre I est ajusté au début du sprite qui représente ce caractère dans la table 3x5.
FX30*LD LF, VXVX contient une valeur entre 0 et 9. La valeur du registre I est ajusté au début du sprite qui représente ce caractère dans la table 8x10.
FX33LD B, VXMet à l'adresse M(I)..M(I+2) la valeur BCD du nombre qui est dans VX.
FX55LD [I], VXEnregistres les valeurs des registres V0..VX dans la mémoire RAM en débutant à l'adresse M(I).
FX65LD VX, [I]Charge les V0..VX à partir de la mémoire RAM en débutant à l'adresse M(I).
FX75*LD R, VXSauvegarde les registres V0..VX dans la banque de registres RPL.
FX85*LD VX, RCharge les registres V0..VX à partir des registres RPL.

Implémentation de la VM SCHIP sur CHIPcon.

Pour suivre cette description référez-vous au dépôt github du projet CHIPcon. tout les fichiers y sont.

Cette machine virtuelle n'ayant que 43 codes opérationnels est simple à implémenter. Les états du modèle d'exécution sauf pour la mémoire RAM sont rassemblés dans une seule variable appellée vms. Le type de donnée qui définie cette structure est déclaré dans le fichier d'entête chip8.h et le code 'C' de la machine est dans le fichier chip8.c.


// structure de donnée définissant le modèle d'exécution de la VM
typedef struct vm_state{
 uint16_t pc;  // compteur ordinal
 uint16_t ix;  // pointeur de données
 uint8_t  sp;  // pointeur de la pile
 uint8_t  var[16]; // banque de registres
 uint8_t  rpl[16]; // banque de registres SCHIP
 union {
  uint16_t opcode; // dernier code machine exécuté 
 struct{ 
  uint8_t b1;  // octet fort du code
  uint8_t b2;  // octet faible du code
  };
 };
 uint16_t stack[32];  // pile des retours
 uint8_t  src_mem:1 ; // indicateur de source du sprite
 uint8_t  debug:1;    // pour support déboguage
 uint8_t  trace:1;    // pour support déboguage
 }vm_state_t;

La fonction uint8_t schip(uint8_t flags) exécute le code qui est enregistré dans la SRAM à partir de l'adresse 0x200. Deux octets de code sont lues pour chaque instruction. Comme le code opérationnel est répartie dans 2 champs séparés, il y a d'abord une phase appelée décodeur d'instruction qui rassemble les 2 champs dans la variable uint16_t code. code est ensuite utilisé par le switch de la phase exécution. Il s'agit d'une organisation classique pour une machine virtuelle. Il n'y a pas de difficulté particulière, une simple lecture du fichier chip8.c devrait permettre de comprendre le fonctionnement de la machine virtuelle.

La VM transige avec l'affichage par les interfaces des modules tvout et text, avec l'unité son par l'interface de celui de tone, avec le clavier via l'interface de keypad et avec la mémoire sram par l'interface du module sram.


liens

CHIPcon partie 1
dépot githup du projet.
page www.chip.com rassemblant beauceaup d'information sur CHIP-8/SCHIP/MegaCHIP
article de wikipedia sur CHIP-8

Aucun commentaire:

Publier un commentaire