// Outputs the current Opcode data, and the function it has been translated to. public void displayOpCodeTranslation(OpCodeStruct data, string translation) { if (displayTranslation.Checked) { Invoke(new Action(() => { TranslationOutput.Items.Add(data.ToString() + " => " + translation); })); } }
private void skip_if_X_equals_NN(OpCodeStruct data) { displayOpCode(data, "Skip instruction if " + data.X + " is: " + data.NN); if (_registers[data.X] == data.NN) { skip_instruction(); } }
private void skip_if_X_not_equals_Y(OpCodeStruct data) { displayOpCode(data, "Skip instruction if " + data.X + " is not: " + data.Y); if (_registers[data.X] != _registers[data.Y]) { skip_instruction(); } }
// Makes a beeping sound for the specified amount of time. private void beep(OpCodeStruct data) { int duration = (int)(_registers[data.X] * (1000f / 60)); displayOpCode(data, "Play BEEP sound effect for: " + duration + "Seconds"); Console.Beep(500, duration); Console.WriteLine("Sound was set to: {0}", _registers[data.X]); }
// Skips the next instruction if a certain key is pressed. private void skip_on_key(OpCodeStruct data) { displayOpCode(data, "Skip Instruction if key specified @ Register[" + data.X + "] is pressed."); if ((if_key_pressed(data) && _pressedKeys.Contains(_registers[data.X])) || (!if_key_pressed(data) && !_pressedKeys.Contains(_registers[data.X]))) { skip_instruction(); } }
// Loads all registers from the address register. private void reg_load(OpCodeStruct data) { displayOpCode(data, "Load Register values from RAM for Registers 0-" + data.X); for (var i = 0; i <= data.X; i++) { _registers[i] = _ram[_addressCounter + i]; } updateRegistersRange(0, data.X); }
// Saves all registers to the address register. private void reg_dump(OpCodeStruct data) { displayOpCode(data, "Save Register values into RAM for Registers 0-" + data.X); for (var i = 0; i <= data.X; i++) { _ram[_addressCounter + i] = _registers[i]; } updateRamRange(_addressCounter, _addressCounter + data.X); }
// Stores a binary decimal into ram private void set_BCD(OpCodeStruct data) { displayOpCode(data, "Store Binary Decimal " + _registers[data.X] + " into RAM @" + _addressCounter); _ram[_addressCounter] = (byte)((_registers[data.X] / 100) % 10); _ram[_addressCounter + 1] = (byte)((_registers[data.X] / 10) % 10); _ram[_addressCounter + 2] = (byte)((_registers[data.X]) % 10); updateRamRange(_addressCounter, _addressCounter + 2); }
// Jumps to the subroutine private void call_subroutine_NNN(OpCodeStruct data) { // Push the current Program counter onto the stack push(_programCounter); // Changes program counter to target the subroutine. _programCounter = data.NNN; updateProgramCounter(_programCounter); displayOpCode(data, "Jump to subroutine: " + _programCounter); }
// Draws a specified sprite to the 'Screen' Object. private void draw_sprite(OpCodeStruct data) { var spriteX = _registers[data.X]; var spriteY = _registers[data.Y]; displayOpCode(data, "Draw Sprite to Screen at X:" + data.X + ", Y:" + data.Y); // Write any pending clears _screen.writePendingClears(); // Clears the significant bit storage register. _registers[0xF] = 0; updateRegisters(0xF, _registers[0xF]); for (int i = 0; i < data.N; i++) { // Selects line of the sprite to render var spriteLine = _ram[_addressCounter + i]; for (var bit = 0; bit < 8; bit++) { int x_axis = (spriteX + bit) % _screenWidth; int y_axis = (spriteY + i) % _screenHeight; var spriteBit = ((spriteLine >> (7 - bit)) & 1); var oldBit = _screen.getPixel(x_axis, y_axis) ? 1 : 0; if (oldBit != spriteBit) { _screen.setUpdateNeeded(); } // New bit is XOR of existing and new. var newBit = oldBit ^ spriteBit; if (newBit != 0) { _screen.setPixel(x_axis, y_axis); } else // Otherwise write a pending clear { _screen.setPendingClear(x_axis, y_axis); } // If we wiped out a pixel, set flag for collission. if (oldBit != 0 && newBit == 0) { _registers[0xF] = 1; } updateRegisters(0xF, _registers[0xF]); } } }
private void add_X(OpCodeStruct data) { displayOpCode(data, "Register[" + data.X + "] += " + data.NN); try { _registers[data.X] += data.NN; updateRegisters(data.X, data.NN); } catch (OverflowException) { Console.WriteLine("OVERFLOW EXCEPTION: {0} > Size of Register space allocated.", data.X); } }
// Will be called repeatedly by the game loop until the desired key is pressed to progress the program counter. private void get_key(OpCodeStruct data) { displayOpCode(data, "Stores pressed key in Register[" + data.X + "] if pressed, otherwise skips next instruction."); if (_pressedKeys.Count > 0) { _registers[data.X] = _pressedKeys.First(); updateRegisters(data.X, _pressedKeys.First()); } else { _programCounter -= 2; updateProgramCounter(_programCounter); } }
/* * OPCODE FUNCTIONS: */ private void clear_or_return(OpCodeStruct data) { // Clears screen if (data.NN == 0xE0) { _screen.clear(); displayOpCode(data, "Clear Screen"); } // Returns subroutine from the stack else if (data.NN == 0xEE) { _programCounter = pop(); updateProgramCounter(_programCounter); displayOpCode(data, "Return subroutine: " + _programCounter); } }
// Activate Miscilanious Opcode private void run_misc_op(OpCodeStruct data) { switch (data.NN) { case 0x07: get_delay(data); break; case 0x0A: get_key(data); break; case 0x15: set_delay_timer(data); break; case 0x18: Task.Factory.StartNew(() => beep(data)); break; case 0x1E: add_x_to_address_register(data); break; case 0x29: set_address_register_for_char(data); break; case 0x33: set_BCD(data); break; case 0x55: reg_dump(data); break; case 0x65: reg_load(data); break; default: Console.WriteLine((string)("ERROR: NO MISC OP_CODE FOR:" + data)); break; } }
private bool if_key_pressed(OpCodeStruct data) { bool key_pressed; if (data.NN == 0x9E) { key_pressed = true; } else if (data.NN == 0xA1) { key_pressed = false; } else { key_pressed = false; Console.WriteLine("ERROR: Key not pressed, but received unexpected value."); } return(key_pressed); }
public void Process_OpCode() { // Fetches OpCode var opCode = (ushort)(_ram[_programCounter++] << 8 | _ram[_programCounter++]); updateProgramCounter(_programCounter); // Decodes the OpCode var code = new OpCodeStruct() { OpCode = opCode, NNN = (ushort)(opCode & 0x0FFF), NN = (byte)(opCode & 0x00FF), N = (byte)(opCode & 0x000F), X = (byte)((opCode & 0x0F00) >> 8), Y = (byte)((opCode & 0x00F0) >> 4), }; // Excecutes the OpCode _opCodes[(byte)(opCode >> 12)](code); }
// Jumps to the localtion specified in the current OpCode's nnn byte. private void jump_to_NNN(OpCodeStruct data) { _programCounter = data.NNN; updateProgramCounter(_programCounter); displayOpCode(data, "Jump to instruction at: " + _programCounter); }
/* * MISC OPERATIONS: */ // Sets register to current value of the delay timer private void get_delay(OpCodeStruct data) { displayOpCode(data, "Get Delay Timer: Register[" + data.X + "] = " + _delayTimer); _registers[data.X] = _delayTimer; updateRegisters(data.X, _delayTimer); }
private void set_delay_timer(OpCodeStruct data) { // TODO: Add GUI Component for tracking the delay Timer value? _delayTimer = _registers[data.X]; displayOpCode(data, "Delay Timer = Register[" + data.X + "] = " + _delayTimer); }
// &s a random integer between 0 and 256with NN private void set_X_rand(OpCodeStruct data) { _registers[data.X] = (byte)(_random.Next(0, 256) & data.NN); updateRegisters(data.X, _registers[data.X]); displayOpCode(data, "Set Register[" + data.X + "] = randomInt(256) bitwise AND by" + data.NN); }
// Just to the value in the register offset by NNN value private void jump_offset_by_NNN(OpCodeStruct data) { displayOpCode(data, "Jump to Register[" + data.NNN + "]"); _programCounter = (ushort)(_registers[0] + data.NNN); updateProgramCounter(_programCounter); }
private void set_adress_counter(OpCodeStruct data) { displayOpCode(data, "Address Counter = " + data.NNN); _addressCounter = data.NNN; updateAddressCounter(_addressCounter); }
private void add_x_to_address_register(OpCodeStruct data) { displayOpCode(data, "Address Counter += Register[" + data.X + "]"); _addressCounter += _registers[data.X]; updateAddressCounter(_addressCounter); }
private void math_operation(OpCodeStruct data) { // Use the opcode's N byte to determine which mathematic operation to perform with X & Y. switch (data.N) { case 0x0: //Assign: Set X to Y displayOpCode(data, "Register[" + data.X + "] = Register[" + data.NN + "]"); _registers[data.X] = _registers[data.Y]; updateRegisters(data.X, _registers[data.X]); break; case 0x1: // BitOp: Set X = X | Y (bitwise OR) displayOpCode(data, "Register[" + data.X + "] = Bitwise OR of Register[" + data.NN + "] and Register[" + data.Y + "]"); _registers[data.X] |= _registers[data.Y]; updateRegisters(data.X, _registers[data.X]); break; case 0x2: // BitOp: Sets X = X & Y (bitwise AND) displayOpCode(data, "Register[" + data.X + "] = Bitwise AND of Register[" + data.NN + "] and Register[" + data.Y + "]"); _registers[data.X] &= _registers[data.Y]; updateRegisters(data.X, _registers[data.X]); break; case 0x3: // BitOP: Sets X = X xor Y displayOpCode(data, "Register[" + data.X + "] = Bitwise XOR of Register[" + data.NN + "] and Register[" + data.Y + "]"); _registers[data.X] ^= _registers[data.Y]; updateRegisters(data.X, _registers[data.X]); break; case 0x4: // Math: Sets X += Y displayOpCode(data, "Register[" + data.X + "] += " + data.Y); _registers[0xF] = (byte)(_registers[data.X] + _registers[data.Y] > 0xFF ? 1 : 0); _registers[data.X] += _registers[data.Y]; updateRegisters(0xF, _registers[0xF]); updateRegisters(data.X, _registers[data.X]); break; case 0x5: // Math: X -= Y displayOpCode(data, "Register[" + data.X + "] -= " + data.Y); _registers[0xF] = (byte)(_registers[data.X] > _registers[data.Y] ? 1 : 0); _registers[data.X] -= _registers[data.Y]; updateRegisters(0xF, _registers[0xF]); updateRegisters(data.X, _registers[data.X]); break; case 0x6: // BitOp: Stores the least significant bit of the value of register position X at position 0xF in ram, then shifts value of register @ position X to the right by 1. displayOpCode(data, "Bit shift value of Register[" + data.X + "] to the Right & store lsb in Register[0xF]"); _registers[0xF] = (byte)((_registers[data.X] & 0x1) != 0 ? 1 : 0); _registers[data.X] /= 2; // Bit shift right. updateRegisters(0xF, _registers[0xF]); updateRegisters(data.X, _registers[data.X]); break; case 0x7: //Math: Y = Y - X displayOpCode(data, "Register[" + data.X + "] = " + data.Y + " - " + data.X); _registers[0xF] = (byte)(_registers[data.Y] > _registers[data.X] ? 1 : 0); _registers[data.Y] -= _registers[data.X]; updateRegisters(0xF, _registers[0xF]); updateRegisters(data.Y, _registers[data.Y]); break; case 0xE: // BitOp: Stores the least significant bit of the value of register position X at position 0xF in ram, then shifts value of register @ position X to the left by 1. displayOpCode(data, "Bit shift value of Register[" + data.X + "] to the Left & store lsb in Register[0xF]"); _registers[0xF] = (byte)((_registers[data.X] & 0xF) != 0 ? 1 : 0); _registers[data.X] *= 2; // Bit shift left. updateRegisters(0xF, _registers[0xF]); updateRegisters(data.X, _registers[data.X]); break; default: Console.WriteLine("ERROR: No valid Math Operation for case: {0}", data.N); break; } }
// Sets the address register to the current location of the 'font' sprite for the sepcified character. private void set_address_register_for_char(OpCodeStruct data) { displayOpCode(data, "Set Address Counter to location of font sprite: " + _registers[data.X]); _addressCounter = (ushort)(_registers[data.X] * 5); updateAddressCounter(_addressCounter); }
private void set_X(OpCodeStruct data) { _registers[data.X] = data.NN; updateRegisters(data.X, data.NN); displayOpCode(data, "Set Register[" + data.X + "] = " + data.NN); }