UNPKG

nes-emu

Version:

A NES emulator

310 lines (305 loc) 11.1 kB
"use strict"; var _ = _interopRequireDefault(require(".")); var _helpers = require("../../helpers"); var _createTestContext = _interopRequireDefault(require("../../helpers/createTestContext")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const should = require("chai").Should(); describe("instructions", () => { describe("arithmetic", () => { let cpu, memory, context; beforeEach(() => { ({ cpu, memory, context } = (0, _createTestContext.default)()); }); describe("ADC", () => { it("adds the value to the accumulator", () => { cpu.registers.a.value = 20; _.default.ADC.execute(context, 5); cpu.registers.a.value.should.equal(25); }); it("adds the carry bit", () => { cpu.registers.a.value = 20; cpu.flags.c = true; _.default.ADC.execute(context, 5); cpu.registers.a.value.should.equal(26); }); it("updates the Z and N flags", () => { cpu.registers.a.value = 50; _.default.ADC.execute(context, 120); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); _.default.ADC.execute(context, 86); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); it("updates the C and V flags", () => { cpu.registers.a.value = 50; _.default.ADC.execute(context, 10); cpu.flags.c.should.equal(false); cpu.flags.v.should.equal(false); // positive (60) + positive (75) = negative (-121) => overflow cpu.flags.c = false; _.default.ADC.execute(context, 75); cpu.flags.c.should.equal(false); cpu.flags.v.should.equal(true); // result is over 255 => carry cpu.flags.c = false; _.default.ADC.execute(context, 122); cpu.flags.c.should.equal(true); cpu.flags.v.should.equal(false); }); }); describe("ASL", () => { it("multiplies the value by 2", () => { memory.writeAt(0x1234, 12); _.default.ASL.execute(context, 0x1234); memory.readAt(0x1234).should.equal(24); cpu.flags.c.should.equal(false); }); it("sets the C flag when the result doesn't fit in 8 bit", () => { memory.writeAt(0x1234, 0b11000000); _.default.ASL.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b10000000); cpu.flags.c.should.equal(true); }); it("updates the Z and N flags", () => { memory.writeAt(0x1234, 0b11000000); _.default.ASL.execute(context, 0x1234); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); memory.writeAt(0x1234, 0); _.default.ASL.execute(context, 0x1234); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); }); describe("DEC", () => { it("decrements the value", () => { memory.writeAt(0x1234, 9); _.default.DEC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(8); }); it("sets the Z flag", () => { memory.writeAt(0x1234, 1); _.default.DEC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); it("sets the N flag", () => { memory.writeAt(0x1234, 0); _.default.DEC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(255); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); }); }); [{ instruction: "DEX", register: "x" }, { instruction: "DEY", register: "y" }].forEach(_ref => { let { instruction, register } = _ref; describe(instruction, () => { it("decrements the value and updates the flags", () => { cpu.registers[register].value = 1; _.default[instruction].execute(context); cpu.registers[register].value.should.equal(0); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); cpu.registers[register].value = 0; _.default[instruction].execute(context); cpu.registers[register].value.should.equal(255); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); }); }); }); describe("INC", () => { it("increments the value", () => { memory.writeAt(0x1234, 8); _.default.INC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(9); }); it("sets the Z flag", () => { memory.writeAt(0x1234, 255); _.default.INC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); it("sets the N flag", () => { memory.writeAt(0x1234, 244); _.default.INC.execute(context, 0x1234); memory.readAt(0x1234).should.equal(245); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); }); }); [{ instruction: "INX", register: "x" }, { instruction: "INY", register: "y" }].forEach(_ref2 => { let { instruction, register } = _ref2; describe(instruction, () => { it("increments the value and updates the flags", () => { cpu.registers[register].value = 255; _.default[instruction].execute(context); cpu.registers[register].value.should.equal(0); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); cpu.registers[register].value = 244; _.default[instruction].execute(context); cpu.registers[register].value.should.equal(245); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); }); }); }); describe("LSR", () => { it("divides the value by 2", () => { memory.writeAt(0x1234, 128); _.default.LSR.execute(context, 0x1234); memory.readAt(0x1234).should.equal(64); cpu.flags.c.should.equal(false); }); it("sets the C flag when the last bit is 1", () => { memory.writeAt(0x1234, 0b11000001); _.default.LSR.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b01100000); cpu.flags.c.should.equal(true); }); it("updates the Z and N flags", () => { memory.writeAt(0x1234, 0b11000000); _.default.LSR.execute(context, 0x1234); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(false); memory.writeAt(0x1234, 0); _.default.LSR.execute(context, 0x1234); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); }); describe("ROL", () => { it("multiplies the value by 2", () => { memory.writeAt(0x1234, 12); _.default.ROL.execute(context, 0x1234); memory.readAt(0x1234).should.equal(24); }); it("sets the C flag with the bit 7", () => { memory.writeAt(0x1234, 0b10100000); _.default.ROL.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b01000000); cpu.flags.c.should.equal(true); }); it("sets the bit 0 with the C flag", () => { cpu.flags.c = true; memory.writeAt(0x1234, 0b10100000); _.default.ROL.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b01000001); }); it("updates the Z and N flags", () => { memory.writeAt(0x1234, 0b11000000); _.default.ROL.execute(context, 0x1234); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); cpu.flags.c = false; memory.writeAt(0x1234, 0); _.default.ROL.execute(context, 0x1234); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); }); describe("ROR", () => { it("divides the value by 2", () => { memory.writeAt(0x1234, 24); _.default.ROR.execute(context, 0x1234); memory.readAt(0x1234).should.equal(12); }); it("sets the C flag with the bit 0", () => { memory.writeAt(0x1234, 0b00000101); _.default.ROR.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b00000010); cpu.flags.c.should.equal(true); }); it("sets the bit 7 with the C flag", () => { cpu.flags.c = true; memory.writeAt(0x1234, 0b00000101); _.default.ROR.execute(context, 0x1234); memory.readAt(0x1234).should.equal(0b10000010); }); it("updates the Z and N flags", () => { cpu.flags.c = true; memory.writeAt(0x1234, 0b11000000); _.default.ROR.execute(context, 0x1234); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); cpu.flags.c = false; memory.writeAt(0x1234, 0); _.default.ROR.execute(context, 0x1234); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); }); describe("SBC", () => { it("substracts the value from the accumulator - 1 when C is clear", () => { cpu.registers.a.value = 20; _.default.SBC.execute(context, 5); cpu.registers.a.value.should.equal(14); }); it("substracts the value from the accumulator - 0 when C is set", () => { cpu.registers.a.value = 20; cpu.flags.c = true; _.default.SBC.execute(context, 5); cpu.registers.a.value.should.equal(15); }); it("updates the Z and N flags", () => { cpu.registers.a.value = 20; _.default.SBC.execute(context, 30); cpu.flags.z.should.equal(false); cpu.flags.n.should.equal(true); cpu.registers.a.value = 0; cpu.flags.c = true; _.default.SBC.execute(context, 0); cpu.flags.z.should.equal(true); cpu.flags.n.should.equal(false); }); it("updates the C and V flags", () => { cpu.registers.a.value = 50; _.default.SBC.execute(context, 10); cpu.flags.c.should.equal(true); cpu.flags.v.should.equal(false); // positive (40) - negative (-100) = negative (-116) => overflow cpu.registers.a.value = 40; cpu.flags.c = true; _.default.SBC.execute(context, _helpers.Byte.toSignedByte(-100)); cpu.flags.c.should.equal(false); // there was borrow cpu.flags.v.should.equal(true); // | // v // 00101000 (40) // - 10011100 (-100) // ^ // negative (-40) - positive (100) = positive (116) => overflow cpu.registers.a.value = _helpers.Byte.toSignedByte(-40); cpu.flags.c = true; _.default.SBC.execute(context, 100); cpu.flags.c.should.equal(true); cpu.flags.v.should.equal(true); }); }); }); });