public void clearDisplay() { if (display != null) { display.Source = Utli.loadBitmap(getScreenBitmap(blankScreenBuffer)); } }
void workerProgressChanged(object sender, ProgressChangedEventArgs e) { //update screen if (display != null) { display.Source = Utli.loadBitmap(getScreenBitmap(screenBuffer)); } }
public void connectDisplay(System.Windows.Controls.Image display) { this.display = display; if (display != null) { display.Source = Utli.loadBitmap(getScreenBitmap(screenBuffer)); } }
public string getAssemblyCode() { string outputLine = ""; ushort addr = (ushort)(Chip8.ROM_BASE_ADDR + addrOfInstruc); //add address outputLine = outputLine + addr.ToString("x2").ToUpper(); //add spaces outputLine += string.Join("", Enumerable.Repeat(' ', 4)); //add machine code outputLine = outputLine + Utli.getHighByte(opcode).ToString("x2").ToUpper() + " " + Utli.getLowerByte(opcode).ToString("x2").ToUpper(); //add spaces outputLine += string.Join("", Enumerable.Repeat(' ', 10)); //add assembly code outputLine = outputLine + mnemonicInstuc; return(outputLine); }
public bool debugStepRoutine() { cpuStep(); updateTimers(); display.Source = Utli.loadBitmap(getScreenBitmap(screenBuffer)); //break point check if (debugMode && (!cpuHalt)) { for (int j = 0; j < brkPtAddresses.Count(); j++) { if (pc == brkPtAddresses[j]) { return(true); } } } return(false); }
public void cpuStep() { //fetch instruction ushort opcode = (ushort)((mainMemory[pc] << 8) | mainMemory[pc + 1]); pc += 2; //decode and execute instruction switch (Utli.getUpperByteHighNibble(opcode)) { case 0x0: { if (Utli.getLowerByteHighNibble(opcode) == 0xE) { switch (Utli.getLowerByteLowNibble(opcode)) { case 0x0: // Clears the screen. Array.Clear(screenBuffer, 0, screenBuffer.Length); //drawflag = true; break; case 0xE: //Returns from a subroutine. pc = mainMemory[stackPtr]; stackPtr++; pc = (ushort)((mainMemory[stackPtr] << 8) | pc); stackPtr++; break; default: Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2")); break; } } else { if ((opcode & 0x0FFF) == 0) { Console.WriteLine("0NNN - Calls RCA 1802 program at address NNN. Not necessary for most ROMs."); } else { Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2")); } pc += 2; } } break; case 0x1: //Jumps to address NNN. pc = (ushort)(opcode & 0x0FFF); break; case 0x2: //Calls subroutine at NNN. stackPtr--; mainMemory[stackPtr] = Utli.getHighByte(pc); stackPtr--; mainMemory[stackPtr] = Utli.getLowerByte(pc); pc = (ushort)(opcode & 0x0FFF); break; case 0x3: //3XNN Skips the next instruction if VX equals NN. if (vRegs[Utli.getUpperByteLowNibble(opcode)] == Utli.getLowerByte(opcode)) { pc += 2; } break; case 0x4: //4XNN Skips the next instruction if VX doesn't equal NN. if (vRegs[Utli.getUpperByteLowNibble(opcode)] != Utli.getLowerByte(opcode)) { pc += 2; } break; case 0x5: //5XY0 Skips the next instruction if VX equals VY. if (vRegs[Utli.getUpperByteLowNibble(opcode)] == vRegs[Utli.getLowerByteHighNibble(opcode)]) { pc += 2; } break; case 0x6: //6XNN Sets VX to NN. vRegs[Utli.getUpperByteLowNibble(opcode)] = Utli.getLowerByte(opcode); break; case 0x7: //7XNN Adds NN to VX. vRegs[Utli.getUpperByteLowNibble(opcode)] += Utli.getLowerByte(opcode); break; case 0x8: { switch (Utli.getLowerByteLowNibble(opcode)) { case 0x0: // 8XY0 Sets VX to the value of VY. vRegs[Utli.getUpperByteLowNibble(opcode)] = vRegs[Utli.getLowerByteHighNibble(opcode)]; break; case 0x1: // 8XY1 Sets VX to VX or VY. vRegs[Utli.getUpperByteLowNibble(opcode)] |= vRegs[Utli.getLowerByteHighNibble(opcode)]; break; case 0x2: // 8XY2 Sets VX to VX and VY. vRegs[Utli.getUpperByteLowNibble(opcode)] &= vRegs[Utli.getLowerByteHighNibble(opcode)]; break; case 0x3: // 8XY3 Sets VX to VX xor VY. vRegs[Utli.getUpperByteLowNibble(opcode)] ^= vRegs[Utli.getLowerByteHighNibble(opcode)]; break; case 0x4: // 8XY4 Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't. { int carryCheck = vRegs[Utli.getUpperByteLowNibble(opcode)] + vRegs[Utli.getLowerByteHighNibble(opcode)]; if (carryCheck > 0xFF) { vRegs[0xF] = 1; } else { vRegs[0xF] = 0; } vRegs[Utli.getUpperByteLowNibble(opcode)] += vRegs[Utli.getLowerByteHighNibble(opcode)]; } break; case 0x5: //8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't. { if (vRegs[Utli.getLowerByteHighNibble(opcode)] > vRegs[Utli.getUpperByteLowNibble(opcode)]) { vRegs[0xF] = 0; } else { vRegs[0xF] = 1; } vRegs[Utli.getUpperByteLowNibble(opcode)] -= vRegs[Utli.getLowerByteHighNibble(opcode)]; } break; case 0x6: //8XY6 Shifts VX right by one. // VF is set to the value of the least significant bit of VX before the shift. { vRegs[0xF] = (byte)(0x1 & vRegs[Utli.getUpperByteLowNibble(opcode)]); vRegs[Utli.getUpperByteLowNibble(opcode)] >>= 1; } break; case 0x7: //8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. { if (vRegs[Utli.getUpperByteLowNibble(opcode)] > vRegs[Utli.getLowerByteHighNibble(opcode)]) { vRegs[0xF] = 0; } else { vRegs[0xF] = 1; } vRegs[Utli.getUpperByteLowNibble(opcode)] = (byte)(vRegs[Utli.getLowerByteHighNibble(opcode)] - vRegs[Utli.getUpperByteLowNibble(opcode)]); } break; case 0xE: //8XYE Shifts VX left by one. VF is set to the value of the // most significant bit of VX before the shift. { vRegs[0xF] = (byte)(vRegs[Utli.getUpperByteLowNibble(opcode)] >> 7); vRegs[Utli.getUpperByteLowNibble(opcode)] <<= 1; } break; default: Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2")); break; } } break; case 0x9: //9XY0 Skips the next instruction if VX doesn't equal VY.. if (vRegs[Utli.getUpperByteLowNibble(opcode)] != vRegs[Utli.getLowerByteHighNibble(opcode)]) { pc += 2; } break; case 0xA: //ANNN Sets Ireg to the address NNN. Ireg = (ushort)(opcode & 0x0FFF); break; case 0xB: //BNNN Jumps to the address NNN plus V0. pc = (ushort)((opcode & 0x0FFF) + vRegs[0x0]); break; case 0xC: //CXNN Sets VX to the result of a bitwise and operation on a random number and NN. Random rand = new Random(); byte random = (byte)rand.Next(0x00, 0xFF); ////0xFF is the maximum and the 0 is our minimum vRegs[Utli.getUpperByteLowNibble(opcode)] = (byte)(random & Utli.getLowerByte(opcode)); break; case 0xD: { //DXYN Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels. // Each row of 8 pixels is read as bit-coded starting from memory location Ireg; // Ireg value doesn’t change after the execution of this instruction. // As described above, VF is set to 1 if any screen pixels are flipped from set to unset when the sprite is drawn, // and to 0 if that doesn’t happen int xCor = vRegs[Utli.getUpperByteLowNibble(opcode)]; int yCor = vRegs[Utli.getLowerByteHighNibble(opcode)]; int nHeight = Utli.getLowerByteLowNibble(opcode); vRegs[0xF] = 0; for (int i = yCor; i < (yCor + nHeight); i++) { Byte pixel = mainMemory[Ireg + (i - yCor)]; for (int j = xCor; j < (xCor + 8); j++) { int pixelVal = (0x1 & (pixel >> ((xCor + 7) - j))); if (pixelVal == 0x1) { if (screenBuffer[(i * SCREEN_WIDTH) + j] == 1) { vRegs[0xF] = 1; } screenBuffer[(i * SCREEN_WIDTH) + j] ^= 1; } } } //drawflag = true; } break; case 0xE: { switch (Utli.getLowerByte(opcode)) { case 0x9E: //EX9E Skips the next instruction if the key stored in VX is pressed. if (gamePad[vRegs[Utli.getUpperByteLowNibble(opcode)]] == 1) { pc += 2; } break; case 0xA1: //EXA1 Skips the next instruction if the key stored in VX isn't pressed. if (gamePad[vRegs[Utli.getUpperByteLowNibble(opcode)]] != 1) { pc += 2; } break; default: Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2")); break; } } break; case 0xF: { switch (Utli.getLowerByte(opcode)) { case 0x07: //FX07 Sets VX to the value of the delay timer. vRegs[Utli.getUpperByteLowNibble(opcode)] = delayTimer; break; case 0x0A: //FX0A A key press is awaited, and then stored in VX. { bool keyPressed = false; for (int i = 0; i < gamePad.Length; i++) { if (gamePad[i] == 1) { keyPressed = true; i = gamePad.Length + 1; //end loop } } if (!keyPressed) { pc -= 2; } } break; case 0x15: // FX15 Sets the delay timer to VX. delayTimer = vRegs[Utli.getUpperByteLowNibble(opcode)]; break; case 0x18: // FX18 Sets the sound timer to VX. soundTimer = vRegs[Utli.getUpperByteLowNibble(opcode)]; break; case 0x1E: //FX1E Adds VX to Ireg. Ireg += vRegs[Utli.getUpperByteLowNibble(opcode)]; break; case 0x29: //FX29 Sets Ireg to the location of the sprite for the character in VX. // Characters 0-F (in hexadecimal) are represented by a 4x5 font. Ireg = (ushort)(vRegs[Utli.getUpperByteLowNibble(opcode)] * 5); break; case 0x33: //FX33 Stores the binary-coded decimal representation of VX, //with the most significant of three digits at the address in I, //the middle digit at I plus 1, and the least significant digit at I plus 2. mainMemory[Ireg] = (byte)(vRegs[Utli.getUpperByteLowNibble(opcode)] / 100); mainMemory[Ireg + 1] = (byte)((vRegs[Utli.getUpperByteLowNibble(opcode)] / 10) % 10); mainMemory[Ireg + 2] = (byte)((vRegs[Utli.getUpperByteLowNibble(opcode)] % 100) % 10); break; case 0x55: //FX55 Stores V0 to VX (including VX) in memory starting at address Ireg. //I is set to I + X + 1 after operation for (int i = 0; i <= Utli.getUpperByteLowNibble(opcode); i++) { mainMemory[Ireg + i] = vRegs[i]; } Ireg = (ushort)(Ireg + Utli.getUpperByteLowNibble(opcode) + 1); break; case 0x65: //FX65 Fills V0 to VX (including VX) with values from memory starting at address Ireg. for (int i = 0; i <= Utli.getUpperByteLowNibble(opcode); i++) { vRegs[i] = mainMemory[Ireg + i]; } Ireg = (ushort)(Ireg + Utli.getUpperByteLowNibble(opcode) + 1); break; default: Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2")); break; } } break; default: Console.WriteLine("Unimplemented Opcode - " + "0x" + opcode.ToString("x2")); break; } }
public string getOpcodeStringFormat() { return(Utli.getHighByte(opcode).ToString("x2").ToUpper() + " " + Utli.getLowerByte(opcode).ToString("x2").ToUpper()); }