#include "cpu.h" void initialiserCpu() { //On initialise le tout Uint16 i=0; for(i=0;i0) cpu.compteurJeu--; /*if(cpu.compteurSon>0) cpu.compteurSon--;*/ } Uint16 recupererOpcode() { return (cpu.memoire[cpu.pc]<<8)+cpu.memoire[cpu.pc+1]; } Uint8 interpreterOpcode(Uint16 opcode) { Uint8 continuer=1; Uint8 b4,b3,b2,b1; b3=(opcode&(0x0F00))>>8; //on prend les 4 bits représentant X b2=(opcode&(0x00F0))>>4; //idem pour Y b1=(opcode&(0x000F)); //idem b4= recupererAction(opcode); switch(b4) { case 0:{ //Cet opcode n'est pas implémenté. break; } case 1:{ //00E0 efface l'écran. effacerEcran(); break; } case 2:{ //00EE revient du saut. if(cpu.nbrsaut>0) { cpu.nbrsaut--; cpu.pc=cpu.saut[cpu.nbrsaut]; } break; } case 3:{ //1NNN effectue un saut à l'adresse 1NNN. cpu.pc=(b3<<8)+(b2<<4)+b1; //on prend le nombre NNN (pour le saut) cpu.pc-=2; //on verra pourquoi à la fin break; } case 4:{ //2NNN appelle le sous-programme en NNN, mais on revient ensuite. cpu.saut[cpu.nbrsaut]=cpu.pc; //on reste là où on était if(cpu.nbrsaut<15) { cpu.nbrsaut++; } cpu.pc=(b3<<8)+(b2<<4)+b1; //on prend le nombre NNN (pour le saut) cpu.pc-=2; //on verra pourquoi à la fin break; } case 5:{ //3XNN saute l'instruction suivante si VX est égal à NN. if(cpu.V[b3]==((b2<<4)+b1)) { cpu.pc+=2; } break; } case 6:{ //4XNN saute l'instruction suivante si VX et NN ne sont pas égaux. if(cpu.V[b3]!=((b2<<4)+b1)) { cpu.pc+=2; } break; } case 7:{ //5XY0 saute l'instruction suivante si VX et VY sont égaux. if(cpu.V[b3]==cpu.V[b2]) { cpu.pc+=2; } break; } case 8:{ //6XNN définit VX à NN. cpu.V[b3]=(b2<<4)+b1; break; } case 9:{ //7XNN ajoute NN à VX. cpu.V[b3]+=(b2<<4)+b1; break; } case 10:{ //8XY0 définit VX à la valeur de VY. cpu.V[b3]=cpu.V[b2]; break; } case 11:{ //8XY1 définit VX à VX OR VY. cpu.V[b3]=cpu.V[b3]|cpu.V[b2]; break; } case 12:{ //8XY2 définit VX à VX AND VY. cpu.V[b3]=cpu.V[b3]&cpu.V[b2]; break; } case 13:{ //8XY3 définit VX à VX XOR VY. cpu.V[b3]=cpu.V[b3]^cpu.V[b2]; break; } case 14:{ //8XY4 ajoute VY à VX. VF est mis à 1 quand il y a un dépassement de mémoire (carry), et à 0 quand il n'y en pas. if((cpu.V[b3]+cpu.V[b2])>255) { cpu.V[0xF]=1; //cpu.V[15] } else { cpu.V[0xF]=0; //cpu.V[15] } cpu.V[b3]+=cpu.V[b2]; break; } case 15:{ //8XY5 VY est soustraite de VX. VF est mis à 0 quand il y a un emprunt, et à 1 quand il n'y a en pas. if((cpu.V[b3]>1); break; } case 17:{ //8XY7 VX = VY - VX. VF est mis à 0 quand il y a un emprunt et à 1 quand il n'y en a pas. if((cpu.V[b2]>7); cpu.V[b3]=(cpu.V[b3]<<1); break; } case 19:{ //9XY0 saute l'instruction suivante si VX et VY ne sont pas égaux. if(cpu.V[b3]!=cpu.V[b2]) { cpu.pc+=2; } break; } case 20:{ //ANNN affecte NNN à I. cpu.I=(b3<<8)+(b2<<4)+b1; break; } case 21:{ //BNNN passe à l'adresse NNN + V0. cpu.pc=(b3<<8)+(b2<<4)+b1+cpu.V[0]; cpu.pc-=2; break; } case 22:{ //CXNN définit VX à un nombre aléatoire inférieur à NN. cpu.V[b3]=(rand())%((b2<<4)+b1+1); break; } case 23:{ //DXYN dessine un sprite aux coordonnées (VX, VY). dessinerEcran(b1,b2,b3) ; break; } case 24:{ //EX9E saute l'instruction suivante si la clé stockée dans VX est pressée. if(cpu.touche[cpu.V[b3]]==1)//1 pressé, 0 relaché { cpu.pc+=2; } break; } case 25:{ //EXA1 saute l'instruction suivante si la clé stockée dans VX n'est pas pressée. if(cpu.touche[cpu.V[b3]]==0)//1 pressé, 0 relaché { cpu.pc+=2; } break; } case 26:{ //FX07 définit VX à la valeur de la temporisation. cpu.V[b3]=cpu.compteurJeu; break; } case 27:{ //FX0A attend l'appui sur une touche et stocke ensuite la donnée dans VX. continuer=attendAppui(b3); break; } case 28:{ //FX15 définit la temporisation à VX. cpu.compteurJeu=cpu.V[b3]; break; } case 29:{ //FX18 définit la minuterie sonore à VX. //cpu.compteurSon=cpu.V[b3]; break; } case 30:{ //FX1E ajoute VX à I. VF est mis à 1 quand il y a overflow (I+VX>0xFFF), et à 0 si tel n'est pas le cas. if((cpu.I+cpu.V[b3])>0xFFF) { cpu.V[0xF]=1; } else { cpu.V[0xF]=0; } cpu.I+=cpu.V[b3]; break; } case 31:{ //FX29 définit I à l'emplacement du caractère stocké dans VX. Les caractères 0-F (en hexadécimal) sont représentés par une police 4x5. cpu.I=cpu.V[b3]*5; break; } case 32:{ //FX33 stocke dans la mémoire le code décimal représentant VX (dans I, I+1, I+2). cpu.memoire[cpu.I]=(cpu.V[b3]-cpu.V[b3]%100)/100; cpu.memoire[cpu.I+1]=(((cpu.V[b3]-cpu.V[b3]%10)/10)%10); cpu.memoire[cpu.I+2]=cpu.V[b3]-cpu.memoire[cpu.I]*100-10*cpu.memoire[cpu.I+1]; break; } case 33:{ //FX55 stocke V0 à VX en mémoire à partir de l'adresse I. Uint8 i=0; for(i=0;i<=b3;i++) { cpu.memoire[cpu.I+i]=cpu.V[i]; } break; } case 34:{ //FX65 remplit V0 à VX avec les valeurs de la mémoire à partir de l'adresse I. Uint8 i=0; for(i=0;i<=b3;i++) { cpu.V[i]=cpu.memoire[cpu.I+i]; } break; } default: { //si ça arrive, il y un truc qui cloche break; } } cpu.pc+=2; //on passe au prochain opcode return continuer; } void dessinerEcran(Uint8 b1,Uint8 b2, Uint8 b3) { Uint8 x=0,y=0,k=0,codage=0,j=0,decalage=0; cpu.V[0xF]=0; for(k=0;k