public void _2nnn_CALL() { var instructions = new byte[] { 0x21, 0xEF }; var expectedAddress = (ushort)(0x21EF & 0x0FFF); var stackModule = new StackModule(); var chip = CHIP8Factory.GetChip8(stack: stackModule); chip.LoadProgram(instructions); chip.Tick += (c, e) => { chip.Stop(); }; chip.Start(); var programCounter = GetProgramCounter(chip); Assert.Equal(expectedAddress, programCounter); var itemOnStack = stackModule.Pop(); // Stack should have the program counter which has only moved up one past the start at 512 Assert.Equal(514, itemOnStack); }
public void _8xy3_XOR_vx_vy(byte x, byte y) { /* * 8xy3 - Performs a bitwise exclusive OR on the values of Vx and Vy, then stores the result in Vx. */ var registers = new RegisterModule(); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0x60, //LD v0 with x, x, 0x61, //LD v1 with y y, 0x80, //Bitwise xor, store in v0 0x13 }; emulator.LoadProgram(instructions); emulator.Start(); var expectedResult = x ^ y; Assert.Equal(expectedResult, registers.GetGeneralValue(0)); }
public void _1nnn_JP() { var instructions = new byte[] { 0x11, 0xEF }; var expectedAddress = (ushort)(0x11EF & 0x0FFF); var chip = CHIP8Factory.GetChip8(); chip.LoadProgram(instructions); chip.Tick += (c, e) => { chip.Stop(); }; chip.Start(); var programCounter = GetProgramCounter(chip); Assert.Equal(expectedAddress, programCounter); }
public void _Bnnn_JP_v0_addr() { var registers = new RegisterModule(); registers.SetGeneralValue(0, 0x12); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0xB1, 0x23 }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); Assert.Equal(0x123 + 0x12, GetProgramCounter(emulator)); }
public void _00EE_RET(ushort addr) { // Make sure it's a valid address and doesn't cause an infinite loop Assert.InRange(addr, 514, 4094); var stackModule = new StackModule(); stackModule.Push(addr); var instructions = new byte[] { 0x00, 0xEE }; var chip = CHIP8Factory.GetChip8(stack: stackModule); chip.LoadProgram(instructions); chip.Tick += (c, e) => { chip.Stop(); }; chip.Start(); var programCounter = GetProgramCounter(chip); Assert.Equal(addr, programCounter); }
public void _Fx1E_add_I_Vx() { var registers = new RegisterModule(); registers.SetGeneralValue(0, 0x12); registers.SetI(0x123); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0xF0, //Add v0 and I, store in I 0x1E }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); Assert.Equal(0x123 + 0x12, registers.GetI()); }
public MainWindow() { displayDictionary = new Dictionary <Point, Rectangle>(); for (var x = 0; x < 64; x++) { for (var y = 0; y < 32; y++) { var point = new Point(x, y); displayDictionary[point] = null; } } var registers = new RegisterModule(); emulator = CHIP8Factory.GetChip8(DisplayEmulatorScreen, registers, new StackModule(), new MemoryModule(Enumerable.Repeat <byte>(0x0, 4096))); emulator.ToneOn += this.ToneOn; emulator.ToneOff += this.ToneOff; var bytes = File.ReadAllBytes("pong.ch8"); emulator.LoadProgram(bytes); InitializeComponent(); this.KeyDown += MainWindow_KeyDown; this.KeyUp += MainWindow_KeyUp; }
public void _Cxkk_RND_vx_byte(byte kk, byte rand) { var registers = new RegisterModule(); var random = new TestRandom(rand); var emulator = CHIP8Factory.GetChip8(registers: registers, random: random); var instructions = new byte[] { 0xC0, //Set v0 = kk & random byte kk }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); Assert.Equal(rand & kk, registers.GetGeneralValue(0)); }
public void _Fx33_LD_B_Vx() { /* * Stores the BCD of vx in I, I+1, and I+2 of memory * 125: * Hex: 0x7D * BCD: 0001 0010 0101 */ var registers = new RegisterModule(); registers.SetGeneralValue(0, 0x7D); registers.SetI(0x123); var memory = new MemoryModule(Enumerable.Repeat((byte)0x0, 4096)); var emulator = CHIP8Factory.GetChip8(registers: registers, mem: memory); var instructions = new byte[] { 0xF0, //Store BCD of v0 in memory 0x33 }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); var startPoint = registers.GetI(); var hundreds = memory[startPoint]; startPoint++; var tens = memory[startPoint]; startPoint++; var ones = memory[startPoint]; Assert.Equal(0x1, hundreds); Assert.Equal(0x2, tens); Assert.Equal(0x5, ones); }
public void Correctly_Clears_Display_CLS() { var registers = new RegisterModule(); bool[,] display = null; Task WriteDisplay(bool[,] values) { display = values; return(Task.CompletedTask); } var emulator = CHIP8Factory.GetChip8(WriteDisplay, registers); registers.SetGeneralValue(0, 0x0); var instructions = new byte[] { /* Load location of sprite for '0' to I */ 0xF0, 0x29, /* Draw 5 byte sized sprite at 0,0 */ 0xD0, 0x05, /* Clear screen */ 0x00, 0xE0 }; emulator.LoadProgram(instructions); emulator.Start(); Assert.NotNull(display); for (var x = 0; x < display.GetLength(0); x++) { for (var y = 0; y < display.GetLength(1); y++) { Assert.False(display[x, y]); } } }
public void _Annn_LD_I_addr() { var registers = new RegisterModule(); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0xA1, 0x23 }; emulator.LoadProgram(instructions); emulator.Start(); Assert.Equal(0x123, registers.GetI()); }
public void _9xy0_SNE_vx_vy(byte vx, byte vy) { var registerModule = new RegisterModule(); registerModule.SetGeneralValue(0, vx); registerModule.SetGeneralValue(1, vy); var instructions = new byte[] { 0x90, //Inc program counter by 2 if v0 == v1 0x10 }; var chip = CHIP8Factory.GetChip8(registers: registerModule); chip.LoadProgram(instructions); chip.Tick += (c, e) => { chip.Stop(); }; chip.Start(); var nextInstruction = 514; var expectedAddress = nextInstruction; if (vx != vy) { expectedAddress += 2; } var programCounter = GetProgramCounter(chip); Assert.Equal(expectedAddress, programCounter); }
public void _6xkk_LD_vx_byte() { /* * 6xkk - LD Vx, byte Set Vx = kk. The interpreter puts the value kk into register Vx. */ var registers = new RegisterModule(); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0x60, //LD v0 with byte 0x12 0x12 }; emulator.LoadProgram(instructions); emulator.Start(); Assert.Equal(0x12, registers.GetGeneralValue(0)); }
public void _8xy0_LD_vx_vy() { /* * 8xy0 - Stores the value of register Vy in register Vx. */ var registers = new RegisterModule(); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0x61, //LD v1 with byte 0x12 0x12, 0x80, // Store value at v1 in v0 0x10 }; emulator.LoadProgram(instructions); emulator.Start(); Assert.Equal(0x12, registers.GetGeneralValue(0)); }
public void _7xkk_LD_vx_byte() { /* * 7xkk - Adds the value kk to the value of register Vx, then stores the result in Vx. */ var registers = new RegisterModule(); var emulator = CHIP8Factory.GetChip8(registers: registers); var instructions = new byte[] { 0x60, //LD v0 with byte 0x12 0x12, 0x70, // Add 0x10 to v0 and save it in v0 0x10 }; emulator.LoadProgram(instructions); emulator.Start(); Assert.Equal(0x22, registers.GetGeneralValue(0)); }
public void _Fx65_LD_Vx_I() { /* * Set registers v0 through vx from memory starting at I */ var registers = new RegisterModule(); registers.SetI(0x278); var startPoint = registers.GetI(); var memory = new MemoryModule(Enumerable.Repeat((byte)0x0, 4096)); memory[startPoint] = 0x7D; startPoint++; memory[startPoint] = 0x55; startPoint++; memory[startPoint] = 0x18; startPoint++; memory[startPoint] = 0x90; var emulator = CHIP8Factory.GetChip8(registers: registers, mem: memory); var instructions = new byte[] { 0xF3, //Set v0 - v3 from memory 0x65 }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); var v0 = registers.GetGeneralValue(0); var v1 = registers.GetGeneralValue(1); var v2 = registers.GetGeneralValue(2); var v3 = registers.GetGeneralValue(3); Assert.Equal(0x7D, v0); Assert.Equal(0x55, v1); Assert.Equal(0x18, v2); Assert.Equal(0x90, v3); }
public void _Fx55_LD_I_Vx() { /* * Stores registers v0 through vx in memory starting at I */ var registers = new RegisterModule(); registers.SetGeneralValue(0, 0x7D); registers.SetGeneralValue(1, 0x55); registers.SetGeneralValue(2, 0x18); registers.SetGeneralValue(3, 0x90); registers.SetI(0x278); var memory = new MemoryModule(Enumerable.Repeat((byte)0x0, 4096)); var emulator = CHIP8Factory.GetChip8(registers: registers, mem: memory); var instructions = new byte[] { 0xF3, //Store v0 - v3 in memory 0x55 }; emulator.LoadProgram(instructions); emulator.Tick += (e, a) => { emulator.Stop(); }; emulator.Start(); var startPoint = 0x278; var v0 = memory[startPoint]; startPoint++; var v1 = memory[startPoint]; startPoint++; var v2 = memory[startPoint]; startPoint++; var v3 = memory[startPoint]; Assert.Equal(0x7D, v0); Assert.Equal(0x55, v1); Assert.Equal(0x18, v2); Assert.Equal(0x90, v3); }
public void Correctly_Draws_Manual_Zero_Sprite_Dxyn() { /* * Dxyn - DRW Vx, Vy, nibble * Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision. */ // Copy of the 0 sprite data we load var zeroSpriteData = new byte[] { 0xF0, 0x90, 0x90, 0x90, 0xF0 }; // Set I to start of sprite var setIInstruction = new byte[] { 0xAD, 0xDD }; // Draw 5 bytes at 0,0 from mem address I var drawInstruction = new byte[] { 0xD0, 0x05 }; var registers = new RegisterModule(); bool[,] display = null; Task WriteDisplay(bool[,] values) { display = values; return(Task.CompletedTask); } var ram = Enumerable.Repeat <byte>(0x0, 4096) .ToArray(); const int spriteStart = 0xDDD; // Copy the data starting at FFF for (var i = spriteStart; i < spriteStart + zeroSpriteData.Length; i++) { ram[i] = zeroSpriteData[i - spriteStart]; } var memory = new MemoryModule(ram); var emulator = CHIP8Factory.GetChip8(WriteDisplay, registers, new StackModule(), memory); registers.SetGeneralValue(0, 0x0); var instructions = setIInstruction.Concat(drawInstruction) .ToArray(); emulator.LoadProgram(instructions); emulator.Start(); void AssertDisplay(int x, int y, bool pixelValue) { var validY = false; switch (x) { case 0: case 3: // Column 1 & 4 all on validY = pixelValue; break; case 1: case 2: // For the middle 2 columns only the top and bottom should be on if (y == 0 || y == 4) { validY = pixelValue; } else { validY = !pixelValue; } break; default: // Everything past 4 should be off validY = !pixelValue; break; } Assert.True(validY, $"Invalid pixel at {x},{y}. {pixelValue}."); } Assert.NotNull(display); // Check the 8x5 area the sprite displays in for (var x = 0; x < 8; x++) { for (var y = 0; y < 5; y++) { AssertDisplay(x, y, display[x, y]); } } }
public void Correctly_Draws_Zero_Sprite_Dxyn(byte xOffset, byte yOffset) { var registers = new RegisterModule(); bool[,] display = null; Task WriteDisplay(bool[,] values) { display = values; return(Task.CompletedTask); } var emulator = CHIP8Factory.GetChip8(WriteDisplay, registers); registers.SetGeneralValue(3, 0x0); registers.SetGeneralValue(0, xOffset); registers.SetGeneralValue(1, yOffset); var instructions = new byte[] { /* Load location of sprite for '0' to I */ 0xF3, 0x29, /* Draw 5 byte sized sprite at (v0, v1) */ 0xD0, 0x15 }; emulator.LoadProgram(instructions); emulator.Start(); void AssertDisplay(int x, int y, bool pixelValue) { var validY = false; x = x - xOffset; y = y - yOffset; switch (x) { case 0: case 3: // Column 1 & 4 all on validY = pixelValue; break; case 1: case 2: // For the middle 2 columns only the top and bottom should be on if (y == 0 || y == 4) { validY = pixelValue; } else { validY = !pixelValue; } break; default: // Everything past 4 should be off validY = !pixelValue; break; } Assert.True(validY, $"Invalid pixel at sprite coordinate ({x},{y}), true coordinate({x + xOffset}, {y + yOffset}). {pixelValue}."); } Assert.NotNull(display); // Check the 8x5 area the sprite displays in for (var x = xOffset; x < 8 + xOffset; x++) { for (var y = yOffset; y < 5 + yOffset; y++) { AssertDisplay(x, y, display[x, y]); } } }