#include "vcpu.h" #include "mem.h" #include "screen.h" #include <stdio.h> #include <stdlib.h> #include <time.h> // Current VCPU state VCPU_State State; void VCPUInit(){ State.PC=ADDR_ROM; State.S=0; srand(time(NULL)); } void VCPUFetch(){ unsigned char byte[2]; MemRead(byte,2,State.PC); // Little indian to -1 no +1 State.opcode=byte[0]; State.opcode=State.opcode<<8; State.opcode=State.opcode | byte[1]; State.PC+=2; } void VCPUDecode(){ State.X=(State.opcode>>8) & 0xF; State.Y=(State.opcode>>4) & 0xF; State.N=State.opcode & 0xF; State.NN=State.Y; State.NN=State.NN<<4; State.NN=State.NN | State.N; State.NNN=State.opcode&0x0FFF; } void VCPUExecute(){ // VCPUDump(); switch(State.opcode >> 12){ case 0x0: // Clear screen or return from subroutine if(State.N == 0){ // Clear screen ScreenClear(); } else { // Return from subroutine State.PC=State.stack[State.S]; State.S--; } break ;; case 0x1: // Jump State.PC=State.NNN; break ;; case 0x2: // Call State.S++; State.stack[State.S]=State.PC; State.PC=State.NNN; break ;; case 0x3: // SE: VX, byte if(State.V[State.X]==State.NN) State.PC+=2; break; ;; case 0x4: // SNE: VX, byte if(State.V[State.X]!=State.NN) State.PC+=2; break; ;; case 0x5: // SE: VX, VY if(State.V[State.X]==State.V[State.Y]) State.PC+=2; break; ;; case 0x6: State.V[State.X]=State.NN; break ;; case 0x7: State.V[State.X]+=State.NN; break ;; case 0x8: // Register operations switch(State.N){ case 0x1: // VX = VX OR VY State.V[State.X]=State.V[State.X] | State.V[State.Y]; break; ;; case 0x2: // VX = VX AND VY State.V[State.X]=State.V[State.X] & State.V[State.Y]; break; ;; case 0x3: // VX = VX XOR VY State.V[State.X]=State.V[State.X] ^ State.V[State.Y]; break; ;; case 0x4: // VX = VX + VY if(State.V[State.X] + State.V[State.Y] > 255) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=(State.V[State.X] + State.V[State.Y]) & 0xFF; break; ;; case 0x5: // VX = VX - VY if(State.V[State.X] > State.V[State.Y]) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] - State.V[State.Y]; break; ;; case 0x6: // VX = VX SHR 1 if(State.V[State.X] & 0x1 == 1) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] >> 1; break; ;; case 0x7: // VX = VY - VX if(State.V[State.X] < State.V[State.Y]) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.Y] - State.V[State.X]; break; ;; case 0xE: // VX = VX SHL 1 if(State.V[State.X] >> 15 == 1) State.V[REG_FLAG]=1; else State.V[REG_FLAG]=0; State.V[State.X]=State.V[State.X] << 1; break; ;; } break ;; case 0x9: // SNE: VX, VY if(State.V[State.X]!=State.V[State.Y]) State.PC+=2; break; ;; case 0xA: State.I=State.NNN; break ;; case 0xB: State.PC=State.V[0]+State.NNN; break ;; case 0xC: unsigned short n = rand() % 255 + 1; State.V[State.X]=n & State.NN; break ;; case 0xD: // Draw a sprite int X=State.V[State.X]%63; int Y=State.V[State.Y]%31; State.V[REG_FLAG]=0; // Set flag to 0 int width,height; ScreenWH(&width,&height); for(char row=0;row<State.N;row++){ // Stop if row out of screen if(Y+row>=height) break; char sprite; MemRead(&sprite,1,State.I+row); // Load sprite // Draw sprite for(int shift=0;shift<8;shift++){ // Stop if column is out of screen if(X+shift >= width) break; if(ScreenPixelApply(X+shift,Y+row,(sprite>>(7-shift))&0x1)) State.V[REG_FLAG]=1; } } break; ;; case 0xE: // TODO break;; case 0xF: switch(State.NN){ case 0x07: // Get timer State.V[State.X]=State.DT; break; ;; case 0x0A: // TODO break; ;; case 0x15: // Set timer State.DT=State.V[State.X]; break; ;; case 0x18: // Set sound timer State.ST=State.V[State.X]; break; ;; case 0x1E: // I = I + VX State.I=State.I+State.V[State.X]; break; ;; case 0x29: // TODO break; ;; case 0x33: // TODO break; ;; case 0x55: MemCopy(State.V,0xF,State.I); break; ;; case 0x65: MemRead(State.V,0xF,State.I); break; ;; } break; ;; } } void VCPUDump(){ printf("opcode: 0x%04x\n",State.opcode&0xFFFF); printf("X: 0x%01x\n",State.X); printf("Y: 0x%01x\n",State.Y); printf("N: 0x%01x\n",State.N); printf("NN: 0x%02x\n",State.NN); printf("NNN: 0x%03x\n",State.NNN); }