const expect = require('chai').expect; const MOS6502 = require('../src/MOS/6502'); const Mem = require('../src/memory'); describe("Testing MOS6502 CPU...", function(){ var asm = new MOS6502.Assembler(); var cpu = new MOS6502.CPU(); var tick = cpu.clk(); cpu.memory = new Mem.RAM(256); cpu.memory.load(0xFFFC, [0x00, 0x00]); it("Resetting (IRQ Disabled flag must be on", function(){ cpu.reset = true; tick(); // One tick to handle resets. expect(cpu.I).to.equal(1); expect(cpu.PC).to.equal(0); // Test program counter set to the vector stored at 0xFFFC - 0xFFFD }); describe("Testing flag set/clear calls...", function(){ it("CLC / SEC", function(){ cpu.memory.clearPage(0); cpu.memory.load(0, [0x18, 0x38]); cpu.reset = true; tick(); // reset. tick(); tick(); // Two ticks to process opcode. expect(cpu.C).to.equal(0); tick(); tick(); expect(cpu.C).to.equal(1); }); it("CLI / SEI", function(){ cpu.memory.clearPage(0); cpu.memory.load(0, [0x58, 0x78]); cpu.reset = true; tick(); tick(); tick(); expect(cpu.I).to.equal(0); tick(); tick(); expect(cpu.I).to.equal(1); }); it("CLD / SED", function(){ cpu.memory.clearPage(0); cpu.memory.load(0, [0xD8, 0xF8]); cpu.reset = true; tick(); tick(); tick(); expect(cpu.D).to.equal(0); tick(); tick(); expect(cpu.D).to.equal(1); }); it("CLV", function(){ cpu.memory.clearPage(0); cpu.memory.load(0, [0xB8]); cpu.reset = true; tick(); tick(); tick(); expect(cpu.V).to.equal(0); }); }); describe("Testing LDA...", function(){ it("LDA Immediate", function(){ let prg = "LDA #$01\n"; prg += "LDA #$BB"; asm.reset().compile(prg); cpu.memory.clearPage(0); cpu.memory.load(0, asm.result()); cpu.hardReset(); //cpu.reset = true; //tick(); tick(); tick(); expect(cpu.A).to.equal(0x01); tick(); expect(cpu.A).to.equal(0x01); tick(); expect(cpu.A).to.equal(0xBB); }); it("LDA Zero Page"); it("LDA Zero Page, X"); it("LDA Absolute"); it("LDA Absolute, X"); it("LDA Absolute, Y"); it("LDA Indirect, X"); it("LDA Indirect, Y"); }); describe("Testing ADC...", function(){ describe("ADC Binary Mode...", function(){ it("ADC Immediate", function(){ let prg = "CLC\n"; prg += "CLV\n"; prg += "CLD\n"; prg += "CLI\n"; prg += "LDA #$00\n"; prg += "ADC #$01\n"; prg += "ADC #$7F\n"; prg += "ADC #$80"; asm.reset().compile(prg); cpu.memory.clearPage(0); cpu.memory.load(0, asm.result()); cpu.hardReset(); //cpu.reset = true; //tick(); // To reset; while (cpu.PC !== 13){ switch(cpu.PC){ case 6: expect(cpu.A).to.equal(0x00); break; case 8: expect(cpu.A).to.equal(0x01); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(0); expect(cpu.N).to.equal(0); break; case 10: expect(cpu.A).to.equal(0x80); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(0); expect(cpu.N).to.equal(1); break; case 12: expect(cpu.A).to.equal(0x00); expect(cpu.Z).to.equal(1); expect(cpu.C).to.equal(1); expect(cpu.N).to.equal(0); } tick(); } }); it("ADC Zero Page"); it("ADC Zero Page, X"); it("ADC Absolute"); it("ADC Absolute, X"); it("ADC Absolute, Y"); it("ADC Indirect, X"); it("ADC Indirect, Y"); }); describe("ADC Decimal (BCD) Mode...", function(){ it("ADC Immediate", function(){ let prg = "CLC\n"; prg += "CLV\n"; prg += "SED\n"; prg += "CLI\n"; prg += "LDA #$00\n"; prg += "ADC #$01\n"; prg += "ADC #$09\n"; prg += "ADC #$89\n"; prg += "ADC #$01\n"; prg += "LDA #$0A\n"; // 0A is an invalid BCD number prg += "CLC\n"; // Need to reset the clear flag from previous add. prg += "ADC #$01"; asm.reset().compile(prg); cpu.memory.clearPage(0); cpu.memory.load(0, asm.result()); cpu.hardReset(); //cpu.reset = true; //tick(); // To reset; while (cpu.PC !== 20){ switch(cpu.PC){ case 6: expect(cpu.A).to.equal(0x00); break; case 8: expect(cpu.A).to.equal(0x01); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(0); expect(cpu.N).to.equal(0); break; case 10: expect(cpu.A).to.equal(0x10); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(0); expect(cpu.N).to.equal(0); break; case 12: expect(cpu.A).to.equal(0x99); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(0); expect(cpu.N).to.equal(1); break; case 14: expect(cpu.A).to.equal(0x00); expect(cpu.Z).to.equal(0); expect(cpu.C).to.equal(1); expect(cpu.N).to.equal(0); break; case 19: //console.log(cpu.A); expect(cpu.A).to.equal(0x11); break; } tick(); } }); it("ADC Zero Page"); it("ADC Zero Page, X"); it("ADC Absolute"); it("ADC Absolute, X"); it("ADC Absolute, Y"); it("ADC Indirect, X"); it("ADC Indirect, Y"); }); }); describe("Testing SBC...", function(){ describe("SBC Binary Mode...", function(){ it("SBC Immediate", function(){ let prg = "SEC\n"; prg += "CLV\n"; prg += "CLD\n"; prg += "CLI\n"; prg += "LDA #$01\n"; prg += "SBC #$01\n"; prg += "SBC #$01"; asm.reset().compile(prg); cpu.memory.clearPage(0); cpu.memory.load(0, asm.result()); cpu.hardReset(); //cpu.reset = true; //tick(); // To reset; while(cpu.PC !== 11){ // NOTE TO SELF: Depending on the OP code, these tests could be // checked multiple times, as the cpu may sit at a program cntr // for a couple cycles depending on the OP. switch(cpu.PC){ case 1: expect(cpu.C).to.be.equal(1); break; case 6: expect(cpu.A).to.be.equal(0x01); break; case 8: expect(cpu.A).to.be.equal(0x00); expect(cpu.C).to.be.equal(1); expect(cpu.Z).to.be.equal(1); expect(cpu.N).to.be.equal(0); break; case 9: expect(cpu.A).to.be.equal(0xFF); expect(cpu.C).to.be.equal(0); expect(cpu.Z).to.be.equal(0); expect(cpu.N).to.be.equal(1); break; } tick(); } }); it("SBC Zero Page"); it("SBC Zero Page, X"); it("SBC Absolute"); it("SBC Absolute, X"); it("SBC Absolute, Y"); it("SBC Indirect, X"); it("SBC Indirect, Y"); }); describe("SBC Decimal (BCD) Mode...", function(){ it("SBC Immediate"); it("SBC Zero Page"); it("SBC Zero Page, X"); it("SBC Absolute"); it("SBC Absolute, X"); it("SBC Absolute, Y"); it("SBC Indirect, X"); it("SBC Indirect, Y"); }); }); });