Skip to content

Instantly share code, notes, and snippets.

@rpazyaquian
Created December 2, 2014 17:37
Show Gist options
  • Save rpazyaquian/d75ec905f80a8d72c019 to your computer and use it in GitHub Desktop.
Save rpazyaquian/d75ec905f80a8d72c019 to your computer and use it in GitHub Desktop.
/*global describe, it */
'use strict';
(function () {
describe('Chip8', function () {
describe('RAM', function () {
it('has 4096 bytes', function () {
expect(Chip8.ram.length).toEqual(4096);
});
});
describe('8-bit registers V0 - VF', function () {
it('initialize at 0', function () {
for (var i = 0; i < 16; i++) {
expect(Chip8.registers[i]).toEqual(0);
};
});
it('can be retrived using get(x)', function () {
expect(Chip8.get(0)).toEqual(0);
});
it('can be set using set(x, nn)', function () {
Chip8.set(0x0, 0xFF)
expect(Chip8.get(0x0)).toEqual(0xFF);
});
});
describe('16-bit address register I', function () {
it('initializes at 0', function () {
expect(Chip8.index).toEqual(0);
});
});
describe('8-bit delay timer DT', function () {
it('initializes at 0', function () {
expect(Chip8.delayTimer).toEqual(0);
});
it('ticks down at 60hz', function () {
Chip8.delayTimer = 60;
Chip8.run({seconds: 1});
expect(Chip8.delayTimer).toEqual(0);
});
});
describe('8-bit sound timer ST', function () {
it('initializes at 0', function () {
expect(Chip8.soundTimer).toEqual(0);
});
it('ticks down at 60hz', function () {
Chip8.soundTimer = 60;
Chip8.run({seconds: 1});
expect(Chip8.soundTimer).toEqual(0);
});
});
describe('16-bit program counter PC', function () {
it('initializes at 0x200', function () {
expect(Chip8.programCounter).toEqual(512);
});
});
describe('8-bit stack pointer SP', function () {
it('initializes at 0', function () {
expect(Chip8.stackPointer).toEqual(0);
});
});
describe('16-bit stack', function () {
it('initializes at 0', function () {
for (var i = 0; i < 16; i++) {
expect(Chip8.stack[i]).toEqual(0);
};
// what's the point of these tests?
// reminding me of what i need to implement, i guess
});
});
describe('display', function () {
it('is 64x32 pixels large', function () {
var width = 64;
var height = 32;
expect(Chip8.display.length).toEqual(32);
for (var i = 0; i < 32; i++) {
expect(Chip8.display[i].length).toEqual(64);
};
});
});
describe('opcodes', function () {
var VX = Chip8.get(0);
var VY = Chip8.get(1);
var VF = Chip8.get(15);
describe('00E0 - CLS', function () {
// Clear the display.
it('clears the display', function () {
Chip8.execute(0x00E0);
expect(Chip8.displayIsBlank()).toBe(true);
});
});
describe('00EE - RET', function () {
// The interpreter sets the program counter to the address at
// the top of the stack, then subtracts 1 from the stack pointer.
it('returns from a subroutine', function () {
// it looks like this might depend on another
// function i need to test...
});
});
describe('1NNN - JP ADDR', function () {
// The interpreter sets the program counter to nnn.
it('jumps to location NNN', function () {
Chip8.execute(0x1200);
expect(Chip8.programCounter).toEqual(512);
});
});
describe('2NNN - CALL ADDR', function () {
// The interpreter increments the stack pointer,
// then puts the current PC on the top of the stack.
// The PC is then set to nnn.
it('calls subroutine at NNN', function () {
// NOTE: this assumes that the PC
// starts at 0x200, or 512. maybe don't
// run this test yet.
Chip8.execute(0x2200);
expect(Chip8.stackPointer).toEqual(1);
expect(Chip8.stack[0]).toEqual(512);
expect(Chip8.programCounter).toEqual(512);
});
});
describe('3XKK - SE VX, BYTE', function () {
// The interpreter compares register Vx to kk,
// and if they are equal, increments the program counter by 2.
it('skips next instruction if VX = KK', function () {
var originalCounter = Chip8.programCounter;
Chip8.set(0, 0x0A);
Chip8.execute(0x300A);
var newCounter = Chip8.programCounter;
expect(newCounter - originalCounter).toEqual(2);
});
});
describe('4XKK - SNE VX, BYTE', function () {
// The interpreter compares register Vx to kk,
// and if they are not equal, increments the program counter by 2.
it('skips next instruction if VX != KK', function () {
var originalCounter = Chip8.programCounter;
Chip8.set(0, 0x0A);
Chip8.execute(0x400B);
var newCounter = Chip8.programCounter;
expect(newCounter - originalCounter).toEqual(0);
});
});
describe('5XY0 - SE VX, VY', function () {
// The interpreter compares register Vx to Vy,
// and if they are equal, increments the program counter by 2.
it('skips next instruction if VX = VY', function () {
var originalCounter = Chip8.programCounter;
Chip8.set(0, 0x0A);
Chip8.set(1, 0x0A);
Chip8.execute(0x5010);
var newCounter = Chip8.programCounter;
expect(newCounter - originalCounter).toEqual(2);
});
});
describe('6XKK - LD VX, BYTE', function () {
// The interpreter puts the value kk into register Vx.
it('sets VX to KK', function () {
Chip8.execute(0x600A);
expect(Chip8.registers[0]).toEqual(0x0A);
});
});
describe('7XKK - ADD VX, BYTE', function () {
// Adds the value kk to the value of register Vx,
// then stores the result in Vx.
it('sets VX to (VX + KK)', function () {
Chip8.set(0, 0x00);
Chip8.execute(0x7001);
expect(VX).toEqual(0x01);
});
});
describe('8###', function () {
describe('8XY0 - LD VX, VY', function () {
// Stores the value of register Vy in register Vx.
it('sets VX to VY', function () {
Chip8.set(0, 0x0A);
Chip8.set(1, 0x14);
Chip8.execute(0x8010);
expect(VX).toEqual(VY);
});
});
describe('8XY1 - OR VX, VY', function () {
// Performs a bitwise OR on the values of Vx and Vy,
// then stores the result in Vx. A bitwise OR compares
// the corresponding bits from two values, and if
// either bit is 1, then the same bit in the result
// is also 1. Otherwise, it is 0.
it('sets VX to (VX || VY)', function () {
Chip8.set(0, 0x0F);
Chip8.set(1, 0x0A);
Chip8.execute(0x8011);
expect(VX).toEqual(0xF);
});
});
describe('8XY2 - AND VX, VY', function () {
// Performs a bitwise AND on the values of Vx and Vy,
// then stores the result in Vx. A bitwise AND compares
// the corrseponding bits from two values, and if
// both bits are 1, then the same bit in the result
// is also 1. Otherwise, it is 0.
it('sets VX to (VX && VY)', function () {
Chip8.set(0, 0x0F);
Chip8.set(1, 0x0A);
Chip8.execute(0x8012);
expect(VX).toEqual(0xA);
});
});
describe('8XY3 - XOR VX, VY', function () {
// Performs a bitwise XOR on the values of Vx and Vy,
// then stores the result in Vx. A bitwise XOR compares
// the corrseponding bits from two values, and if
// the bits are not the same, then the corresponding bit
// in the result is also 1. Otherwise, it is 0.
it('sets VX to (VX ^ VY)', function () {
Chip8.set(0, 0x0F);
Chip8.set(1, 0x0A);
Chip8.execute(0x8013);
expect(VX).toEqual(0x5);
});
});
describe('8XY4 - ADD VX, VY', function () {
// The values of Vx and Vy are added together.
// If the result is greater than 8 bits (i.e., > 255),
// VF is set to 1, otherwise 0.
// Only the lowest 8 bits of the result are kept,
// and stored in Vx.
describe('when VX + VY < 255', function () {
Chip8.set(0, 0x01);
Chip8.set(1, 0x01);
Chip8.execute(0x8014);
it('sets VX to (VX + VY)', function () {
expect(VX).toEqual(0x02);
});
it('sets VF to 0', function () {
expect(VF).toEqual(0x00);
});
});
describe('when VX + VY > 255', function () {
Chip8.set(0, 0xFF);
Chip8.set(1, 0x01);
Chip8.execute(0x8014);
it('sets VX to (VX + VY) - 256', function () {
// so in this case, 0x100 = 256,
// therefore VX is set to 256 - 256,
// therefore VX = 0.
expect(VX).toEqual(0x00);
});
it('sets VF to carry', function () {
expect(VF).toEqual(0x01);
});
});
});
describe('8XY5 - SUB VX, VY', function () {
// If Vx > Vy, then VF is set to 1, otherwise 0.
// Then Vy is subtracted from Vx,
// and the results stored in Vx.
// NOTE:
// e.g. if Vx = 200, Vy = 100,
// then Vx = (200 - 100), VF = 1
// if Vx = 100, Vy = 105,
// then Vx = 255 - abs(100-105) = 255 - 5 = 250,
// VF = 0.
// (we're assuming it rolls over.)
// NOTE 2:
// actually, that's a good point.
// should we assume it rolls over to
// the "negatives", or
// should it floor out at 0?
// let's assume it rolls over,
// just to be accurate...
// so assume that we have:
// VX = 0b1110
// VY = 0b1111
// now, counting downwards from 0b1110
// we get to 0b0000, but we need to go down
// one more. in binary, 0b0000 - 0b0001
// rolls over to 0b1111.
// therefore, 0b1110 - 0b1111
// is equal to 0b1111,
// or 0xF.
describe('when VX > VY', function () {
Chip8.set(0, 0x02);
Chip8.set(1, 0x01);
Chip8.execute(0x8015);
it('sets VX to (VX - VY)', function () {
expect(VX).toEqual(0x01);
});
it('VF to NOT borrow', function () {
expect(VF).toEqual(0x01);
// 1 if there was no "borrowing"
});
});
describe('when VX < VY', function () {
Chip8.set(0, 0x00);
Chip8.set(1, 0x01);
Chip8.execute(0x8015);
it('sets VX to (VX - VY)', function () {
expect(VX).toEqual(0xF);
});
it('VF to NOT borrow', function () {
expect(VF).toEqual(0x0);
// 0 if there was "borrowing" (rollover)
});
});
describe('when VX = VY', function () {
// what do you do when they're the same?
// well, no roll-over occurs.
// you get VX = 0b0000, and VF = 0b1.
Chip8.set(0, 0x01);
Chip8.set(1, 0x01);
Chip8.execute(0x8015);
it('sets VX to (VX - VY)', function () {
expect(VX).toEqual(0x0);
});
it('VF to NOT borrow', function () {
expect(VF).toEqual(0x1);
// 1 if there was no "borrowing"
});
});
});
describe('8XY6 - SHR VX, VY', function () {
// If the least-significant bit of Vx is 1,
// then VF is set to 1, otherwise 0.
// Then Vx is divided by 2.
// NOTE: VY is ignored
Chip8.set(0, 0xFF);
Chip8.execute(0x8016);
it('sets VX to (VX >> 1)', function () {
expect(VX).toEqual(0x7F);
});
it('VF to least-significant bit of VX (1 or 0)', function () {
expect(VF).toEqual(0x1);
});
});
describe('8XY7 - SUBN VX, VY', function () {
// If Vy > Vx, then VF is set to 1, otherwise 0.
// Then Vx is subtracted from Vy,
// and the results stored in Vx.
describe('when VX < VY', function () {
Chip8.set(0, 0xFE);
Chip8.set(1, 0xFF);
Chip8.execute(0x8017);
it('sets VX = (VY - VX)', function () {
expect(VX).toEqual(0x1);
});
it('VF to NOT borrow', function () {
expect(VF).toEqual(0x1);
});
});
describe('when VX > VY', function () {
Chip8.set(0, 0xFF);
Chip8.set(1, 0xFE);
Chip8.execute(0x8017);
// assuming roll-over
it('sets VX = (VY - VX)', function () {
// VX = 0 - 1 = rollover = 255 = 0xFF
expect(VX).toEqual(0xFF);
});
it('VF to NOT borrow', function () {
// borrowed, so VF = 0
expect(VF).toEqual(0x0);
});
});
describe('when VX = VY', function () {
Chip8.set(0, 0xFF);
Chip8.set(1, 0xFE);
Chip8.execute(0x8017);
it('sets VX = (VY - VX)', function () {
expect(VX).toEqual(0x0);
});
it('VF to NOT borrow', function () {
expect(VF).toEqual(0x1);
});
});
});
describe('8XYE - SHL VX, VY', function () {
// If the most-significant bit of Vx is 1,
// then VF is set to 1, otherwise to 0.
// Then Vx is multiplied by 2.
// VX = 0x4
Chip8.set(0, 0x80);
Chip8.execute(0x801E);
it('sets VX to (VX << 1)', function () {
// 0b 1000 0000 -> 0b 0000 0000
expect(VX).toEqual(0x00);
});
it('VF to most-significant bit of VX (1 or 0)', function () {
// MSB of 0b 1000 0000 is 1
expect(VF).toEqual(0x01);
});
});
});
describe('9XY0 - SNE VX, VY', function () {
// The values of Vx and Vy are compared,
// and if they are not equal,
// the program counter is increased by 2.
it('skips next instruction if VX != VY', function () {
var originalCounter = Chip8.programCounter;
Chip8.set(0, 0x0A);
Chip8.set(1, 0x0B);
Chip8.execute(0x5010);
var newCounter = Chip8.programCounter;
expect(newCounter - originalCounter).toEqual(2);
});
});
describe('ANNN - LD I, ADDR', function () {
// The value of register I is set to nnn.
Chip8.execute(0xA200);
it('sets I = NNN', function () {
expect(Chip8.index).toEqual(0x200);
});
});
describe('BNNN - JP V0, ADDR', function () {
// The program counter is set to
// NNN plus the value of V0.
Chip8.set(0, 0x01)
Chip8.execute(0xB200);
it('jumps to location NNN + V0', function () {
expect(Chip8.programCounter).toEqual(0x201);
});
});
describe('CXKK - RND VX, BYTE', function () {
// The interpreter generates a random number from 0 to 255,
// which is then ANDed with the value kk.
// The results are stored in Vx.
// See instruction 8xy2 for more information on AND.
it('sets VX = (a random byte AND KK)', function () {
// TODO
});
});
describe('DXYN - DRW VX, VY, NIBBLE', function () {
// The interpreter reads n bytes from memory,
// starting at the address stored in I.
// These bytes are then displayed as sprites
// on screen at coordinates (Vx, Vy).
// Sprites are XORed onto the existing screen.
// If this causes any pixels to be erased,
// VF is set to 1, otherwise it is set to 0.
// If the sprite is positioned so part of it
// is outside the coordinates of the display,
// it wraps around to the opposite side of the screen.
// See instruction 8xy3 for more information on XOR,
// and section 2.4, Display, for more information on
// the Chip-8 screen and sprites.
it('displays an N-byte (0-15 px high) sprite starting at memory location I at (Vx, Vy)', function () {
});
it('sets VF to collision', function () {
});
});
describe('EX9E - SKP VX', function () {
// Checks the keyboard, and if the key
// corresponding to the value of Vx is currently
// in the down position, PC is increased by 2.
// NOTE:
// this will depend heavily on the controller
// provided, so don't tie it to any specific
// implementation! just track "[key] is up/down".
it('skips next instruction if key with the value of VX is pressed', function () {
Chip8.setKey(0, Chip8.DOWN);
var originalCounter = Chip8.programCounter;
Chip8.set(0, 0x0A);
Chip8.set(1, 0x0B);
Chip8.execute(0x5010);
var newCounter = Chip8.programCounter;
expect(newCounter - originalCounter).toEqual(2);
});
});
describe('EXA1 - SKNP VX', function () {
// Checks the keyboard, and if the key
// corresponding to the value of Vx is currently
// in the up position, PC is increased by 2.
// NOTE:
// this will depend heavily on the controller
// provided, so don't tie it to any specific
// implementation! just track "[key] is up/down".
Chip8.setKey(0, Chip8.DOWN);
it('skips next instruction if key with the value of VX is NOT pressed', function () {
});
});
describe('F###', function () {
describe('FX07 - LD VX, DT', function () {
// The value of DT is placed into Vx.
it('sets VX to value of DT', function () {
});
});
describe('FX0A - LD VX, KEY', function () {
// All execution stops until a key is pressed,
// then the value of that key is stored in Vx.
it('waits for a key press', function () {
});
it('sets VX to value of pressed key', function () {
});
});
describe('FX15 - LD DT, VX', function () {
// DT is set equal to the value of Vx.
it('sets DT to value of VX', function () {
});
});
describe('FX18 - LD ST, VX', function () {
// ST is set equal to the value of Vx.
it('sets ST to value of VX', function () {
});
});
describe('FX1E - ADD I, VX', function () {
// The values of I and Vx are added,
// and the results are stored in I.
it('sets I to (I + VX)', function () {
});
});
describe('FX29 - LD F, VX', function () {
// The value of I is set to the location for
// the hexadecimal sprite corresponding to
// the value of Vx. See section 2.4, Display,
// for more information on the
// Chip-8 hexadecimal font.
it('sets I to location of sprite for digit VX', function () {
});
});
describe('FX33 - LD B, VX', function () {
// The interpreter takes the decimal value of Vx,
// and places the hundreds digit in memory at
// location in I, the tens digit at location
// I+1, and the ones digit at location I+2.
it('stores hundreds digit of VX in memory at I', function () {
});
it('stores tens digit of VX in memory at I+1', function () {
});
it('stores ones digit of VX in memory at I+2', function () {
});
});
describe('FX55 - LD [I], VX', function () {
// The interpreter copies the values of registers V0
// through VX into memory, starting at the address in I.
// NOTE:
// so for example, `F855` would get the contents of
// V0, V1, V2 ... V8 (9 total) and copy them into
// RAM at I, I+1, I+2 ... I+8 in order.
it('stores registers V0 through VX in memory starting at I', function () {
});
});
describe('FX65 - LD VX, [I]', function () {
// The interpreter reads values from memory starting
// at location I into registers V0 through Vx.
// NOTE:
// so for example, `F865` would get the contents in RAM
// at I, I+1, I+2 ... I+8 (9 total) and copy them
// to V0, V1, V2 ... V8 in order.
it('reads registers V0 through VX from memory starting at I', function () {
});
});
});
});
describe('auxiliary logic', function () {
it('should run here few assertions', function () {
});
});
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment