Rework the way the cpu object loads and executes code

This commit is contained in:
Preston Skupinski 2011-11-05 21:45:36 -04:00
parent 798dd18835
commit a9b70c8ad0
3 changed files with 173 additions and 114 deletions

6
README
View File

@ -2,4 +2,8 @@ This project's goal is to fully emulate the 65816 microprocessor in JavaScript.
After achieving that goal the next step will be to create a new branch that will focus on emulating the SNES. Any CPU related improvements that aren't specific to the SNES will be merged back.
You call the execute function of the cpu object with a raw hex string representing the program you wish to emulate and it will execute those instructions as close to the 65816 as possible.
Here is a short example of how to use the emulator:
var cpu = new CPU_65816();
cpu.load_binary("18fba9ff", 0x8000); // Load the program at 0x8000 in memory
cpu.execute(0x8000); // Execute starting at 0x8000

58
cpu.js
View File

@ -255,28 +255,23 @@ function CPU_65816() {
/**
* Load given program into memory and prepare for execution.
*/
this.load_program = function(raw_hex, has_header) {
this.mmu.load_rom(raw_hex);
this.r.pc = 0x8000;
// Skip the header(the first 512 bytes) if there is one present for now.
if(has_header) {
this.r.pc += 4096;
}
this.load_binary = function(raw_hex, memory_location_start) {
var loc = memory_location_start;
var byte_buffer = [];
for(var i = 0; i < raw_hex.length; i++) {
byte_buffer.push(raw_hex[i]);
if(byte_buffer.length===2) {
this.mmu.store_byte(loc, parseInt(byte_buffer[0]+byte_buffer[1],
"16"));
loc++;
byte_buffer = [];
}
}
};
/**
* Take a raw hex string representing the program and execute it.
*/
this.execute = function(raw_hex, has_header) {
this.load_program(raw_hex, has_header);
this.start();
};
/**
* Step through the processing of a single byte from the current location of
* the program counter.
* TODO: Refactor the code to only process a single byte per step call
* Step through the processing of a single instruction from the current
* location of the program counter.
*/
this.step = function() {
if(this.interrupt&&(!this.p.i|(this.interrupt===this.INTERRUPT.NMI))) {
@ -364,11 +359,6 @@ function CPU_65816() {
return;
}
var operation = this.opcode_map[b];
// Check if unsupported opcode.
if(operation==null) {
this.executing = false;
return;
}
var bytes_required = operation.bytes_required(this);
if(bytes_required===1) {
operation.execute(this);
@ -385,7 +375,12 @@ function CPU_65816() {
this.executing = false;
};
this.start = function() {
/**
* TODO: Add ability for this function to limit number of cpu cycles per
* second.
*/
this.execute = function(start_address) {
this.r.pc = start_address;
this.executing = true;
while(this.executing) {
this.step();
@ -493,19 +488,6 @@ function MMU() {
}
this.memory[bank][location] = b;
};
this.load_rom = function(raw_hex) {
var loc = 0x8000;
var byte_buffer = [];
for(var i = 0; i < raw_hex.length; i++) {
byte_buffer.push(raw_hex[i]);
if(byte_buffer.length===2) {
this.store_byte(loc, parseInt(byte_buffer[0]+byte_buffer[1], "16"));
loc++;
byte_buffer = [];
}
}
};
}
var STP = {

View File

@ -33,7 +33,8 @@ function test_lda() {
test("Make sure LDA with a constant properly loads an 8-bit value in "+
"8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff");
cpu.load_binary("18fba9ff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xff, "The accumulator should be 0xff when 0xff is "+
"given as its argument in 8-bit "+
"memory/accumulator mode.");
@ -45,7 +46,8 @@ function test_lda() {
test("Make sure LDA with a constant properly loads a 16-bit value in "+
"16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff");
cpu.load_binary("18fbc220a9ffff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xffff, "The accumulator should be 0xffff when 0xffff is "+
"given as its argument in 16-bit "+
"memory/accumulator mode.");
@ -58,7 +60,8 @@ function test_lda() {
test("Make sure LDA with a direct page address loads an 8-bit value in "+
"8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba90185fea5fe");
cpu.load_binary("18fba90185fea5fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 1, "The accumulator should be 1 when 1 is "+
"loaded from $fe(direct page) in 8-bit "+
"memory/accumulator mode.");
@ -70,7 +73,8 @@ function test_lda() {
test("Make sure LDA with a direct page address loads a 16-bit value in "+
"16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a901ff85fea5fe");
cpu.load_binary("18fbc220a901ff85fea5fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xff01, "The accumulator should be 0xff01 when 0xff01 "+
"is loaded from $fe(direct page) in 16-bit "+
"memory/accumulator mode.");
@ -82,7 +86,8 @@ function test_lda() {
test("Make sure LDA with an absolute address loads an 8-bit value in "+
"8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fe8dff0aa900adff0a");
cpu.load_binary("18fba9fe8dff0aa900adff0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfe, "The accumulator should be 0xfe when 0xfe is "+
"loaded from $0aff(absolute) in 8-bit "+
"memory/accumulator mode.");
@ -94,7 +99,8 @@ function test_lda() {
test("Make sure LDA with an absolute address loads a 16-bit value in "+
"16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff8dff0aa90000adff0a");
cpu.load_binary("18fbc220a9ffff8dff0aa90000adff0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xffff, "The accumulator should be 0xffff when 0xffff "+
"is loaded from $0aff and $0b00(absolute) in 16-bit "+
"memory/accumulator mode.");
@ -107,7 +113,8 @@ function test_lda() {
"register loads an 8-bit value in 8-bit memory/accumulator mode.",
function() {
var cpu = new CPU_65816();
cpu.execute("18fba201a9ff85ffa900b5fe");
cpu.load_binary("18fba201a9ff85ffa900b5fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xff, "The accumulator should be 0xff when 0xff "+
"is loaded from direct page address $fe indexed "+
"with x(which is 1) and thus loaded from $ff in "+
@ -124,7 +131,8 @@ function test_lda() {
"register loads a 16-bit value in 16-bit memory/accumulator mode.",
function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a201a9ffff85fea90000bdfd");
cpu.load_binary("18fbc220a201a9ffff85fea90000bdfd", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xffff, "The accumulator should be 0xffff when 0xffff "+
"is loaded from direct page addresses $fe and "+
"$ff after $fd is indexed with the x register("+
@ -140,7 +148,8 @@ function test_lda() {
test("Make sure LDA indirect given a direct page address loads an 8-bit "+
"value in 8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff85fea90a85ffa9068dff0aa900b2fe");
cpu.load_binary("18fba9ff85fea90a85ffa9068dff0aa900b2fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 6, "The accumulator should be 6 when LDA loads an 8-bit "+
"value using an indirect address in 8-bit mode "+
"memory/accumulator mode.");
@ -152,7 +161,8 @@ function test_lda() {
test("Make sure LDA indirect given a direct page address loads a 16-bit "+
"value in 16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ff0a85fea9ffff8dff0aa90000b2fe");
cpu.load_binary("18fbc220a9ff0a85fea9ffff8dff0aa90000b2fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xffff, "The accumulator should be 0xffff when LDA loads "+
"a 16-bit value using an indirect address "+
"loaded from a direct page address.");
@ -164,7 +174,8 @@ function test_lda() {
test("Ensure that LDA absolute indexed by the x register works for 8-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fa8dff0aa201a900bdfe0a");
cpu.load_binary("18fba9fa8dff0aa201a900bdfe0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfa, "The accumulator should be 0xfa when LDA loads "+
"an 8-bit value using absolute indexed x mode "+
"from $0aff");
@ -178,7 +189,8 @@ function test_lda() {
test("Ensure that LDA absolute indexed by the x register works for 16-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9fefa8dff0aa203bdfc0a");
cpu.load_binary("18fbc220a9fefa8dff0aa203bdfc0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfafe, "The accumulator should be 0xfafe when LDA "+
"loads a 16-bit value from $0aff using "+
"absolute indexed x addressing mode.");
@ -192,7 +204,8 @@ function test_lda() {
test("Ensure that LDA absolute indexed by the y register works for 8-bit "+
"memory/acccumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fe8dff0aa002a900b9fd0a");
cpu.load_binary("18fba9fe8dff0aa002a900b9fd0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfe, "The accumulator should be 0xfe when LDA loads an "+
"8-bit value from $0aff using absolute indexed y "+
"addressing mode.");
@ -206,7 +219,8 @@ function test_lda() {
test("Ensure that LDA absolute indexed by the y register works for 16-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9fefa8dff0aa003a90000b9fc0a");
cpu.load_binary("18fbc220a9fefa8dff0aa003a90000b9fc0a", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfafe, "The accumulator should be 0xfafe when LDA loads "+
"a 16-bit value from $0aff using absolute "+
"indexed y addressing mode.");
@ -220,7 +234,8 @@ function test_lda() {
test("Ensure that LDA stack relative works for 8-bit memory/accumulator "+
"mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fe48a90148a900a302");
cpu.load_binary("18fba9fe48a90148a900a302", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfe, "The accumulator should be 0xfe when LDA loads "+
"an 8-bit value from the stack using LDA stack "+
"relative addressing mode.");
@ -232,7 +247,8 @@ function test_lda() {
test("Ensure that LDA stack relative works for 16-bit memory/accumulator "+
"mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9fefa48a9010048a90000a303");
cpu.load_binary("18fbc220a9fefa48a9010048a90000a303", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfafe, "The accumulator should be 0xfafe when LDA "+
"loads a 16-bit value from the stack using LDA "+
"stack relative addressing mode.");
@ -244,7 +260,8 @@ function test_lda() {
test("Ensure that LDA absolute long works for 8-bit memory/accumulator "+
"mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fa8fffeeaaa900afffeeaa");
cpu.load_binary("18fba9fa8fffeeaaa900afffeeaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfa, "The accumulator should be 0xfa when LDA "+
"loads an 8-bit value from $aaeeff using "+
"absolute long addressing mode.");
@ -256,7 +273,8 @@ function test_lda() {
test("Ensure that LDA absolute long works for 16-bit memory/accumulator "+
"mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9fefa8fffeeaaa90000afffeeaa");
cpu.load_binary("18fbc220a9fefa8fffeeaaa90000afffeeaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfafe, "The accumulator should be 0xfafe when LDA "+
"loads a 16-bit value from $aaeeff using "+
"absolute long addressing mode.");
@ -268,7 +286,8 @@ function test_lda() {
test("Ensure that LDA absolute long indexed by the x register works for "+
"8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9fe8fffeeaaa202a900bffdeeaa");
cpu.load_binary("18fba9fe8fffeeaaa202a900bffdeeaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfe, "The accumulator should be 0xfe when LDA "+
"loads an 8-bit value from $aaeeff using "+
"absolute long indexed x addressing mode.");
@ -282,7 +301,8 @@ function test_lda() {
test("Ensure that LDA absolute long indexed by the x register works for "+
"16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9fefa8fffeeaaa203a90000bffceeaa");
cpu.load_binary("18fbc220a9fefa8fffeeaaa203a90000bffceeaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfafe, "The accumulator should be 0xfafe when LDA "+
"loads a 16-bit value from $aaeeff using "+
"absolute long indexed x addressing mode.");
@ -299,7 +319,8 @@ function test_stz() {
module("STZ");
test("Test STZ direct page for 8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff85fa64faa5fa");
cpu.load_binary("18fba9ff85fa64faa5fa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from a "+
"direct page addresss that has had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -308,7 +329,8 @@ function test_stz() {
});
test("Test STZ direct page for 16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff85fa64faa5fa");
cpu.load_binary("18fbc220a9ffff85fa64faa5fa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from a "+
"direct page address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -317,7 +339,8 @@ function test_stz() {
});
test("Test STZ absolute for 8-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff8d34129c3412ad3412");
cpu.load_binary("18fba9ff8d34129c3412ad3412", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from an "+
"absolute address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -326,7 +349,8 @@ function test_stz() {
});
test("Test STZ absolute for 16-bit memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff8d34129c3412ad3412");
cpu.load_binary("18fbc220a9ffff8d34129c3412ad3412", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from an "+
"absolute page address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -336,7 +360,8 @@ function test_stz() {
test("Test STZ direct page indexed by the x register for 8-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff85fb85faa20174faa5fb");
cpu.load_binary("18fba9ff85fb85faa20174faa5fb", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from a "+
"direct page addresss that has had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -346,7 +371,8 @@ function test_stz() {
test("Test STZ direct page indexed by the x register for 16-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff85faa20274f8a5fa");
cpu.load_binary("18fbc220a9ffff85faa20274f8a5fa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from a "+
"direct page address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -356,7 +382,8 @@ function test_stz() {
test("Test STZ absolute indexed by the x register for 8-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fba9ff8dbbaa8dbaaaa2019ebaaaadbbaa");
cpu.load_binary("18fba9ff8dbbaa8dbaaaa2019ebaaaadbbaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from an "+
"absolute address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -366,7 +393,8 @@ function test_stz() {
test("Test STZ absolute indexed by the x register for 16-bit "+
"memory/accumulator mode.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220a9ffff8dbbaaa2029eb9aaadbbaa");
cpu.load_binary("18fbc220a9ffff8dbbaaa2029eb9aaadbbaa", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "The accumulator should be zero after loading from an "+
"absolute page address that had zero stored to it.");
equals(cpu.p.e, 0, "The hidden e flag should be zero for native mode.");
@ -380,7 +408,8 @@ function test_emulation_mode() {
test("Make sure pulling from the stack when the stack register is at 0x1ff"+
"causes the stack register to pull from 0x100.", function() {
var cpu = new CPU_65816();
cpu.execute("a9fe8d0001a90068");
cpu.load_binary("a9fe8d0001a90068", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.s, 0, "The stack register should be 0 after the pull "+
"operation.");
equals(cpu.r.a, 0xfe, "The accumulator should be 0xfe after the pull "+
@ -392,7 +421,9 @@ function test_mvn_and_mvp() {
module("MVN and MVP");
test("Test a short example program for MVP", function() {
var cpu = new CPU_65816();
cpu.execute("18fbe230a9ab8dff0fa9cd8d0010c230a90100a20010a00020440000");
cpu.load_binary("18fbe230a9ab8dff0fa9cd8d0010c230a90100a20010a00020440000",
0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xffff, "After executing the example program the "+
"accumulator should've underflowed and "+
"resulted in 0xffff.");
@ -415,7 +446,8 @@ function test_subroutines() {
var cpu = new CPU_65816();
// It jumps to 0xffff so it doesn't execute the subroutine again and
// effectively halts the program.
cpu.execute("18fbc23018a9ffff200e804cffff3a60");
cpu.load_binary("18fbc23018a9ffff200e804cffff3a60", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xfffe, "The subroutine should execute exactly once, "+
"decrementing 0xffff to 0xfffe.");
});
@ -425,7 +457,8 @@ function test_cmp() {
module("CMP");
test("Compare two 8-bit numbers, 0x01 and 0xff", function() {
var cpu = new CPU_65816();
cpu.execute("18fbe23018a901c9ff");
cpu.load_binary("18fbe23018a901c9ff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x01, "CMP should not change the value of the "+
"accumulator");
equals(cpu.p.z, 0, "When comparing 0x01 and 0xff the zero(z) bit "+
@ -437,7 +470,8 @@ function test_cmp() {
});
test("Compare two 16-bit numbers, 0xff01 and 0xfeff", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc23018a901ffc9fffe");
cpu.load_binary("18fbc23018a901ffc9fffe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xff01, "CMP should not change the value of the "+
"accumulator");
equals(cpu.p.n, 0, "When comparing 0xff01 and 0xfeff the negative(n) "+
@ -454,7 +488,8 @@ function test_sbc() {
test("Test normal subtraction of two 8-bit numbers that don't cause a "+
"borrow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbe230a90138e901");
cpu.load_binary("18fbe230a90138e901", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "0x01 - 0x01 should result in zero when using "+
"SBC");
equals(cpu.p.z, 1, "0x01 - 0x01 should set the zero(z) bit when "+
@ -470,7 +505,8 @@ function test_sbc() {
test("Test normal subtraction of two 16-bit numbers that don't cause a "+
"borrow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc230a9010038e90100");
cpu.load_binary("18fbc230a9010038e90100", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0, "0x0001 - 0x0001 should result in zero when using "+
"SBC");
equals(cpu.p.z, 1, "0x0001 - 0x0001 should set the zero(z) bit when "+
@ -485,7 +521,8 @@ function test_sbc() {
test("Test subtraction that triggers a borrow with 8-bit numbers",
function() {
var cpu = new CPU_65816();
cpu.execute("18fbe230a9d038e9ef");
cpu.load_binary("18fbe230a9d038e9ef", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xe1, "0xd0 - 0xef should set the accumulator to 0xe1 "+
"when using SBC");
equals(cpu.p.n, 1, "0xd0 - 0xef should set the negative(n) bit when "+
@ -500,7 +537,8 @@ function test_sbc() {
test("Test subtraction that triggers a borrow with 16-bit numbers",
function() {
var cpu = new CPU_65816();
cpu.execute("18fbc230a900d038e900ef");
cpu.load_binary("18fbc230a900d038e900ef", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0xe100, "0xd000 - 0xef00 should set the accumulator to "+
"0xe0ff when using SBC");
equals(cpu.p.n, 1, "0xd000 - 0xef00 should set the negative(n) bit when "+
@ -515,7 +553,8 @@ function test_sbc() {
test("Test subtraction with decimal mode on with two single digit 8-bit "+
"numbers.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbf8a90938e905");
cpu.load_binary("18fbf8a90938e905", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 4, "The accumulator should be 4 after subtracting 0x5 "+
"0x9 with decimal mode on with 8-bit "+
"memory/accumulator mode.");
@ -529,7 +568,8 @@ function test_sbc() {
test("Test subtraction with decimal mode on with two double digit 8-bit "+
"numbers.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbf8a99038e949");
cpu.load_binary("18fbf8a99038e949", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x41, "The accumulator should be 41 after subtracting 0x49 "+
"from 0x90 with decimal mode on with 8-bit "+
"memory/accumulator mode.");
@ -543,7 +583,8 @@ function test_sbc() {
test("Test subtraction with decimal mode on with 8-bit numbers that causes "+
"a borrow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbf8a91038e920");
cpu.load_binary("18fbf8a91038e920", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x90, "The accumulator should be 0x90 after subtracting "+
"0x20 from 0x10 with decimal and 8-bit "+
"memory/accumulator modes.");
@ -557,7 +598,8 @@ function test_sbc() {
test("Test subtraction of two single digit 16-bit numbers with decimal "+
"mode set.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220f8a9050038e90200");
cpu.load_binary("18fbc220f8a9050038e90200", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x03, "The accumulator should be 0x03 after subtracting "+
"0x02 from 0x05 with decimal and 16-bit "+
"memory/accumulator modes.");
@ -571,7 +613,8 @@ function test_sbc() {
test("Test subtraction of two four digit 16-bit numbers with decimal "+
"mode set.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220f8a9999938e91111");
cpu.load_binary("18fbc220f8a9999938e91111", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8888, "The accumulator should be 0x8888 after "+
"subtracting 0x1111 from 0x9999 with decimal "+
"and 16-bit memory/accumulator modes.");
@ -585,7 +628,8 @@ function test_sbc() {
test("Test subtraction of two four digit 16-bit numbers with decimal "+
"mode set that causes a borrow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc220f8a9111138e99999");
cpu.load_binary("18fbc220f8a9111138e99999", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x1112, "The accumulator should be 0x1112 after "+
"subtracting 0x9999 from 0x1111 with decimal "+
"and 16-bit memory/accumulator modes.");
@ -603,7 +647,8 @@ function test_adc() {
test("Test normal addition of two 16-bit numbers that don't cause an "+
"overflow (m bit is 0)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a90100690100");
cpu.load_binary("18fb18c230a90100690100", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 2, "0x0001 + 0x0001 should result in 0x0002 when using "+
"ADC");
equals(cpu.p.n, 0, "0x0001 + 0x0001 does not result in a negative "+
@ -618,7 +663,8 @@ function test_adc() {
test("Test normal addition of two 8-bit numbers that don't cause an "+
"overflow (m bit is 1)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a9016901");
cpu.load_binary("18fb18e230a9016901", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 2, "0x01 + 0x01 should result in 0x02 when using "+
"ADC");
equals(cpu.p.n, 0, "0x01 + 0x01 does not result in a negative "+
@ -634,7 +680,8 @@ function test_adc() {
test("Test that overflow sets the carry flag and works in general with two"+
"16-bit numbers (m bit is 0)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a9ffff690100");
cpu.load_binary("18fb18c230a9ffff690100", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.c, 1, "0xffff + 0x0001 should set the carry bit when using "+
"ADC");
equals(cpu.r.a, 0, "0xffff + 0x0001 should result in the accumulator "+
@ -650,7 +697,8 @@ function test_adc() {
test("Test that overflow sets the carry flag and works in general with two"+
"8-bit numbers (m bit is 1)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a9ff6901");
cpu.load_binary("18fb18e230a9ff6901", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.c, 1, "0xff + 0x01 should set the carry bit when using "+
"ADC");
equals(cpu.r.a, 0, "0xff + 0x01 should result in the accumulator "+
@ -665,7 +713,8 @@ function test_adc() {
test("Test signed overflow with two 8-bit numbers (m bit is 1)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a97f6901");
cpu.load_binary("18fb18e230a97f6901", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x80, "0x7f + 0x01 should result in 0x80 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7f + 0x01 should set the overflow(v) bit when "+
@ -679,7 +728,8 @@ function test_adc() {
});
test("Test signed overflow with two 16-bit numbers (m bit is 0)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a9ff7f690100");
cpu.load_binary("18fb18c230a9ff7f690100", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8000, "0x7fff + 0x0001 should result in 0x8000 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7fff + 0x0001 should set the overflow(v) bit when "+
@ -694,7 +744,8 @@ function test_adc() {
test("Test ADC direct page with 8-bit numbers (m bit is 1)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a90185ffa97f65ff");
cpu.load_binary("18fb18e230a90185ffa97f65ff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x80, "0x7f + 0x01 should result in 0x80 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7f + 0x01 should set the overflow(v) bit when "+
@ -709,7 +760,8 @@ function test_adc() {
test("Test ADC direct page with 16-bit numbers (m bit is 0)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a9010085fea9ff7f65fe");
cpu.load_binary("18fb18c230a9010085fea9ff7f65fe", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8000, "0x7fff + 0x0001 should result in 0x8000 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7fff + 0x0001 should set the overflow(v) bit when "+
@ -724,7 +776,8 @@ function test_adc() {
test("Test ADC absolute with 8-bit numbers (m bit is 1)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a9018dffffa97f6dffff");
cpu.load_binary("18fb18e230a9018dffffa97f6dffff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x80, "0x7f + 0x01 should result in 0x80 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7f + 0x01 should set the overflow(v) bit when "+
@ -739,7 +792,8 @@ function test_adc() {
test("Test ADC absolute with 16-bit numbers (m bit is 0)", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a901008dffffa9ff7f6dffff");
cpu.load_binary("18fb18c230a901008dffffa9ff7f6dffff", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8000, "0x7fff + 0x0001 should result in 0x8000 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7fff + 0x0001 should set the overflow(v) bit when "+
@ -755,7 +809,8 @@ function test_adc() {
test("Test ADC direct page indirect with 8-bit numbers (m bit is 1)",
function() {
var cpu = new CPU_65816();
cpu.execute("18fb18e230a90185ffa9ff85fd64fea97f72fd");
cpu.load_binary("18fb18e230a90185ffa9ff85fd64fea97f72fd", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x80, "0x7f + 0x01 should result in 0x80 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7f + 0x01 should set the overflow(v) bit when "+
@ -770,7 +825,8 @@ function test_adc() {
test("Test ADC direct page indirect with 16-bit numbers (m bit is 0)",
function() {
var cpu = new CPU_65816();
cpu.execute("18fb18c230a901008500a9000085bba9ff7f72bb");
cpu.load_binary("18fb18c230a901008500a9000085bba9ff7f72bb", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8000, "0x7fff + 0x0001 should result in 0x8000 when "+
"using ADC");
equals(cpu.p.v, 1, "0x7fff + 0x0001 should set the overflow(v) bit when "+
@ -786,7 +842,8 @@ function test_adc() {
test("Test that ADC handles decimal mode with legal BCD numbers in 8-bit "+
"memory/accumulator mode with single digit numbers.", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8a9056905");
cpu.load_binary("18fb18f8a9056905", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x10, "0x05 + 0x05 should result in 0x10 with decimal "+
"mode on and with 8-bit memory/accumulator mode.");
equals(cpu.p.c, 0, "The carry flag of the p status register should be "+
@ -801,7 +858,8 @@ function test_adc() {
test("Test that ADC handles decimal mode with legal BCD numbers in 8-bit "+
"memory/accumulator mode with double digit numbers.", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8a9156926");
cpu.load_binary("18fb18f8a9156926", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x41, "0x15 + 0x26 should result in 0x41 with decimal "+
"mode on and with 8-bit memory/accumulator mode.");
equals(cpu.p.c, 0, "The carry flag of the p status register should be "+
@ -817,7 +875,8 @@ function test_adc() {
"memory/accumulator mode with double digit numbers with the carry "+
"bit set", function() {
var cpu = new CPU_65816();
cpu.execute("18fb38f8a9156926");
cpu.load_binary("18fb38f8a9156926", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x42, "0x15 + 0x26 should result in 0x42 with decimal "+
"mode on and with 8-bit memory/accumulator mode "+
"and the carry bit set.");
@ -834,7 +893,8 @@ function test_adc() {
"memory/accumulator mode when adding two numbers that cause an "+
"overflow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8a9556960");
cpu.load_binary("18fb18f8a9556960", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x16, "0x55 + 0x60 should result in 0x16 with decimal "+
"mode on and with 8-bit memory/accumulator mode.");
equals(cpu.p.c, 1, "The carry flag of the p status register should be "+
@ -850,7 +910,8 @@ function test_adc() {
"memory/accumulator mode when adding two single digit numbers.",
function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8c220a90100690900");
cpu.load_binary("18fb18f8c220a90100690900", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x10, "0x0001 + 0x0009 should result in 0x0010 with "+
"decimal mode on and with 16-bit "+
"memory/accumulator mode.");
@ -867,7 +928,8 @@ function test_adc() {
"memory/accumulator mode when adding two four digit numbers.",
function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8c220a90110699939");
cpu.load_binary("18fb18f8c220a90110699939", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x5000, "0x1001 + 0x3999 should result in 0x5000 with "+
"decimal mode on and with 16-bit "+
"memory/accumulator mode.");
@ -884,7 +946,8 @@ function test_adc() {
"memory/accumulator mode when adding two numbers that cause an "+
"overflow.", function() {
var cpu = new CPU_65816();
cpu.execute("18fb18f8c220a99756699999");
cpu.load_binary("18fb18f8c220a99756699999", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x5697, "0x5697 + 0x9999 should result in 0x5697 with "+
"decimal mode on and with 16-bit "+
"memory/accumulator mode.");
@ -901,7 +964,8 @@ function test_adc() {
"memory/accumulator mode when adding two four digit numbers with the "+
"carry bit set.", function() {
var cpu = new CPU_65816();
cpu.execute("18fb38f8c220a90110699939");
cpu.load_binary("18fb38f8c220a90110699939", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x5001, "0x1001 + 0x3999 should result in 0x5001 with "+
"decimal mode on and with 16-bit "+
"memory/accumulator mode and the carry flag set.");
@ -921,9 +985,8 @@ function test_branching() {
test("Test that BRA with 0x00 as its argument doesn't increment or "+
"decrement the program counter", function() {
var cpu = new CPU_65816();
cpu.execute("8000");
// NOTE: 0x8003 is subject to change however I decide to lay out memory
// eventually.
cpu.load_binary("8000", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.pc, 0x8003, "Make sure that the program counter isn't "+
"incremented or decremented if BRA is given "+
"0x00 as its argument.");
@ -932,12 +995,16 @@ function test_branching() {
test("Check that the branching operations properly treat the argument as "+
"a two's complement number", function() {
var cpu = new CPU_65816();
cpu.execute("80f0"); // negative two's complement number 0xf0 = -16
// negative two's complement number 0xf0 = -16
cpu.load_binary("80f0", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.pc, (0x8003-16), "A branching operation when given a "+
"negative two's complement number should "+
"decrement the program counter by the "+
"proper amount.");
cpu.execute("8020"); // positive two's complement number.
"proper amount.");
cpu.reset();
cpu.load_binary("8020", 0x8000); // positive two's complement number.
cpu.execute(0x8000);
equals(cpu.r.pc, (0x8003+0x20), "A branching operation when given a "+
"positive two's complement number should "+
"increment the program counter by the "+
@ -946,14 +1013,16 @@ function test_branching() {
test("Check that BPL works as expected", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc230a9fe7f1a10fd");
cpu.load_binary("18fbc230a9fe7f1a10fd", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x8000, "Check that branching only occurs while the "+
"number is a two's complement positive number.");
});
test("Check that BMI works as expected", function() {
var cpu = new CPU_65816();
cpu.execute("18fbc230a901803a30fd");
cpu.load_binary("18fbc230a901803a30fd", 0x8000);
cpu.execute(0x8000);
equals(cpu.r.a, 0x7fff, "Check that branching only occurs while the "+
"number is a two's complement negative number.");
});
@ -964,7 +1033,8 @@ function test_sep() {
test("Test 'SEP #$30' not in emulation mode", function() {
var cpu = new CPU_65816();
cpu.p.e = 0;
cpu.execute("e230");
cpu.load_binary("e230", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.m, 1, "'SEP #$30' should set the m status bit of the p "+
"register to 1");
equals(cpu.p.x, 1, "'SEP #$30' should set the x status bit of the p "+
@ -985,7 +1055,8 @@ function test_sep() {
test("Test 'SEP #$cf' not in emulation mode", function() {
var cpu = new CPU_65816();
cpu.p.e = 0;
cpu.execute("e2cf");
cpu.load_binary("e2cf", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.m, 0, "'SEP #$cf' should not set the m status bit of the p "+
"register to 1");
equals(cpu.p.x, 0, "'SEP #$cf' should not set the x status bit of the p "+
@ -1019,7 +1090,8 @@ function test_rep() {
cpu.p.x = 1;
cpu.p.m = 1;
cpu.p.z = 1;
cpu.execute("c230");
cpu.load_binary("c230", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.m, 0, "'REP #$30' should clear the m bit of the p status "+
"register");
equals(cpu.p.x, 0, "'REP #$30' should clear the x bit of the p status "+
@ -1050,7 +1122,8 @@ function test_rep() {
cpu.p.x = 1;
cpu.p.m = 1;
cpu.p.z = 1;
cpu.execute("c2cf");
cpu.load_binary("c2cf", 0x8000);
cpu.execute(0x8000);
equals(cpu.p.m, 1, "'REP #$cf' should not clear the m bit of the p "+
"status register");
equals(cpu.p.x, 1, "'REP #$cf' should not clear the x bit of the p "+