Chip8仿真器Bug

时间:2018-03-20 01:28:59

标签: javascript emulation chip-8

我正在使用JavaScript创建一个Chip8模拟器,而且我已经完成了很多工作。问题是,它在前几秒内工作,然后陷入无限循环的操作码,并且永远不会爆发。

检查出来:http://output.jsbin.com/mopireb/

它呈现两个拨片,得分,然后当你检查控制台时(我记录所有操作码和寄存器,这3个代码永远循环。

f007
3000
121a

我做错了什么?

这是我的源代码(到目前为止可怕的优化,但以后会有这样做):

<div id="memory" />
<input type="text" size="40" onkeypress="trackkey(event)"></input><br />
<canvas id="screen" width="640" height="320" style="border:1px solid #000000;">
</canvas>
<script>
  function trackkey(event) {
  var x = event.which || event.keyCode;
  var y=0;
//    alert(x);
    switch(x){
      case 49://1, 1
        y=1;
        break;
      case 50://2, 2
        y=2;
        break;
      case 51://3, 3
        y=3;
        break;
      case 52://4, 0xc
        y=0xc;
        break;
      case 113://q, 4
        y=4;
        break;
      case 119://w, 5
        y=5;
        break;
      case 101://e, 6
        y=6;
        break;
      case 114://r, 0xD
        y=0xD;
        break;
      case 97://a, 7
        y=7;
        break;
      case 115://s, 8
        y=8;
        break;
      case 100://d, 9
        y=9;
        break;
      case 102://f, 0xe
        y=0xE;
        break;
      case 122://z, 0xA
        y=0xA;
        break;
      case 120://x, 0 
        y=0;
        break;
      case 99://c, 0xB
        y=0xB;
        break;
      case 122://v, 0xF
        y=0xF;
        break;

      default:
        y=50;
        break;
    }
    y-=1;
    if(y!=49){
        pressedKey=y;keyDown=true;
        for(var i=0;i<16;i++){
          if(i!=y){
          key[i]=0;
          }else{key[i]=1;}

  }
    }
  }
  //specs and variables
  var opcode;
  var memory=new Array(4096);
  var V=new Array(16);
  var I;
  var pc;
  var buffer;
  var gfx=new Array(64*32);
  var delay_timer;
  var sound_timer;
  var stack=new Array(16);
  var sp;
  var key=new Array(16);
  var drawFlag;
  var text=[
  0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
  0x20, 0x60, 0x20, 0x20, 0x70, // 1
  0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
  0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
  0x90, 0x90, 0xF0, 0x10, 0x10, // 4
  0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
  0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
  0xF0, 0x10, 0x20, 0x40, 0x40, // 7
  0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
  0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
  0xF0, 0x90, 0xF0, 0x90, 0x90, // A
  0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
  0xF0, 0x80, 0x80, 0x80, 0xF0, // C
  0xE0, 0x90, 0x90, 0x90, 0xE0, // D
  0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
  0xF0, 0x80, 0xF0, 0x80, 0x80  // F
  ];
  //game loop
  main();

  function main(){
    //setupGraphics();
    //setupInput();
    setKeys();
    loadGame();
    initialize();
    drawGraphics();
    setInterval(gameLoop, 16);
  }

  function gameLoop(){

    emulateCycle();
    if(drawFlag){
      drawGraphics();
      setKeys();//store key press state (press and release)
    }

  }

  //store key press state
  function setKeys(){
  }

  //initialize
  function initialize(){
    pc=0x200;
    opcode=0;
    I=0;
    sp=0;
    clear();
    for(var i=0;i<0x10;i++){
      V[i]=0;
    }
    for(var i=0;i<80;i++){
      memory[i]=text[i];
    }
    for(var i=0;i<buffer.length;i++){
      memory[i+512]=buffer[i];
    }

    delay_timer=0;
    sound_timer=0;
  }

  //load program
  function loadGame(){
    buffer=[106,2,107,12,108,63,109,12,162,234,218,182,220,214,110,0,34,212,102,3,104,2,96,96,240,21,240,7,48,0,18,26,199,23,119,8,105,255,162,240,214,113,162,234,218,182,220,214,96,1,224,161,123,254,96,4,224,161,123,2,96,31,139,2,218,182,141,112,192,10,125,254,64,0,125,2,96,0,96,31,141,2,220,214,162,240,214,113,134,132,135,148,96,63,134,2,97,31,135,18,70,2,18,120,70,63,18,130,71,31,105,255,71,0,105,1,214,113,18,42,104,2,99,1,128,112,128,181,18,138,104,254,99,10,128,112,128,213,63,1,18,162,97,2,128,21,63,1,18,186,128,21,63,1,18,200,128,21,63,1,18,194,96,32,240,24,34,212,142,52,34,212,102,62,51,1,102,3,104,254,51,1,104,2,18,22,121,255,73,254,105,255,18,200,121,1,73,2,105,1,96,4,240,24,118,1,70,64,118,254,18,108,162,242,254,51,242,101,241,41,100,20,101,0,212,85,116,21,242,41,212,85,0,238,128,128,128,128,128,128,128,0,0,0,0,0];
  }

  //clear display
  function clear(){
    for(var i=0;i<gfx.length;i++){
      gfx[i]=0;
    }
  }

  //draw
  function draw(x, y, h){
    var coordinates;
    coordinates=y*64+x;
    for(var j=0;j<h;j++){
      for(var i=0;i<8;i++){
        if((coordinates+i+64*j)%64!=0){
          if(gfx[coordinates+i+64*j]==1&&parseInt(parseInt(memory[(I+j)]).toString(2)[i])==0){V[0xF]=1;}else{V[0xF]=0;}
        gfx[coordinates+i+64*j]=parseInt(parseInt(memory[(I+j)]).toString(2)[i]);

        }else{i=8;}
      }
    }
    drawFlag=true;
  }

  //draw graphics
  function drawGraphics(){
    V[0xF]=0;
    for(var i=0;i<gfx.length;i++){
        var c = document.getElementById("screen");
        var ctx = c.getContext("2d");
        if(ctx.getImageData(i%64*10, Math.floor(i/64)*10, 1, 1).data[0]!=0&&gfx[i]!=0){V[0xF]=1;}else{V[0xF]=0;}
        ctx.clearRect(0, 0, ctx.width, ctx.height);
        ctx.beginPath();
        if(gfx[i]==1){ctx.fillStyle = "white";}else{ctx.fillStyle = "black";}
        ctx.fillRect(i%64*10, Math.floor(i/64)*10, 10, 10);
        ctx.stroke();
      }
    drawFlag=false;
  }

  //emulate cycle
  function emulateCycle(){
    console.log(V);
    debugger;
    opcode=0;
    opcode = memory[pc] << 8 | memory[pc + 1];
    switch(opcode&0xF000){
      //0x0NNN not needed
      case 0x0000: //0x00E0 and 0x00EE
        switch(opcode&0x000F){
          case 0x0000:
            clear();//clear display
            drawFlag=true;
            pc+=2;
            break;
          case 0x000E:
            //return from subroutine
            pc=stack[sp-1];
            sp=sp-1;
            pc+=2;
            break;
        }   
        break;
      case 0x1000://goto subroutine
        pc = opcode & 0x0FFF;
        break;
      case 0x2000://call subroutine
        stack[sp]=pc;
        sp++;
        pc=opcode & 0x0FFF;
        break;
      case 0x3000://skip next instruction if Vx==NN
        if(V[(opcode>>8)&0x000F]==opcode&0x00FF){
          pc+=2;
        }
        pc+=2;
        break;
      case 0x4000://skip next instruction if Vx!=NN
        if(V[(opcode>>8)&0x000F]!=opcode&0x00FF){
          pc+=2;
        }
        pc+=2;
        break;
      case 0x5000://skip next instruction if Vx==Vy
        if(V[(opcode>>8)&0x000F]==V[(opcode>>4)&0x000F]){
          pc+=2;
        }
        pc+=2;
        break;
      case 0x6000://set Vx to NN
        V[(opcode>>8)&0x000F]=opcode&0x00FF;
        //alert(V[(opcode>>8)&0x000F]);
        pc+=2;
        break;
      case 0x7000://Vx+=NN
        V[(opcode>>8)&0x000F]+=opcode&0x00FF;
        pc+=2;
        break;
      case 0x800F:
        switch(opcode&0x000F){
          case 0x0000://Vx=Vy
            V[(opcode>>8)&0x000F]=V[(opcode>>4)&0x000F];
            pc+=2;
            break;
          case 0x0001://Vx=Vx|Vy
            V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]|V[(opcode>>4)&0x000F];
            pc+=2;
            break;
          case 0x0002://Vx=Vx&Vy
            V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]&V[(opcode>>4)&0x000F];
            pc+=2;
            break;
          case 0x0003://Vx=Vx^Vy
            V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]^V[(opcode>>4)&0x000F];
            pc+=2;
            break;
          case 0x0004://Vx+=Vy
            if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
              V[0xF] = 1; //carry
            }else{
              V[0xF] = 0;
              V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
            } 
            pc+=2;
            break;
          case 0x0005://Vx-=Vy
            if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
              V[0xF] = 1; //carry
            }else{
              V[0xF] = 0;
              V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
            } 
            pc+=2;
            break;
          case 0x0006://Vx=Vy=Vy>>1
            V[0xF]=V[(opcode>>4)&0x000F]&0x000F;
            V[(opcode>>4)&0x000F]=V[(opcode>>4)&0x000F]>>1;
            V[(opcode>>8)&0x000F]=(opcode>>4)&0x000F;
            pc+=2;
            break;
          case 0x0007://Vx=Vy-Vx
            if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
              V[0xF] = 1; //carry
            }else{
              V[0xF] = 0;
              V[(opcode & 0x00F0) >> 4]=V[(opcode & 0x0F00) >> 8]-V[(opcode & 0x00F0) >> 4];
            } 
            pc+=2;
            break;
          case 0x000E://Vx=Vy=Vy<<1
            V[0xF]=V[(opcode & 0x0F00) >> 8] >> 7;
            V[(opcode>>4)&0x000F]=V[(opcode>>4)&0x000F]<<1;
            V[(opcode>>8)&0x000F]=V[(opcode>>4)&0x000F];
            pc+=2;
            break;
        }
        break;
      case 0x9000://if(Vx!=Vy){skip}
        if(V[(opcode>>8)&0x000F]!=V[(opcode>>4)&0x000F]){
          pc+=2;
        }
        pc+=2;
      case 0xA000://I=NNN
        I=opcode&0x0FFF;
        pc+=2;
        break;
      case 0xB000://I=NNN+V0
        pc=(opcode&0x0FFF)+V[0];
        break;
      case 0xC000://Vx=random&NN
        V[(opcode>>8)&0x000F]=Math.floor((Math.random() * 255))&((opcode)&0x00FF);
        pc+=2;
        break;
      case 0xD000://DXYN draw(Vx, Vy, N)
        draw(V[(opcode>>8)&0x000F], V[(opcode>>4)&0x000F], (opcode)&0x000F);
        pc+=2;
        break;
      case 0xE000://keypad
        switch(opcode & 0x00FF){// EX9E: Skips the next instruction if the key stored in VX is pressed
          case 0x009E:
            if(key[V[(opcode & 0x0F00) >> 8]] != 0){
              pc+=2;
            }else{}
            pc+=2;
            break;
          case 0x00A1:
            if(key[V[(opcode & 0x0F00) >> 8]] == 0){
              pc+=2;
            }else{}
            pc+=2;
            break;
        }
        break;
      case 0xF000:
        switch(opcode & 0x00FF){
          case 0x0007:
            V[(opcode>>8)&0x000F]=delay_timer;
            pc+=2;
            break;
          case 0x000A:
            if(keyDown==true){
                V[(opcode>>8)&0x000F]=pressedKey;pc+=2;
            }else{alert("PAUSE");}
            break;
          case 0x0015:
            delay_timer=V[(opcode>>8)&0x000F];
            pc+=2;
            break;
          case 0x0018:
            sound_timer=V[(opcode>>8)&0x000F];
            pc+=2;
            break;
          case 0x001E:
            I+=V[(opcode>>8)&0x000F]; 
            pc+=2;
            break;
          case 0x0029:
            I=V[(opcode>>8)&0x000F]*5;
            pc+=2;
            break;
          case 0x0033:
            memory[I]     = V[(opcode & 0x0F00) >> 8] / 100;
            memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
            memory[I + 2] = (V[(opcode & 0x0F00) >> 8] % 100) % 10;
            pc += 2;
            break;
          case 0x0055:
            for (var i = 0; i <= ((opcode & 0x0F00) >> 8); i+=2){
              memory[I + i] = V[i];
              I++;
            }
            pc+=2;
            break;
          case 0x0065:

            for (var i = 0; i <= ((opcode & 0x0F00) >> 8); i+=2){
              V[i] = (memory[I+i]<<8)&memory[I+(i+1)];
              I++;
            }
            pc += 2;
            break;
        }     
        break;
      default:
        console.log("UNSUPPORTED OPCODE- "+(opcode).toString(16));console.log("");
        break;
      }
    console.log(opcode.toString(16));
    if(delay_timer > 0){delay_timer-=1;}
    if(sound_timer > 0){if(sound_timer == 1){console.log("BEEP!");sound_timer-=1;}}
    keyDown=false;
    pressedKey=null;
  }

</script>

0 个答案:

没有答案