aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzedarider <ymherklotz@gmail.com>2016-10-27 18:53:16 +0100
committerzedarider <ymherklotz@gmail.com>2016-10-27 18:53:16 +0100
commit72b51899b0d71a43af81c89a5eeeedb08c2b6d0b (patch)
tree46828b93573164544da8058cf2b8789bd7d7fa66
parent58e3d34252d003f748b73d55b81155a5f76c0a54 (diff)
downloadMipsCPU-72b51899b0d71a43af81c89a5eeeedb08c2b6d0b.tar.gz
MipsCPU-72b51899b0d71a43af81c89a5eeeedb08c2b6d0b.zip
Finished cpu completely except some corner cases
-rw-r--r--src/shared/mips_mem_ram.obin10000 -> 10016 bytes
l---------src/ymh15/.#mips_cpu.cpp1
-rw-r--r--src/ymh15/2test_mips.cpp482
-rw-r--r--src/ymh15/mips_cpu.cpp270
-rw-r--r--src/ymh15/mips_cpu.obin25904 -> 27856 bytes
-rw-r--r--src/ymh15/mips_cpu_ymh15.hpp2
-rw-r--r--src/ymh15/mips_instruction_test.h74
-rwxr-xr-xsrc/ymh15/test_mipsbin341840 -> 448336 bytes
-rw-r--r--src/ymh15/test_mips.cpp1639
-rw-r--r--src/ymh15/test_mips.h74
-rw-r--r--src/ymh15/test_mips.obin46200 -> 216592 bytes
-rw-r--r--src/ymh15/test_mips_ymh15.hpp1
12 files changed, 1971 insertions, 572 deletions
diff --git a/src/shared/mips_mem_ram.o b/src/shared/mips_mem_ram.o
index 718d8dc..b954d72 100644
--- a/src/shared/mips_mem_ram.o
+++ b/src/shared/mips_mem_ram.o
Binary files differ
diff --git a/src/ymh15/.#mips_cpu.cpp b/src/ymh15/.#mips_cpu.cpp
deleted file mode 120000
index 5a5142f..0000000
--- a/src/ymh15/.#mips_cpu.cpp
+++ /dev/null
@@ -1 +0,0 @@
-yannherklotz@Yann-Arch.800:1477569971 \ No newline at end of file
diff --git a/src/ymh15/2test_mips.cpp b/src/ymh15/2test_mips.cpp
new file mode 100644
index 0000000..75afaa8
--- /dev/null
+++ b/src/ymh15/2test_mips.cpp
@@ -0,0 +1,482 @@
+#include "../../include/mips.h"
+#include "test_mips_ymh15.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+int main(int argc, char** argv) {
+ mips_mem_h ram = mips_mem_create_ram(4096);
+ mips_cpu_h cpu = mips_cpu_create(ram);
+
+ srand(time(NULL));
+
+ if(argc == 2) {
+ mips_cpu_set_debug_level(cpu, argv[1][0]-'0', stdout);
+ } else {
+ mips_cpu_set_debug_level(cpu, 0, NULL);
+ }
+
+ mips_test_begin_suite();
+
+ int testId = mips_test_begin_test("ADD");
+ mips_test_end_test(testId, test_add(ram, cpu, ADD, 0x3fffffff, 0, 10), "Testing the adder without overflow");
+
+ testId = mips_test_begin_test("ADD");
+ mips_test_end_test(testId, !test_add(ram, cpu, ADD, 0x7fffffff, 1, 1), "Testing the adder with overflow");
+
+ testId = mips_test_begin_test("ADDU");
+ mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x3fffffff, 0, 10), "testing without overflow");
+
+ testId = mips_test_begin_test("ADDU");
+ mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x7fffffff, 1, 1), "Testing the adder with overflow");
+
+ testId = mips_test_begin_test("SUB");
+ mips_test_end_test(testId, test_add(ram, cpu, SUB, 0x3fffffff, 0, 10), "Testing the adder without overflow");
+
+ testId = mips_test_begin_test("SUB");
+ mips_test_end_test(testId, !test_add(ram, cpu, SUB, 0x7fffffff, 1, 1), "Testing the adder with overflow");
+
+ testId = mips_test_begin_test("SUBU");
+ mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x3fffffff, 0, 10), "Testing the adder without overflow");
+
+ testId = mips_test_begin_test("SUBU");
+ mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x7fffffff, 1, 1), "Testing the adder with overflow");
+
+ testId = mips_test_begin_test("AND");
+ mips_test_end_test(testId, test_bitwise(ram, cpu, AND), "Testing bitwise and");
+
+ testId = mips_test_begin_test("OR");
+ mips_test_end_test(testId, test_bitwise(ram, cpu, OR), "Testing bitwise or");
+
+ testId = mips_test_begin_test("XOR");
+ mips_test_end_test(testId, test_bitwise(ram, cpu, XOR), "Testing bitwise xor");
+
+ testId = mips_test_begin_test("ADDI");
+ mips_test_end_test(testId, test_I(ram, cpu, ADDI, 20, 10), "Testing addi");
+
+ testId = mips_test_begin_test("ADDIU");
+ mips_test_end_test(testId, test_I(ram, cpu, ADDIU, 20, 10), "Testing addiu");
+
+ testId = mips_test_begin_test("ANDI");
+ mips_test_end_test(testId, test_I(ram, cpu, ANDI, 20, 10), "Testing addi");
+
+ testId = mips_test_begin_test("ORI");
+ mips_test_end_test(testId, test_I(ram, cpu, ORI, 20, 10), "Testing addi");
+
+ testId = mips_test_begin_test("XORI");
+ mips_test_end_test(testId, test_I(ram, cpu, XORI, 20, 10), "Testing addi");
+
+ testId = mips_test_begin_test("BEQ");
+ mips_test_end_test(testId, test_branch(ram, cpu, 4, 4, 0, 9, 4), "Testing BEQ");
+
+ testId = mips_test_begin_test("BNE");
+ mips_test_end_test(testId, test_branch(ram, cpu, 5, 4, 0, 9, 10), "Testing BNE");
+
+ testId = mips_test_begin_test("BGEZ");
+ mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 0, 1, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("BLEZ");
+ mips_test_end_test(testId, test_branch(ram, cpu, 6, -1, 0, 0, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("BGTZ");
+ mips_test_end_test(testId, test_branch(ram, cpu, 7, 4, 0, 0, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("BGEZAL");
+ mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 1, 17, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("BLTZAL");
+ mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 1, 16, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("BLTZ");
+ mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 0, 16, 20), "Testing BGEZ");
+
+ testId = mips_test_begin_test("J");
+ mips_test_end_test(testId, test_jump(ram, cpu, J), "Testing J");
+
+ testId = mips_test_begin_test("JAL");
+ mips_test_end_test(testId, test_jump(ram, cpu, JAL), "Testing JAL");
+
+ testId = mips_test_begin_test("JALR");
+ mips_test_end_test(testId, test_jump(ram, cpu, JALR), "Testing JALR");
+
+ testId = mips_test_begin_test("JR");
+ mips_test_end_test(testId, test_jump(ram, cpu, JR), "Testing JR");
+
+ testId = mips_test_begin_test("LB");
+ mips_test_end_test(testId, test_load(ram, cpu, LB, 0xf7), "Testing LB");
+
+ testId = mips_test_begin_test("LBU");
+ mips_test_end_test(testId, test_load(ram, cpu, LBU, 0xf7), "Testing LBU");
+
+ testId = mips_test_begin_test("LH");
+ mips_test_end_test(testId, test_load(ram, cpu, LH, 0xff7f), "Testing LH");
+
+ testId = mips_test_begin_test("LHU");
+ mips_test_end_test(testId, test_load(ram, cpu, LHU, 0xff7f), "Testing LHU");
+
+ testId = mips_test_begin_test("LW");
+ mips_test_end_test(testId, test_load(ram, cpu, LW, 0xffffff7f), "Testing LW");
+
+ testId = mips_test_begin_test("LUI");
+ mips_test_end_test(testId, test_load(ram, cpu, LUI, 0xff7f), "Testing LUI");
+
+ testId = mips_test_begin_test("LWL");
+ mips_test_end_test(testId, test_load(ram, cpu, LWL, 0xff6fff7f), "Testing LWL");
+
+ testId = mips_test_begin_test("LWR");
+ mips_test_end_test(testId, test_load(ram, cpu, LWR, 0xff6fff7f), "Testing LWR");
+
+ testId = mips_test_begin_test("MULT");
+ mips_test_end_test(testId, test_mult_div(ram, cpu, MULT, 5, -4), "Testing LWR");
+
+ testId = mips_test_begin_test("MULTU");
+ mips_test_end_test(testId, test_mult_div(ram, cpu, MULTU, 5, -4), "Testing LWR");
+
+ testId = mips_test_begin_test("DIV");
+ mips_test_end_test(testId, test_mult_div(ram, cpu, DIV, 5, -4), "Testing LWR");
+
+ testId = mips_test_begin_test("DIVU");
+ mips_test_end_test(testId, test_mult_div(ram, cpu, DIVU, 5, -4), "Testing LWR");
+
+ mips_test_end_suite();
+ return 0;
+}
+
+// R Type
+uint32_t gen_instruction(uint32_t src1, uint32_t src2, uint32_t dest,
+ uint32_t shift, uint32_t function) {
+ uint32_t inst = 0;
+ inst = inst | src1 << 21 | src2 << 16 | dest << 11 | shift << 6 |
+ function;
+ return inst;
+}
+
+// I Type
+uint32_t gen_instruction(uint32_t opcode, uint32_t src, uint32_t dest,
+ uint32_t Astart) {
+ uint32_t inst = 0;
+ inst = inst | opcode << 26 | src << 21 | dest << 16 | Astart;
+ return inst;
+}
+
+// J Type
+uint32_t gen_instruction(uint32_t opcode, uint32_t memory) {
+ uint32_t inst = 0;
+ inst = inst | opcode << 26 | memory;
+ return inst;
+}
+
+uint32_t change_endianness(uint32_t inst) {
+ inst = (inst << 24 | ((inst << 8)&0xff0000) |
+ ((inst >> 8)&0xff00) |inst >> 24);
+ return inst;
+}
+
+int test_add(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, uint32_t max, uint8_t value, unsigned i_t) {
+
+ uint32_t inst, ans, a, b;
+
+ for(unsigned i = 0; i < i_t; ++i) {
+ mips_error mips_err;
+ mips_cpu_reset(cpu);
+ inst = change_endianness(gen_instruction(9, 10, 8, 0, type));
+ if(value) {
+ a = max;
+ if(type > 0x21) {
+ b = -max;
+ } else {
+ b = max;
+ }
+ } else {
+ a = rand() % max;
+ b = rand() % max;
+ }
+
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+
+ mips_cpu_set_register(cpu, 9, a);
+ mips_cpu_set_register(cpu, 10, b);
+
+ mips_err = mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 8, &ans);
+
+ if(type < 0x22) {
+ //printf("%#10x + %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
+ if(mips_err == mips_ExceptionArithmeticOverflow || a+b!=ans) {
+ return 0;
+ }
+ } else {
+ //printf("%#10x - %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
+ if(mips_err == mips_ExceptionArithmeticOverflow || a-b!=ans) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int test_bitwise(mips_mem_h ram, mips_cpu_h cpu, uint8_t op) {
+ uint32_t a, b, ans, inst;
+ int passed;
+ for(unsigned i = 0; i < 10; ++i) {
+ passed = 0;
+ mips_cpu_reset(cpu);
+ inst = change_endianness(gen_instruction(8, 9, 7, 0, op));
+
+ a = rand() % 0xffffffff;
+ b = rand() % 0xffffffff;
+
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+
+ mips_cpu_set_register(cpu, 8, a);
+ mips_cpu_set_register(cpu, 9, b);
+
+ mips_error mips_err = mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 7, &ans);
+
+ if(op == AND) {
+ //printf("%#10x & %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
+ if((a & b) == ans) {
+ passed = 1;
+ }
+ } else if(op == OR) {
+ //printf("%#10x | %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
+ if((a | b) == ans) {
+ passed = 1;
+ }
+ } else {
+ //printf("%#10x ^ %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
+ if((a ^ b) == ans) {
+ passed = 1;
+ }
+ }
+
+
+ if(mips_err != mips_Success || !passed) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int test_I(mips_mem_h ram, mips_cpu_h cpu, uint32_t type,
+ uint32_t num1, uint32_t num2) {
+ int passed = 0;
+ uint32_t result, inst;
+
+ mips_cpu_reset(cpu);
+ inst = change_endianness(gen_instruction(type, 8, 7, num1));
+
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+ mips_cpu_set_register(cpu, 8, num2);
+
+ mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 7, &result);
+
+ switch(type) {
+ case 8:
+ if(result == num1 + num2) {
+ passed = 1;
+ }
+ case 9:
+ if(result == num1 + num2) {
+ passed = 1;
+ }
+ case 12:
+ if(result == (num1 & num2)) {
+ passed = 1;
+ }
+ case 13:
+ if(result == (num1 | num2)) {
+ passed = 1;
+ }
+ case 14:
+ if(result == (num1 ^ num2)) {
+ passed = 1;
+ }
+ default:;
+ }
+
+ return passed;
+}
+
+int test_branch(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t a, uint8_t l, uint32_t opc2, uint32_t b) {
+ int passed = 0;
+ int pass = 0;
+ uint32_t reg10, reg11, reg31, pc_set;
+ pc_set = 32;
+ mips_cpu_reset(cpu);
+ mips_cpu_set_pc(cpu, pc_set);
+
+ uint32_t inst = change_endianness(gen_instruction(opcode, 8, opc2, 3));
+ mips_mem_write(ram, pc_set, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(8, 9, 10, 0, ADDU));
+ mips_mem_write(ram, pc_set+4, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(8, 12, 11, 0, ADDU));
+ mips_mem_write(ram, pc_set+16, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(8, 13, 10, 0, ADDU));
+ mips_mem_write(ram, pc_set+8, 4, (uint8_t*)&inst);
+
+ mips_cpu_set_register(cpu, 8, a);
+ mips_cpu_set_register(cpu, 9, b);
+ mips_cpu_set_register(cpu, 12, 30);
+ mips_cpu_set_register(cpu, 13, 100);
+
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 10, &reg10);
+ mips_cpu_get_register(cpu, 11, &reg11);
+
+ if(l == 1) {
+ mips_cpu_get_register(cpu, 31, &reg31);
+ if(reg31 == pc_set+8) {
+ pass = 1;
+ }
+ } else {
+ pass = 1;
+ }
+
+ if(reg10 == a+b && reg11 == a+30 && pass) {
+ passed = 1;
+ } else {
+ passed = 0;
+ }
+
+ return passed;
+}
+
+int test_jump(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode) {
+ int passed = 0;
+ uint32_t inst, reg10, reg13, reg16, reg31;
+
+ mips_cpu_reset(cpu);
+
+ if(opcode == 2 || opcode == 3) {
+ inst = change_endianness(gen_instruction(opcode, 0x20));
+ } else if(opcode == 8 || opcode == 9) {
+ inst = change_endianness(gen_instruction(25, 0, 31, 0, opcode));
+ }
+
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+
+ inst = change_endianness(gen_instruction(8, 9, 10, 0, ADDU));
+ mips_mem_write(ram, 4, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(11, 12, 13, 0, ADDU));
+ mips_mem_write(ram, 8, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(14, 15, 16, 0, ADDU));
+ mips_mem_write(ram, 0x20<<2, 4, (uint8_t*)&inst);
+
+ mips_cpu_set_register(cpu, 8, 8);
+ mips_cpu_set_register(cpu, 9, 9);
+ mips_cpu_set_register(cpu, 10, 10);
+ mips_cpu_set_register(cpu, 11, 11);
+ mips_cpu_set_register(cpu, 12, 12);
+ mips_cpu_set_register(cpu, 13, 13);
+ mips_cpu_set_register(cpu, 14, 14);
+ mips_cpu_set_register(cpu, 15, 15);
+ mips_cpu_set_register(cpu, 16, 16);
+ mips_cpu_set_register(cpu, 25, 0x20<<2);
+
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 10, &reg10);
+ mips_cpu_get_register(cpu, 13, &reg13);
+ mips_cpu_get_register(cpu, 16, &reg16);
+ mips_cpu_get_register(cpu, 31, &reg31);
+
+ if(reg10 == 9+8 && reg13 == 13 && reg16 == 14+15) {
+ passed = 1;
+ }
+
+ if((opcode == 3 || opcode == 9) && reg31 != 8) {
+ passed = 0;
+ }
+
+ return passed;
+}
+
+int test_load(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t word) {
+ int passed = 0;
+ uint16_t half_word;
+ uint8_t byte;
+ uint32_t res;
+
+ half_word = (uint16_t)word;
+ byte = (uint8_t)word;
+
+ mips_cpu_reset(cpu);
+
+ uint32_t inst = change_endianness(gen_instruction(opcode, 8, 9, 4));
+
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+
+ if(opcode == LB || opcode == LBU) {
+ mips_mem_write(ram, 0x30, 1, &byte);
+ } else if(opcode == LH || opcode == LHU) {
+ uint16_t tmp = (half_word<<8) | (half_word>>8);
+ mips_mem_write(ram, 0x30, 2, (uint8_t*)&tmp);
+ } else {
+ uint32_t tmp = change_endianness(word);
+ mips_mem_write(ram, 0x30, 4, (uint8_t*)&tmp);
+ }
+
+ mips_cpu_set_register(cpu, 8, 0x2c);
+ if(opcode == LWR) {
+ mips_cpu_set_register(cpu, 8, 0x2f);
+ }
+ mips_cpu_set_register(cpu, 9, 0xbabacdcd);
+
+ mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 9, &res);
+
+ if((res == (uint32_t)(int8_t)byte && opcode == LB) || (res == (uint32_t)byte && opcode == LBU) || (res == (uint32_t)(int16_t)half_word && opcode == LH) || (res == (uint32_t)half_word && opcode == LHU) || (res == word && opcode == LW) || (res == 4<<16 && opcode == LUI) || (res == ((word&0xffff)|(0xbaba0000)) && (opcode == LWR)) || (res == ((word&0xffff0000)|(0xcdcd)))) {
+ passed = 1;
+ }
+
+ return passed;
+}
+
+int test_mult_div(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t num1, uint32_t num2) {
+ int passed = 0;
+ uint64_t result;
+ uint32_t hi, lo;
+
+ mips_cpu_reset(cpu);
+
+ uint32_t inst = change_endianness(gen_instruction(8, 9, 0, 0, opcode));
+ mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(0, 0, 10, 0, MFHI));
+ mips_mem_write(ram, 4, 4, (uint8_t*)&inst);
+ inst = change_endianness(gen_instruction(0, 0, 11, 0, MFLO));
+ mips_mem_write(ram, 8, 4, (uint8_t*)&inst);
+
+ mips_cpu_set_register(cpu, 8, num1);
+ mips_cpu_set_register(cpu, 9, num2);
+ mips_cpu_set_register(cpu, 10, 0xabcde);
+ mips_cpu_set_register(cpu, 11, 0xf193b);
+
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+ mips_cpu_step(cpu);
+
+ mips_cpu_get_register(cpu, 10, &hi);
+ mips_cpu_get_register(cpu, 11, &lo);
+
+ result = (((uint64_t)hi)<<32) | ((uint64_t)lo);
+
+ if((opcode == MULT && result == (uint64_t)((int64_t)(int32_t)num1*(int64_t)(int32_t)num2)) || (opcode == MULTU && result == (uint64_t)((uint32_t)num1)*(uint32_t)num2) || (opcode == DIV && lo == (uint32_t)((int32_t)num1/(int32_t)num2) && hi == (uint32_t)((int32_t)num1%(int32_t)num2)) || (opcode == DIVU && lo == num1/num2 && hi == num1%num2)) {
+ passed = 1;
+ }
+
+ return passed;
+}
diff --git a/src/ymh15/mips_cpu.cpp b/src/ymh15/mips_cpu.cpp
index 34107de..37bf08a 100644
--- a/src/ymh15/mips_cpu.cpp
+++ b/src/ymh15/mips_cpu.cpp
@@ -42,10 +42,6 @@ mips_cpu_h mips_cpu_create(mips_mem_h mem) {
}
mips_error mips_cpu_reset(mips_cpu_h state) {
- if(!state) {
- return mips_ErrorInvalidArgument;
- }
-
// resets both program counters
state->pc = 0;
state->next_pc = state->pc + 4;
@@ -63,10 +59,6 @@ mips_error mips_cpu_reset(mips_cpu_h state) {
mips_error mips_cpu_get_register(mips_cpu_h state, unsigned index,
uint32_t *value) {
- if(!state || !value || index > 31 || index == 0) {
- return mips_ErrorInvalidArgument;
- }
-
// get the state of a current register by using the provided pointer;
*value = state->regs[index];
@@ -75,10 +67,9 @@ mips_error mips_cpu_get_register(mips_cpu_h state, unsigned index,
mips_error mips_cpu_set_register(mips_cpu_h state, unsigned index,
uint32_t value) {
- if(!state || index > 31 || index == 0) {
+ if(index > 31 || index < 1) {
return mips_ErrorInvalidArgument;
}
-
// set reg state
state->regs[index] = value;
@@ -87,10 +78,6 @@ mips_error mips_cpu_set_register(mips_cpu_h state, unsigned index,
mips_error mips_cpu_set_pc(mips_cpu_h state, uint32_t pc) {
- if(!state) {
- return mips_ErrorInvalidArgument;
- }
-
// set the pc and next_pc to the right values
state->pc = pc;
state->next_pc = state->pc+4;
@@ -99,10 +86,6 @@ mips_error mips_cpu_set_pc(mips_cpu_h state, uint32_t pc) {
}
mips_error mips_cpu_get_pc(mips_cpu_h state, uint32_t *pc) {
- if(!state || !pc) {
- return mips_ErrorInvalidArgument;
- }
-
// get the value of the current pc
*pc = state->pc;
@@ -112,10 +95,6 @@ mips_error mips_cpu_get_pc(mips_cpu_h state, uint32_t *pc) {
// This function executes the code that is found in memory at the address
// of the program counter
mips_error mips_cpu_step(mips_cpu_h state) {
- if(!state) {
- return mips_ErrorInvalidArgument;
- }
-
// gets the instruction from memory
uint32_t inst;
mips_mem_read(state->mem, state->pc, 4, (uint8_t*)&inst);
@@ -206,7 +185,7 @@ mips_error exec_instruction(mips_cpu_h state, uint32_t inst) {
// execute R instruction to perform operation
return exec_R(state, var);
- } else if(((inst >> 26)&0x3f) < 4 && ((inst >> 26)&0x3f) != 1) { // as opcode is < 4
+ } else if(((inst >> 26)&0x3f) == J || ((inst >> 26)&0x3f) == JAL) { // as opcode is < 4
var[OPCODE] = inst >> 26; // it has to be J type
var[MEM] = inst&0x3ffffff;
return exec_J(state, var);
@@ -214,10 +193,7 @@ mips_error exec_instruction(mips_cpu_h state, uint32_t inst) {
var[OPCODE] = inst >> 26;
var[REG_S] = (inst >> 21)&0x1f;
var[REG_D] = (inst >> 16)&0x1f;
- var[IMM] = inst&0xffff;
- if((var[IMM]&0x8000) == 0x8000) {
- var[IMM] = (var[IMM]|0xffff0000);
- }
+ var[IMM] = (uint32_t)(int16_t)(inst&0xffff);
return exec_I(state, var);
}
@@ -226,7 +202,7 @@ mips_error exec_instruction(mips_cpu_h state, uint32_t inst) {
mips_error exec_R(mips_cpu_h state, uint32_t var[8]) {
// if the function code is between 0x1f and 0x24 then it is addition
// or subtraction
- if((var[FUNC]&0xf0) == 0x20 && (var[FUNC]&0xf) < 4) {
+ if((var[FUNC]&0xf0) == ADD && (var[FUNC]&0xf) < 4) {
// calls add with -1 if it is a subtractin and 1 if it is addition
return add_sub(state, var, ((int32_t)-(var[FUNC]&0xf)/2)*2+1, 0);
@@ -235,22 +211,31 @@ mips_error exec_R(mips_cpu_h state, uint32_t var[8]) {
// is a bitwise operation
return bitwise(state, var, 0);
- } else if(var[FUNC] == 8) {
+ } else if(var[FUNC] == JR) {
// jr
return jump(state, var, 0);
- } else if(var[FUNC] == 9) {
+ } else if(var[FUNC] == JALR) {
// jalr
return jump(state, var, 1);
- } else if(var[FUNC] >= 0x10 && var[FUNC] <= 0x13) {
+ } else if(var[FUNC] >= MFHI && var[FUNC] <= MTLO) {
// mfhi mthi mflo mtlo
return move(state, var);
- } else if(var[FUNC] >= 0x18 && var[FUNC] <= 0x1b) {
+ } else if(var[FUNC] >= MULT && var[FUNC] <= DIVU) {
// mult multu div divu
return mult_div(state, var);
+ } else if(var[FUNC] == SLT || var[FUNC] == SLTU) {
+ return set(state, var, 0);
+
+ } else if(var[FUNC] == SLL || var[FUNC] == SLLV || var[FUNC] == SRA || var[FUNC] == SRAV || var[FUNC] == SRL || var[FUNC] == SRLV) {
+ return shift(state, var);
+
+ } else if(var[OPCODE] == 0 && var[REG_S] == 0 && var[REG_D] == 0 && var[REG_T] == 0 && var[SHIFT] == 0 && var[FUNC] == NOOP) {
+ return mips_Success;
+
} else {
// otherwise return that it was an invalid instruction
return mips_ExceptionInvalidInstruction;
@@ -259,10 +244,9 @@ mips_error exec_R(mips_cpu_h state, uint32_t var[8]) {
mips_error exec_J(mips_cpu_h state, uint32_t var[8]) {
switch(var[OPCODE]) {
- case 0:
- case 2: // j
+ case J: // j
return jump(state, var, 0);
- case 3: // jal
+ case JAL: // jal
return jump(state, var, 1);
default:
return mips_ExceptionInvalidInstruction;
@@ -271,47 +255,51 @@ mips_error exec_J(mips_cpu_h state, uint32_t var[8]) {
mips_error exec_I(mips_cpu_h state, uint32_t var[8]) {
switch(var[OPCODE]) {
- case 0x1: // bgez, bgezal, bltz, bltzal
+ case BGEZ: // bgez, bgezal, bltz, bltzal
return branch(state, var);
- case 0x4: // beq
+ case BEQ: // beq
return branch(state, var);
- case 0x5: // bne
+ case BNE: // bne
return branch(state, var);
- case 0x6: // blez
+ case BLEZ: // blez
return branch(state, var);
- case 0x7: // bgtz
+ case BGTZ: // bgtz
return branch(state, var);
- case 0x8: // addi
+ case ADDI: // addi
return add_sub(state, var, 1, 1);
- case 0x9: // addiu
+ case ADDIU: // addiu
return add_sub(state, var, 1, 2);
- case 0xc: // andi
+ case SLTI:
+ return set(state, var, 1);
+ case SLTIU:
+ return set(state, var, 1);
+ case ANDI:
return bitwise(state, var, 1);
- case 0xd: // ori
+ case ORI: // ori
return bitwise(state, var, 1);
- case 0xe: // xori
+ case XORI: // xori
return bitwise(state, var, 1);
- case 0xf: // lui
+ case LUI: // lui
return load(state, var);
- case 0x20: // lb
+ case LB: // lb
return load(state, var);
- case 0x21: // lh
+ case LH: // lh
return load(state, var);
- case 0x22: // lwl
+ case LWL: // lwl
return load(state, var);
- case 0x23: // lw
+ case LW: // lw
return load(state, var);
- case 0x24: // lbu
+ case LBU: // lbu
return load(state, var);
- case 0x25: // lhu
+ case LHU: // lhu
return load(state, var);
- case 0x26: // lwr
+ case LWR: // lwr
return load(state, var);
- case 0x28: // sb
+ case SB: // sb
return store(state, var);
- case 0x29: // sh
+ case SH: // sh
return store(state, var);
- case 0x2b: // sw
+ case SW: // sw
return store(state, var);
default:
return mips_ExceptionInvalidInstruction;
@@ -350,16 +338,22 @@ mips_error bitwise(mips_cpu_h state, uint32_t var[8], unsigned imm) {
uint32_t reg_s, reg_t, reg_d;
mips_cpu_get_register(state, var[REG_S], &reg_s);
- if(imm == 0) {
+ if(!imm) {
mips_cpu_get_register(state, var[REG_T], &reg_t);
} else {
- reg_t = var[IMM];
+ reg_t = var[IMM]&0x0000ffff;
}
// performs correct bitwise operation and sets register;
- if((var[FUNC]&0xf) == 4 || var[OPCODE] == 0xc) reg_d = reg_s & reg_t;
- else if((var[FUNC]&0xf) == 5 || var[OPCODE] == 0xd) reg_d = reg_s | reg_t;
- else reg_d = reg_s ^ reg_t;
+ if(var[FUNC] == AND || var[OPCODE] == ANDI) {
+ reg_d = reg_s & reg_t;
+ }
+ else if(var[FUNC] == OR || var[OPCODE] == ORI) {
+ reg_d = reg_s | reg_t;
+ }
+ else {
+ reg_d = reg_s ^ reg_t;
+ }
// set register to the answer
mips_cpu_set_register(state, var[REG_D], reg_d);
@@ -372,12 +366,12 @@ mips_error branch(mips_cpu_h state, uint32_t var[8]) {
state->regs[31] = state->pc+8;
}
- if((state->regs[var[REG_S]] == state->regs[var[REG_D]] && var[OPCODE] == 4) || // bez
- (state->regs[var[REG_S]] != state->regs[var[REG_D]] && var[OPCODE] == 5) || // bne
- (((int32_t)state->regs[var[REG_S]] >= 0) && (var[OPCODE] == 1) && (var[REG_D]&1) == 1) || // bgez / bgezal
- ((int32_t)state->regs[var[REG_S]] < 0 && var[OPCODE] == 1 && (var[REG_D]&1) == 0) || // bltz / bltzal
- ((int32_t)state->regs[var[REG_S]] > 0 && var[OPCODE] == 7 && (var[REG_D]&1) == 0) || // bgtz
- ((int32_t)state->regs[var[REG_S]] <= 0 && var[OPCODE] == 6 && (var[REG_D]&1) == 0)) { // blez
+ if((state->regs[var[REG_S]] == state->regs[var[REG_D]] && var[OPCODE] == BEQ) ||
+ (state->regs[var[REG_S]] != state->regs[var[REG_D]] && var[OPCODE] == BNE) ||
+ (((int32_t)state->regs[var[REG_S]] >= 0) && (var[OPCODE] == BGEZ) && (var[REG_D]&1) == 1) ||
+ ((int32_t)state->regs[var[REG_S]] < 0 && var[OPCODE] == BLTZ && (var[REG_D]&1) == 0) ||
+ ((int32_t)state->regs[var[REG_S]] > 0 && var[OPCODE] == BGTZ && (var[REG_D]&1) == 0) ||
+ ((int32_t)state->regs[var[REG_S]] <= 0 && var[OPCODE] == BLEZ && (var[REG_D]&1) == 0)) {
state->next_pc += (var[IMM]<<2);
state->delay_slot += 1;
@@ -389,78 +383,90 @@ mips_error branch(mips_cpu_h state, uint32_t var[8]) {
mips_error jump(mips_cpu_h state, uint32_t var[8], uint8_t link) {
uint8_t reg_d;
uint32_t jump_loc;
- if(var[FUNC] == 9 || var[FUNC] == 8) {
+ if(var[FUNC] == JALR || var[FUNC] == JR) {
jump_loc = state->regs[var[REG_S]];
reg_d = var[REG_D];
+ state->next_pc = jump_loc;
} else {
jump_loc = var[MEM]<<2;
reg_d = 31;
+ state->next_pc = (state->next_pc&0xf0000000) | (jump_loc&0xfffffff);
}
if(link) {
state->regs[reg_d] = state->pc+8;
}
- state->next_pc = jump_loc;
state->delay_slot += 1;
return mips_Success;
}
mips_error load(mips_cpu_h state, uint32_t var[8]) {
- uint32_t addr;
- uint8_t mem_byte;
- uint16_t mem_halfword;
- uint32_t mem_word;
+ uint32_t addr = 0;
+ uint8_t mem_byte = 0;
+ uint16_t mem_halfword = 0;
+ uint32_t mem_word = 0;
+ unsigned i = 0;
addr = state->regs[var[REG_S]] + var[IMM];
- if(var[OPCODE] == 0x24 || var[OPCODE] == 0x20) { // lb lbu
+ if(var[OPCODE] == LB || var[OPCODE] == LBU) {
mips_mem_read(state->mem, addr, 1, &mem_byte);
- } else if(var[OPCODE] == 0x21 || var[OPCODE] == 0x25) { // lh lhu
+ } else if(var[OPCODE] == LH || var[OPCODE] == LHU) {
if((addr&0b1) == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
mips_mem_read(state->mem, addr, 2, (uint8_t*)&mem_halfword);
mem_halfword = mem_halfword>>8 | mem_halfword<<8;
- } else if(var[OPCODE] == 0x23 || var[OPCODE] == 0x22) { // lw lwl
+ } else if(var[OPCODE] == LW) {
if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
mips_mem_read(state->mem, addr, 4, (uint8_t*)&mem_word);
mem_word = (mem_word<<24) | ((mem_word>>8)&0xff00) | ((mem_word<<8)&0xff0000) | (mem_word>>24);
- } else if(var[OPCODE] == 0x26) { // lwr
- if((addr&0b1) == 0 || (addr&0b10)>>1 == 0) {
- return mips_ExceptionInvalidAddress;
+ } else if(var[OPCODE] == LWL) {
+ i = 3;
+ while((addr&3) != 0) {
+ mips_mem_read(state->mem, addr, 1, &mem_byte);
+ mem_word = mem_word | ((uint32_t)mem_byte<<(i*8));
+ ++addr;
+ --i;
+ }
+ } else if(var[OPCODE] == LWR) {
+ i = 0;
+ while((addr&3) != 3) {
+ mips_mem_read(state->mem, addr, 1, &mem_byte);
+ mem_word = mem_word | ((uint32_t)mem_byte<<(i*8));
+ --addr;
+ ++i;
}
- mips_mem_read(state->mem, addr-3, 4, (uint8_t*)&mem_word);
- mem_word = (mem_word<<24) | ((mem_word>>8)&0xff00) | ((mem_word<<8)&0xff0000) | (mem_word>>24);
}
-
+
switch(var[OPCODE]) {
- case 0xf:
+ case LUI:
state->regs[var[REG_D]] = var[IMM]<<16;
return mips_Success;
- case 0x20:
+ case LB:
state->regs[var[REG_D]] = (uint32_t)(int8_t)mem_byte;
return mips_Success;
- case 0x21:
+ case LH:
state->regs[var[REG_D]] = (uint32_t)(int16_t)mem_halfword;
return mips_Success;
- case 0x22:
- state->regs[var[REG_D]] = (mem_word&0xffff0000)|(state->regs[var[REG_D]]&0xffff);
+ case LWL:
+ state->regs[var[REG_D]] = (state->regs[var[REG_D]]&(0xffffffff>>((3-i)*8))) | (mem_word&(0xffffffff<<((i+1)*8)));
return mips_Success;
- case 0x23:
+ case LW:
state->regs[var[REG_D]] = mem_word;
return mips_Success;
- case 0x24:
+ case LBU:
state->regs[var[REG_D]] = (uint32_t)mem_byte;
return mips_Success;
- case 0x25:
+ case LHU:
state->regs[var[REG_D]] = (uint32_t)mem_halfword;
return mips_Success;
- case 0x26:
- state->regs[var[REG_D]] = (state->regs[var[REG_D]]&0xffff0000)|(mem_word&0xffff);
+ case LWR:
+ state->regs[var[REG_D]] = (state->regs[var[REG_D]]&(0xffffffff<<(i*8))) | (mem_word&(0xffffffff>>((4-i)*8)));
return mips_Success;
default:
return mips_ExceptionInvalidInstruction;
@@ -478,17 +484,17 @@ mips_error store(mips_cpu_h state, uint32_t var[8]) {
half_word = (uint16_t)state->regs[var[REG_D]];
byte = (uint8_t)state->regs[var[REG_D]];
- if(var[OPCODE] == 0x28) {
+ if(var[OPCODE] == SB) {
mips_mem_write(state->mem, addr, 1, &byte);
- } else if(var[OPCODE] == 0x29) {
+ } else if(var[OPCODE] == SH) {
if((addr&0b1) == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
uint16_t tmp = half_word << 8 | half_word >> 8;
mips_mem_write(state->mem, addr, 2, (uint8_t*)&tmp);
- } else if(var[OPCODE] == 0x2b) {
+ } else if(var[OPCODE] == SW) {
if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
uint32_t tmp = word<<24 | ((word>>8)&0xff00) | ((word<<8)&0xff0000) | word>>24;
mips_mem_write(state->mem, addr, 4, (uint8_t*)&tmp);
@@ -500,14 +506,14 @@ mips_error store(mips_cpu_h state, uint32_t var[8]) {
mips_error move(mips_cpu_h state, uint32_t var[8]) {
switch(var[FUNC]) {
- case 0x10:
+ case MFHI:
return mips_cpu_set_register(state, var[REG_D], state->hi);
- case 0x11:
- return mips_cpu_get_register(state, var[REG_D], &state->hi);
- case 0x12:
+ case MTHI:
+ return mips_cpu_get_register(state, var[REG_S], &state->hi);
+ case MFLO:
return mips_cpu_set_register(state, var[REG_D], state->lo);
- case 0x13:
- return mips_cpu_get_register(state, var[REG_D], &state->lo);
+ case MTLO:
+ return mips_cpu_get_register(state, var[REG_S], &state->lo);
default:
return mips_ExceptionInvalidInstruction;
}
@@ -517,19 +523,19 @@ mips_error move(mips_cpu_h state, uint32_t var[8]) {
mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
uint64_t unsigned_result, signed_result;
switch(var[FUNC]) {
- case 0x18: // mult
+ case MULT:
signed_result = ((int64_t)(int32_t)state->regs[var[REG_S]])*((int64_t)(int32_t)state->regs[var[REG_T]]);
state->lo = (uint32_t)signed_result;
state->hi = (uint32_t)(signed_result>>32);
return mips_Success;
- case 0x19: // multu
+ case MULTU:
unsigned_result = ((uint64_t)state->regs[var[REG_S]])*((uint64_t)state->regs[var[REG_T]]);
state->lo = (uint32_t)unsigned_result;
state->hi = (uint32_t)(unsigned_result>>32);
return mips_Success;
- case 0x1a: // div
+ case DIV:
if(var[REG_T] == 0) {
state->lo = 0;
state->hi = 0;
@@ -540,7 +546,7 @@ mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
state->hi = ((int32_t)state->regs[var[REG_S]])%((int32_t)state->regs[var[REG_T]]);
return mips_Success;
- case 0x1b: // divu
+ case DIVU:
if(var[REG_T] == 0) {
state->lo = 0;
state->hi = 0;
@@ -557,10 +563,50 @@ mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
}
mips_error shift(mips_cpu_h state, uint32_t var[8]) {
- if(var[FUNC] == 0 && var[OPCODE] == 0) {
+ if(var[FUNC] == SLL && var[OPCODE] == 0) {
state->regs[var[REG_D]] = state->regs[var[REG_T]] << var[SHIFT];
- } else if(var[FUNC] == 4) {
+ } else if(var[FUNC] == SLLV) {
state->regs[var[REG_D]] = state->regs[var[REG_T]] << state->regs[var[REG_S]];
- } else if(var[FUNC] == 2/*TODO*/);
+ } else if(var[FUNC] == SRA) {
+ state->regs[var[REG_D]] = (int32_t)state->regs[var[REG_T]] >> var[SHIFT];
+ } else if(var[FUNC] == SRAV) {
+ state->regs[var[REG_D]] = ((int32_t)state->regs[var[REG_T]]) >> state->regs[var[REG_S]];
+ } else if(var[FUNC] == SRL) {
+ state->regs[var[REG_D]] = state->regs[var[REG_T]] >> var[SHIFT];
+ } else if(var[FUNC] == SRLV) {
+ state->regs[var[REG_D]] = state->regs[var[REG_T]] >> state->regs[var[REG_S]];
+ }
+ return mips_Success;
+}
+
+mips_error set(mips_cpu_h state, uint32_t var[8], uint32_t imm) {
+ uint32_t reg_s, reg_t, reg_d;
+
+ mips_cpu_get_register(state, var[REG_S], &reg_s);
+
+ if(!imm) {
+ mips_cpu_get_register(state, var[REG_T], &reg_t);
+ } else {
+ reg_t = var[IMM];
+ }
+
+ if(var[FUNC] == SLT || var[OPCODE] == SLTI) {
+ if(((int32_t)reg_s) < ((int32_t)reg_t)) {
+ reg_d = 1;
+ } else {
+ reg_d = 0;
+ }
+ } else if(var[FUNC] == SLTU || var[OPCODE] == SLTIU) {
+ if(reg_s < reg_t) {
+ reg_d = 1;
+ } else {
+ reg_d = 0;
+ }
+ } else {
+ return mips_ExceptionInvalidInstruction;
+ }
+
+ mips_cpu_set_register(state, var[REG_D], reg_d);
+
return mips_Success;
}
diff --git a/src/ymh15/mips_cpu.o b/src/ymh15/mips_cpu.o
index 4092c0a..d59e406 100644
--- a/src/ymh15/mips_cpu.o
+++ b/src/ymh15/mips_cpu.o
Binary files differ
diff --git a/src/ymh15/mips_cpu_ymh15.hpp b/src/ymh15/mips_cpu_ymh15.hpp
index 085c59c..05f21f9 100644
--- a/src/ymh15/mips_cpu_ymh15.hpp
+++ b/src/ymh15/mips_cpu_ymh15.hpp
@@ -16,6 +16,7 @@
#define MEM 7
// Functions
+#define NOOP 0x0
#define SLL 0x0
#define SRL 0x2
#define SRA 0x3
@@ -89,5 +90,6 @@ mips_error store(mips_cpu_h state, uint32_t var[8]);
mips_error move(mips_cpu_h state, uint32_t var[8]);
mips_error mult_div(mips_cpu_h state, uint32_t var[8]);
mips_error shift(mips_cpu_h state, uint32_t var[8]);
+mips_error set(mips_cpu_h state, uint32_t var[8], uint32_t imm);
#endif // MIPS_CPU_YMH15_H
diff --git a/src/ymh15/mips_instruction_test.h b/src/ymh15/mips_instruction_test.h
new file mode 100644
index 0000000..f276124
--- /dev/null
+++ b/src/ymh15/mips_instruction_test.h
@@ -0,0 +1,74 @@
+#include "mips.h"
+
+// Used to define the generic instruction implementation
+struct instruction_impl{
+ char type;
+ uint8_t opCode;
+ // Only used for an 'actual' function rather than instruction set member
+ uint32_t data;
+
+ // Constructor where there is actual raw data
+ instruction_impl(uint32_t dataIn, char typeIn):
+ type(typeIn),
+ opCode(uint8_t((dataIn & 0xFC000000) >> 26)),
+ data(dataIn){}
+};
+
+// Used for R type instructions, inherits the generic function type
+struct instruction_impl_r : public instruction_impl{
+ uint8_t source1;
+ uint8_t source2;
+ uint8_t dest;
+ uint8_t shift;
+ uint8_t function;
+
+ // Constructor specifying each part of the instruction
+ instruction_impl_r(
+ uint8_t source1In,
+ uint8_t source2In,
+ uint8_t destIn,
+ uint8_t shiftIn,
+ uint8_t functionIn):
+ instruction_impl(
+ uint32_t(
+ 0x00000000 | ((uint32_t(source1In) & 0x0000001F) << 21) |
+ ((uint32_t(source2In) & 0x0000001F) << 16) |
+ ((uint32_t(destIn) & 0x0000001F) << 11) |
+ ((uint32_t(shiftIn) & 0x0000001F) << 6) |
+ (uint32_t(functionIn) & 0x0000003F)),
+ 'r'),
+ source1(source1In),
+ source2(source2In),
+ dest(destIn),
+ shift(shiftIn),
+ function(functionIn){}
+};
+
+// Used for J type instructions, inherits the generic function type
+struct instruction_impl_j: public instruction_impl{
+ uint32_t address;
+
+ instruction_impl_j(uint8_t opCodeIn, uint32_t addressIn):
+ instruction_impl(uint32_t(((uint32_t(opCodeIn) & 0x0000003F) << 26) | (addressIn & 0x03FFFFFF)), 'j'),
+ address(addressIn){}
+};
+
+// Used for I type instructions, inherits the generic function type
+struct instruction_impl_i: public instruction_impl{
+ uint8_t source;
+ uint8_t dest;
+ uint16_t immediate;
+
+ // Constructor specifying each part of the instruction
+ instruction_impl_i(uint8_t opCodeIn, uint8_t sourceIn, uint8_t destIn, uint16_t immediateIn):
+ instruction_impl(
+ uint32_t(
+ 0x00000000 | ((uint32_t(opCodeIn) & 0x0000003F) << 26) |
+ ((uint32_t(sourceIn) & 0x0000001F) << 21) |
+ ((uint32_t(destIn) & 0x0000001F) << 16) |
+ (uint32_t(immediateIn))),
+ 'i'),
+ source(sourceIn),
+ dest(destIn),
+ immediate(immediateIn){}
+};
diff --git a/src/ymh15/test_mips b/src/ymh15/test_mips
index 3c01c18..0368d58 100755
--- a/src/ymh15/test_mips
+++ b/src/ymh15/test_mips
Binary files differ
diff --git a/src/ymh15/test_mips.cpp b/src/ymh15/test_mips.cpp
index 75afaa8..67bed8f 100644
--- a/src/ymh15/test_mips.cpp
+++ b/src/ymh15/test_mips.cpp
@@ -1,482 +1,1203 @@
-#include "../../include/mips.h"
-#include "test_mips_ymh15.hpp"
-
-#include <iostream>
-
-using namespace std;
-
-int main(int argc, char** argv) {
- mips_mem_h ram = mips_mem_create_ram(4096);
- mips_cpu_h cpu = mips_cpu_create(ram);
-
- srand(time(NULL));
-
- if(argc == 2) {
- mips_cpu_set_debug_level(cpu, argv[1][0]-'0', stdout);
- } else {
- mips_cpu_set_debug_level(cpu, 0, NULL);
- }
-
- mips_test_begin_suite();
-
- int testId = mips_test_begin_test("ADD");
- mips_test_end_test(testId, test_add(ram, cpu, ADD, 0x3fffffff, 0, 10), "Testing the adder without overflow");
-
- testId = mips_test_begin_test("ADD");
- mips_test_end_test(testId, !test_add(ram, cpu, ADD, 0x7fffffff, 1, 1), "Testing the adder with overflow");
-
- testId = mips_test_begin_test("ADDU");
- mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x3fffffff, 0, 10), "testing without overflow");
-
- testId = mips_test_begin_test("ADDU");
- mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x7fffffff, 1, 1), "Testing the adder with overflow");
-
- testId = mips_test_begin_test("SUB");
- mips_test_end_test(testId, test_add(ram, cpu, SUB, 0x3fffffff, 0, 10), "Testing the adder without overflow");
-
- testId = mips_test_begin_test("SUB");
- mips_test_end_test(testId, !test_add(ram, cpu, SUB, 0x7fffffff, 1, 1), "Testing the adder with overflow");
-
- testId = mips_test_begin_test("SUBU");
- mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x3fffffff, 0, 10), "Testing the adder without overflow");
-
- testId = mips_test_begin_test("SUBU");
- mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x7fffffff, 1, 1), "Testing the adder with overflow");
-
- testId = mips_test_begin_test("AND");
- mips_test_end_test(testId, test_bitwise(ram, cpu, AND), "Testing bitwise and");
-
- testId = mips_test_begin_test("OR");
- mips_test_end_test(testId, test_bitwise(ram, cpu, OR), "Testing bitwise or");
-
- testId = mips_test_begin_test("XOR");
- mips_test_end_test(testId, test_bitwise(ram, cpu, XOR), "Testing bitwise xor");
-
- testId = mips_test_begin_test("ADDI");
- mips_test_end_test(testId, test_I(ram, cpu, ADDI, 20, 10), "Testing addi");
-
- testId = mips_test_begin_test("ADDIU");
- mips_test_end_test(testId, test_I(ram, cpu, ADDIU, 20, 10), "Testing addiu");
-
- testId = mips_test_begin_test("ANDI");
- mips_test_end_test(testId, test_I(ram, cpu, ANDI, 20, 10), "Testing addi");
-
- testId = mips_test_begin_test("ORI");
- mips_test_end_test(testId, test_I(ram, cpu, ORI, 20, 10), "Testing addi");
-
- testId = mips_test_begin_test("XORI");
- mips_test_end_test(testId, test_I(ram, cpu, XORI, 20, 10), "Testing addi");
-
- testId = mips_test_begin_test("BEQ");
- mips_test_end_test(testId, test_branch(ram, cpu, 4, 4, 0, 9, 4), "Testing BEQ");
-
- testId = mips_test_begin_test("BNE");
- mips_test_end_test(testId, test_branch(ram, cpu, 5, 4, 0, 9, 10), "Testing BNE");
-
- testId = mips_test_begin_test("BGEZ");
- mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 0, 1, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("BLEZ");
- mips_test_end_test(testId, test_branch(ram, cpu, 6, -1, 0, 0, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("BGTZ");
- mips_test_end_test(testId, test_branch(ram, cpu, 7, 4, 0, 0, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("BGEZAL");
- mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 1, 17, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("BLTZAL");
- mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 1, 16, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("BLTZ");
- mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 0, 16, 20), "Testing BGEZ");
-
- testId = mips_test_begin_test("J");
- mips_test_end_test(testId, test_jump(ram, cpu, J), "Testing J");
-
- testId = mips_test_begin_test("JAL");
- mips_test_end_test(testId, test_jump(ram, cpu, JAL), "Testing JAL");
-
- testId = mips_test_begin_test("JALR");
- mips_test_end_test(testId, test_jump(ram, cpu, JALR), "Testing JALR");
-
- testId = mips_test_begin_test("JR");
- mips_test_end_test(testId, test_jump(ram, cpu, JR), "Testing JR");
-
- testId = mips_test_begin_test("LB");
- mips_test_end_test(testId, test_load(ram, cpu, LB, 0xf7), "Testing LB");
-
- testId = mips_test_begin_test("LBU");
- mips_test_end_test(testId, test_load(ram, cpu, LBU, 0xf7), "Testing LBU");
-
- testId = mips_test_begin_test("LH");
- mips_test_end_test(testId, test_load(ram, cpu, LH, 0xff7f), "Testing LH");
-
- testId = mips_test_begin_test("LHU");
- mips_test_end_test(testId, test_load(ram, cpu, LHU, 0xff7f), "Testing LHU");
-
- testId = mips_test_begin_test("LW");
- mips_test_end_test(testId, test_load(ram, cpu, LW, 0xffffff7f), "Testing LW");
-
- testId = mips_test_begin_test("LUI");
- mips_test_end_test(testId, test_load(ram, cpu, LUI, 0xff7f), "Testing LUI");
-
- testId = mips_test_begin_test("LWL");
- mips_test_end_test(testId, test_load(ram, cpu, LWL, 0xff6fff7f), "Testing LWL");
-
- testId = mips_test_begin_test("LWR");
- mips_test_end_test(testId, test_load(ram, cpu, LWR, 0xff6fff7f), "Testing LWR");
-
- testId = mips_test_begin_test("MULT");
- mips_test_end_test(testId, test_mult_div(ram, cpu, MULT, 5, -4), "Testing LWR");
-
- testId = mips_test_begin_test("MULTU");
- mips_test_end_test(testId, test_mult_div(ram, cpu, MULTU, 5, -4), "Testing LWR");
-
- testId = mips_test_begin_test("DIV");
- mips_test_end_test(testId, test_mult_div(ram, cpu, DIV, 5, -4), "Testing LWR");
-
- testId = mips_test_begin_test("DIVU");
- mips_test_end_test(testId, test_mult_div(ram, cpu, DIVU, 5, -4), "Testing LWR");
-
- mips_test_end_suite();
- return 0;
-}
-
-// R Type
-uint32_t gen_instruction(uint32_t src1, uint32_t src2, uint32_t dest,
- uint32_t shift, uint32_t function) {
- uint32_t inst = 0;
- inst = inst | src1 << 21 | src2 << 16 | dest << 11 | shift << 6 |
- function;
- return inst;
-}
-
-// I Type
-uint32_t gen_instruction(uint32_t opcode, uint32_t src, uint32_t dest,
- uint32_t Astart) {
- uint32_t inst = 0;
- inst = inst | opcode << 26 | src << 21 | dest << 16 | Astart;
- return inst;
-}
-
-// J Type
-uint32_t gen_instruction(uint32_t opcode, uint32_t memory) {
- uint32_t inst = 0;
- inst = inst | opcode << 26 | memory;
- return inst;
-}
-
-uint32_t change_endianness(uint32_t inst) {
- inst = (inst << 24 | ((inst << 8)&0xff0000) |
- ((inst >> 8)&0xff00) |inst >> 24);
- return inst;
-}
-
-int test_add(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, uint32_t max, uint8_t value, unsigned i_t) {
-
- uint32_t inst, ans, a, b;
-
- for(unsigned i = 0; i < i_t; ++i) {
- mips_error mips_err;
- mips_cpu_reset(cpu);
- inst = change_endianness(gen_instruction(9, 10, 8, 0, type));
- if(value) {
- a = max;
- if(type > 0x21) {
- b = -max;
- } else {
- b = max;
- }
- } else {
- a = rand() % max;
- b = rand() % max;
- }
-
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
-
- mips_cpu_set_register(cpu, 9, a);
- mips_cpu_set_register(cpu, 10, b);
-
- mips_err = mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 8, &ans);
-
- if(type < 0x22) {
- //printf("%#10x + %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
- if(mips_err == mips_ExceptionArithmeticOverflow || a+b!=ans) {
- return 0;
- }
- } else {
- //printf("%#10x - %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
- if(mips_err == mips_ExceptionArithmeticOverflow || a-b!=ans) {
- return 0;
- }
+#include "test_mips.h"
+
+int main(){
+
+ mips_test_begin_suite();
+
+ // Create 512MB of RAM - PHWOAAAR (used to test J and JAL instructions)
+ mips_mem_h testMem = mips_mem_create_ram(512000000);
+ mips_cpu_h testCPU = mips_cpu_create(testMem);
+
+ // Check get and set for R1 to R31
+ for (unsigned i = 1; i < 32; i++){
+ test cpu_getSetReg("<internal>", "Verify that the value from a register is "
+ "the same as the value the register was set to", 0);
+ writeReg(testCPU, i, 0xABCDEF12);
+ cpu_getSetReg.checkReg(i, 0xABCDEF12);
+ cpu_getSetReg.perform_test(testCPU, testMem);
+ }
+
+ test cpu_getSetPc("<internal>", "Verify that the program counter is the same "
+ "as it was set to", 0);
+ writeReg(testCPU, 255, 404); // Joke: Program Counter not found?
+ cpu_getSetPc.checkReg(255, 404);
+ cpu_getSetPc.perform_test(testCPU, testMem);
+
+ test set_zero("<internal>", "Verify that R0 = 0 after an attempted set", 0);
+ writeReg(testCPU, 0, 0xABCDEF12);
+ set_zero.checkReg(0, 0);
+ set_zero.perform_test(testCPU, testMem);
+
+ test cpu_reset("<internal>", "Verify all regs and "
+ "pc set to 0 after reset", 0);
+ // Example of using for loops to define a test -- Why it isn't from a file
+ for (unsigned i = 0; i < 32; i++){
+ // Set the value of each register to its index
+ writeReg(testCPU, i, i);
+ cpu_reset.checkReg(i, 0);
+ }
+ mips_cpu_reset(testCPU);
+ cpu_reset.perform_test(testCPU, testMem);
+
+ // Check that each combination of registers can be uses as source1, source2
+ // and dest - Yes this does ~28,000 tests (Uses addu as simple instruction
+ // to implement)
+ // Could take this approach with every instruction but that would be OTT
+ // Changed according to formative feedback for speed purposes!
+ for (unsigned r1 = 1; r1 < 32; r1 += 7){
+ for (unsigned r2 = 1; r2 < 32; r2 += 5){
+ for (unsigned r3 = 1; r3 < 32; r3 += 3){
+ // Make sure Source1 and Source 2 are different
+ if(r2 != r3){
+ test basic_addu("<internal>",
+ "Verify the result of addu with no overflow for each combination of"
+ " source1, source2 and destination", 1);
+ writeMem(testMem, get_pc(testCPU),
+ instruction_impl_r(r2, r3, r1, 0, 33).data);
+ writeReg(testCPU, r2, 0x1374BAB3);
+ writeReg(testCPU, r3, 0x3A947118);
+ basic_addu.checkReg(r1, 0x4E092BCB);
+ basic_addu.perform_test(testCPU, testMem);
+ // Reset CPU after each test to keep instruction executing in same
+ // memory location
+ mips_cpu_reset(testCPU);
}
+ }
}
-
- return 1;
+ }
+
+ test reg_all("<internal>", "Verify that a register can be used as both "
+ "sources and a destination, all at once", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(8, 8, 8, 0, 33).data);
+ writeReg(testCPU, 8, 0x1AFAC3B0);
+ reg_all.checkReg(8, 0x35F58760);
+ reg_all.perform_test(testCPU, testMem);
+
+ test basic_sll("sll", "Verify that R8 = R9 << 5 and R9 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(0, 9, 8, 5, 0).data);
+ writeReg(testCPU, 9, 0xFBABABAB);
+ basic_sll.checkReg(8, 0x75757560);
+ basic_sll.checkReg(9, 0xFBABABAB);
+ basic_sll.perform_test(testCPU, testMem);
+
+ test basic_srl("srl", "Verify that R8 = R9 >> 5 and R9 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(0, 9, 8, 5, 2).data);
+ writeReg(testCPU, 9, 0xFBABABAB);
+ basic_srl.checkReg(8, 0x7DD5D5D);
+ basic_srl.checkReg(9, 0xFBABABAB);
+ basic_srl.perform_test(testCPU, testMem);
+
+ test basic_sra("sra", "Verify that R8 = R9 arith>> 5 and R9 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(0, 9, 8, 5, 3).data);
+ writeReg(testCPU, 9, 0x80309000);
+ basic_sra.checkReg(8, 0xFC018480);
+ basic_sra.checkReg(9, 0x80309000);
+ basic_sra.perform_test(testCPU, testMem);
+
+ test basic_sraPos("sra", "Verify that R8 = R9 arith>> 5 and R9 unchanged when"
+ " R9 is positive", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(0, 9, 8, 19, 3).data);
+ writeReg(testCPU, 9, 0x0ABA1A34);
+ basic_sraPos.checkReg(8, 0x157);
+ basic_sraPos.checkReg(9, 0x0ABA1A34);
+ basic_sraPos.perform_test(testCPU, testMem);
+
+ test basic_sllv("sllv", "Verify that R8 = R9 << R10 and R9 R10 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 9, 8, 0, 4).data);
+ writeReg(testCPU, 9, 0xFBABABAB);
+ writeReg(testCPU, 10, 5);
+ basic_sllv.checkReg(8, 0x75757560);
+ basic_sllv.checkReg(9, 0xFBABABAB);
+ basic_sllv.checkReg(10, 5);
+ basic_sllv.perform_test(testCPU, testMem);
+
+ test basic_srlv("srlv", "Verify that R8 = R9 >> R10 and R9 R10 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 9, 8, 0, 6).data);
+ writeReg(testCPU, 9, 0xFBABABAB);
+ writeReg(testCPU, 10, 5);
+ basic_srlv.checkReg(8, 0x7DD5D5D);
+ basic_srlv.checkReg(9, 0xFBABABAB);
+ basic_srlv.checkReg(10, 5);
+ basic_srlv.perform_test(testCPU, testMem);
+
+ test basic_srav("srav",
+ "Verify that R8 = R9 arith>> R10 and R9 R10 unchanged", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 9, 8, 0, 7).data);
+ writeReg(testCPU, 9, 0x80000000);
+ writeReg(testCPU, 10, 5);
+ basic_srav.checkReg(8, 0xFC000000);
+ basic_srav.checkReg(9, 0x80000000);
+ basic_srav.checkReg(10, 5);
+ basic_srav.perform_test(testCPU, testMem);
+
+ test basic_sravPos("srav",
+ "verify that R8 = R9 >> R10 and R9 R10 unchanged when R9 is positive", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 9, 8, 0, 7).data);
+ writeReg(testCPU, 9, 0x74BABBC1);
+ writeReg(testCPU, 10, 9);
+ basic_sravPos.checkReg(8, 0x003A5D5D);
+ basic_sravPos.checkReg(9, 0x74BABBC1);
+ basic_sravPos.checkReg(10, 9);
+ basic_sravPos.perform_test(testCPU, testMem);
+
+ test basic_jr("jr", "Verify that pc = R9 and R9 unchanged as well as that the"
+ " instruction in the branch delay slot is executed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 0, 0, 0, 8).data);
+ // R8 = R9 >> 1 in the branch delay slot
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 9, 8, 1, 2).data);
+ writeReg(testCPU, 9, 0x000000A4);
+ basic_jr.checkReg(255, 0x000000A4);
+ basic_jr.checkReg(8, 0x00000052);
+ basic_jr.checkReg(9, 0x000000A4);
+ basic_jr.perform_test(testCPU, testMem);
+
+ test basic_jalr("jalr",
+ "Verify that pc = R9, R1 = R9 + 8 and R9 unchangedas well as that the"
+ " instruction in the branch delay slot is executed and R31 set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 0, 31, 0, 9).data);
+ // R8 = R9 >> 3 in the branch delay slot
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 9, 8, 3, 2).data);
+ writeReg(testCPU, 9, 0x000000B4);
+ basic_jalr.checkReg(255, 0x000000B4);
+ basic_jalr.checkReg(8, 0x00000016);
+ basic_jalr.checkReg(31, get_pc(testCPU) + 8);
+ basic_jalr.perform_test(testCPU, testMem);
+
+ // nops after since:
+ // "Reads of the HI or LO special registers must be separated from
+ // subsequent instructions that write to them by two or more other
+ // instructions."
+ test basic_mthi("mthi", "Checks value from mfhi is same as given in mthi", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(8, 0, 0, 0, 17).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 9, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x0BABABAC);
+ basic_mthi.checkReg(9, 0x0BABABAC);
+ basic_mthi.perform_test(testCPU, testMem);
+
+ test basic_mfhi("mfhi", "Checks value from mfhi is same as given in mthi", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(8, 0, 0, 0, 17).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 9, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1F1C1D1A);
+ basic_mfhi.checkReg(9, 0x1F1C1D1A);
+ basic_mfhi.perform_test(testCPU, testMem);
+
+ test basic_mtlo("mtlo", "Checks value from mflo is same as given in mtlo", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(8, 0, 0, 0, 17).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 9, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x0BABABAC);
+ basic_mtlo.checkReg(9, 0x0BABABAC);
+ basic_mtlo.perform_test(testCPU, testMem);
+
+ test basic_mflo("mflo", "Checks value from mflo is same as given in mtlo", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(8, 0, 0, 0, 17).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 9, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1F1C1D1A);
+ basic_mflo.checkReg(9, 0x1F1C1D1A);
+ basic_mflo.perform_test(testCPU, testMem);
+
+ test basic_multu("multu", "Verify values of hi and lo after R10 * R11", 5);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 25).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 16,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 10, 0x0BABABAB);
+ writeReg(testCPU, 11, 0xFEFEFEFE);
+ basic_multu.checkReg(8, 0x0B9FF447);
+ basic_multu.checkReg(9, 0xE651FDAA);
+ basic_multu.perform_test(testCPU, testMem);
+
+ test basic_mult("mult", "Verify values of hi and lo after R10 * R11 with R10 "
+ "and R11 both positive", 5);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 24).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 16,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 10, 0x1ACDC121);
+ writeReg(testCPU, 11, 0x22BBC999);
+ basic_mult.checkReg(8, 0x03A2FD0E);
+ basic_mult.checkReg(9, 0x06B655B9);
+ basic_mult.perform_test(testCPU, testMem);
+
+ test mult_negative("mult", "Verify values of hi and lo after R10 * R11", 5);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 24).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 16,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 10, 0x0BABABAB);
+ writeReg(testCPU, 11, 0xFEFEFEFE);
+ mult_negative.checkReg(8, 0xFFF4489C);
+ mult_negative.checkReg(9, 0xE651FDAA);
+ mult_negative.perform_test(testCPU, testMem);
+
+ test basic_divu("divu", "Check hi and lo after R10 / R11", 5);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 27).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 16,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 10, 0xF1489B44);
+ writeReg(testCPU, 11, 0x000000A1);
+ basic_divu.checkReg(8, 121);
+ basic_divu.checkReg(9, 25143275);
+ basic_divu.perform_test(testCPU, testMem);
+
+ test basic_div("div", "Check hi and lo after R10 / R11 (signed)", 3);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 26).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeMem(testMem, get_pc(testCPU) + 12,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeMem(testMem, get_pc(testCPU) + 16,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 10, 0xF1489B44);
+ writeReg(testCPU, 11, 0x000000A1);
+ basic_div.checkReg(8, 0xffffff87);
+ basic_div.checkReg(9, 0xffe8999d);
+ basic_div.perform_test(testCPU, testMem);
+
+ test div_negop2("div", "Check hi and lo after R10 / R11 (signed) where R11 is"
+ " negative", 3);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(10, 11, 0, 0, 26).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 8, 0, 16).data);
+ writeMem(testMem, get_pc(testCPU) + 8,
+ instruction_impl_r(0, 0, 9, 0, 18).data);
+ writeReg(testCPU, 10, 0x0BF9F147);
+ writeReg(testCPU, 11, 0xFFFFFF12);
+ div_negop2.checkReg(8, 0xB);
+ div_negop2.checkReg(9, 0xfff31e2e);
+ div_negop2.perform_test(testCPU, testMem);
+
+ test basic_add("add",
+ "Verify the result of an add where there is no overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 32).data);
+ writeReg(testCPU, 9, 0x0BB8BB8F);
+ writeReg(testCPU, 10, 0x00AAA1C1);
+ basic_add.checkReg(8, 0xC635D50);
+ basic_add.perform_test(testCPU, testMem);
+
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ test add_overflow_pos("add", "Check that dest register doesn't change if "
+ "positive overflow occurs in add", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 32).data);
+ writeReg(testCPU, 9, 0x7A8B8BB1);
+ writeReg(testCPU, 10, 0x71649BCD);
+ add_overflow_pos.checkReg(8, 0xFAFAFAFA);
+ add_overflow_pos.perform_test(testCPU, testMem);
+
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ test add_overflow_neg("add", "Check that dest register doesn't change if "
+ "negative overflow occurs in add", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 32).data);
+ writeReg(testCPU, 9, 0x80ABAF14);
+ writeReg(testCPU, 10, 0xF1649BCD);
+ add_overflow_neg.checkReg(8, 0xFAFAFAFA);
+ add_overflow_neg.perform_test(testCPU, testMem);
+
+ test basic_addu("addu", "Verify the result of addu with no overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 33).data);
+ writeReg(testCPU, 9, 0x1374BAB3);
+ writeReg(testCPU, 10, 0x3A947118);
+ basic_addu.checkReg(8, 0x4E092BCB);
+ basic_addu.perform_test(testCPU, testMem);
+
+ test addu_overflow("addu",
+ "Verify that addu result valid even with overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 33).data);
+ writeReg(testCPU, 9, 0xF374BAB3);
+ writeReg(testCPU, 10, 0x3A947118);
+ addu_overflow.checkReg(8, 0x2E092BCB);
+ addu_overflow.perform_test(testCPU, testMem);
+
+ test basic_sub("sub",
+ "Verify the result of a sub where there is no overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 34).data);
+ writeReg(testCPU, 9, 0x0BB8BB8F);
+ writeReg(testCPU, 10, 0x00AAA1C1);
+ basic_sub.checkReg(8, 0xB0E19CE);
+ basic_sub.perform_test(testCPU, testMem);
+
+ test sub_overflow_pos("sub", "Check that dest register doesn't change if "
+ "positive overflow occurs in sub", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 34).data);
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ writeReg(testCPU, 9, 0x7A8B8BB1);
+ writeReg(testCPU, 10, 0x81649BCD);
+ sub_overflow_pos.checkReg(8, 0xFAFAFAFA);
+ sub_overflow_pos.perform_test(testCPU, testMem);
+
+ test sub_overflow_neg("sub", "Check that dest register doesn't change if "
+ "negative overflow occurs in sub", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 34).data);
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ writeReg(testCPU, 9, 0x80ABAF14);
+ writeReg(testCPU, 10, 0x71649BCD);
+ sub_overflow_neg.checkReg(8, 0xFAFAFAFA);
+ sub_overflow_neg.perform_test(testCPU, testMem);
+
+ test basic_subu("subu", "Verify the result of subu with no overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 35).data);
+ writeReg(testCPU, 9, 0x1374BAB3);
+ writeReg(testCPU, 10, 0x3A947118);
+ basic_subu.checkReg(8, 0xD8E0499B);
+ basic_subu.perform_test(testCPU, testMem);
+
+ test subu_overflow("subu",
+ "Verify that subu result valid even with overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 35).data);
+ writeReg(testCPU, 9, 0x7374BAB3);
+ writeReg(testCPU, 10, 0xF14A8BC1);
+ subu_overflow.checkReg(8, 0x822A2EF2);
+ subu_overflow.perform_test(testCPU, testMem);
+
+ test and_basic("and", "Verify the result of R8 = R9 & R10", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 36).data);
+ writeReg(testCPU, 9, 0x1337C3D0);
+ writeReg(testCPU, 10, 0xBB81A1AC);
+ and_basic.checkReg(8, 0x13018180);
+ and_basic.perform_test(testCPU, testMem);
+
+ test or_basic("or", "Verify the result of R8 = R9 | R10", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 37).data);
+ writeReg(testCPU, 9, 0x1337C3D0);
+ writeReg(testCPU, 10, 0xBB81A1AC);
+ or_basic.checkReg(8, 0xBBB7E3FC);
+ or_basic.perform_test(testCPU, testMem);
+
+ test xor_basic("xor", "Verify the result of R8 = R9 ^ R10", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 38).data);
+ writeReg(testCPU, 9, 0x1337C3D0);
+ writeReg(testCPU, 10, 0xBB81A1AC);
+ xor_basic.checkReg(8, 0xA8B6627C);
+ xor_basic.perform_test(testCPU, testMem);
+
+ test slt_basic_unset("slt",
+ "Check that R8 isn't set since R9 > R10 (signed)", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 42).data);
+ writeReg(testCPU, 8, 0x1234ABCD);
+ writeReg(testCPU, 9, 0x03456789);
+ writeReg(testCPU, 10, 0xF4F4BEEE);
+ slt_basic_unset.checkReg(8, 0);
+ slt_basic_unset.perform_test(testCPU, testMem);
+
+ test sltu_basic("sltu", "Check that R8 is set since R9 < R10 (unsigned)", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 43).data);
+ writeReg(testCPU, 8, 0x1234ABCD);
+ writeReg(testCPU, 9, 0x03456789);
+ writeReg(testCPU, 10, 0xF4F4BEEE);
+ sltu_basic.checkReg(8, 1);
+ sltu_basic.perform_test(testCPU, testMem);
+
+ test slt_basic_set("slt", "Check that R8 is set since R9 < R10 (signed)", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_r(9, 10, 8, 0, 42).data);
+ writeReg(testCPU, 8, 0xBBBBBBBB);
+ writeReg(testCPU, 9, 0x08008501);
+ writeReg(testCPU, 10, 0x0F00F13D);
+ slt_basic_set.checkReg(8, 1);
+ slt_basic_set.perform_test(testCPU, testMem);
+
+ test j_basic("j", "Check that pc has correct value after branch delay slot "
+ "and the instruction in the branch delay slot is executed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(2, 99).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(9, 0, 8, 0, 32).data);
+ writeReg(testCPU, 9, 0xAB);
+ j_basic.checkReg(255, 396);
+ j_basic.checkReg(8, 0xAB);
+ j_basic.perform_test(testCPU, testMem);
+
+ test j_aligned("j", "Check that the upper 4 bits of the pc remain unchanged",
+ 2);
+ writeReg(testCPU, 255, 0x1ABCDEF4);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(2, 99).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ j_aligned.checkReg(255, 0x1000018C);
+ j_aligned.perform_test(testCPU, testMem);
+
+ test j_alignedWithBranch("j", "Check that the new PC is aligned with the "
+ "instruction in the branch delay slot", 2);
+ writeReg(testCPU, 255, 0x0FFFFFFC);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(2, 99).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ j_alignedWithBranch.checkReg(255, 0x1000018C);
+ j_alignedWithBranch.perform_test(testCPU, testMem);
+
+ test jal_basic("jal", "Check that pc and link register have correct values "
+ "after branch delay slot and the instruction in the branch delay slot is "
+ "executed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(3, 109).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(9, 0, 8, 0, 32).data);
+ writeReg(testCPU, 9, 0xAB);
+ jal_basic.checkReg(255, 436);
+ jal_basic.checkReg(8, 0xAB);
+ jal_basic.checkReg(31, get_pc(testCPU) + 8);
+ jal_basic.perform_test(testCPU, testMem);
+
+ test jal_aligned("jal", "Check that the upper 4 bits of the pc remain "
+ "unchanged", 2);
+ writeReg(testCPU, 255, 0x1ABCDEF4);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(3, 99).data);
+ writeMem(testMem, get_pc(testCPU) + 4, instruction_impl_r(0, 0, 0, 0, 0).data);
+ j_aligned.checkReg(255, 0x1000018C);
+ j_aligned.perform_test(testCPU, testMem);
+
+ test jal_alignedWithBranch("j", "Check that the new PC is aligned with the "
+ "instruction in the branch delay slot", 2);
+ writeReg(testCPU, 255, 0x0FFFFFFC);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_j(3, 99).data);
+ writeMem(testMem, get_pc(testCPU) + 4, instruction_impl_r(0, 0, 0, 0, 0).data);
+ jal_alignedWithBranch.checkReg(255, 0x1000018C);
+ jal_alignedWithBranch.perform_test(testCPU, testMem);
+
+ test bltz_basic_no("bltz", "Check that branch isn't taken if source register "
+ "is equal to 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ bltz_basic_no.checkReg(8, 0);
+ bltz_basic_no.checkReg(255, get_pc(testCPU) + 8);
+ bltz_basic_no.perform_test(testCPU, testMem);
+
+ test bltz_basic_noPos("bltz", "Check that branch isn't taken if source "
+ "register is > 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1349DE40);
+ bltz_basic_noPos.checkReg(8, 0x1349DE40);
+ bltz_basic_noPos.checkReg(255, get_pc(testCPU) + 8);
+ bltz_basic_noPos.perform_test(testCPU, testMem);
+
+ test bltz_basic_yes("bltz", "Check that branch is taken if source register "
+ "is < 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x80FAB131);
+ bltz_basic_yes.checkReg(8, 0x80FAB131);
+ bltz_basic_yes.checkReg(255, get_pc(testCPU) - 36);
+ bltz_basic_yes.perform_test(testCPU, testMem);
+
+ test bgez_basic_yesZero("bgez", "Check that branch is taken if source "
+ "register is = 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 1, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ bgez_basic_yesZero.checkReg(8, 0);
+ bgez_basic_yesZero.checkReg(255, get_pc(testCPU) - 36);
+ bgez_basic_yesZero.perform_test(testCPU, testMem);
+
+ test bgez_basic_yesPos("bgez", "Check that branch is taken if source register"
+ " is > 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 1, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x3323);
+ bgez_basic_yesPos.checkReg(8, 0x3323);
+ bgez_basic_yesPos.checkReg(255, get_pc(testCPU) - 36);
+ bgez_basic_yesPos.perform_test(testCPU, testMem);
+
+ test bgez_basic_no("bgez", "Check that branch isn't taken if source register "
+ "is < 0. Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 1, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x8349DE40);
+ bgez_basic_no.checkReg(8, 0x8349DE40);
+ bgez_basic_no.checkReg(255, get_pc(testCPU) + 8);
+ bgez_basic_no.perform_test(testCPU, testMem);
+
+ test bltzal_basic_no("bltzal", "Check that branch isn't taken if source "
+ "register is equal to 0. Also check that source isn't changed and the "
+ "return address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 16, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ bltzal_basic_no.checkReg(8, 0);
+ bltzal_basic_no.checkReg(255, get_pc(testCPU) + 8);
+ bltzal_basic_no.checkReg(31, get_pc(testCPU) + 8);
+ bltzal_basic_no.perform_test(testCPU, testMem);
+
+ test bltzal_basic_noPos("bltzal", "Check that branch isn't taken if source "
+ "register is > 0. Also check that source isn't changed and the return "
+ "address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 16, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1349DE40);
+ bltzal_basic_noPos.checkReg(8, 0x1349DE40);
+ bltzal_basic_noPos.checkReg(255, get_pc(testCPU) + 8);
+ bltzal_basic_noPos.checkReg(31, get_pc(testCPU) + 8);
+ bltzal_basic_noPos.perform_test(testCPU, testMem);
+
+ test bltzal_basic_yes("bltzal", "Check that branch is taken if source "
+ "register is < 0. Also check that source isn't changed and the return "
+ "address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 16, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x80FAB131);
+ bltzal_basic_yes.checkReg(8, 0x80FAB131);
+ bltzal_basic_yes.checkReg(255, get_pc(testCPU) - 36);
+ bltzal_basic_yes.checkReg(31, get_pc(testCPU) + 8);
+ bltzal_basic_yes.perform_test(testCPU, testMem);
+
+ test bgezal_basic_yesZero("bgezal", "Check that branch is taken if source "
+ "register is = 0. Also check that source isn't changed and the return "
+ "address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 17, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ bgezal_basic_yesZero.checkReg(8, 0);
+ bgezal_basic_yesZero.checkReg(255, get_pc(testCPU) - 36);
+ bgezal_basic_yesZero.checkReg(31, get_pc(testCPU) + 8);
+ bgezal_basic_yesZero.perform_test(testCPU, testMem);
+
+ test bgezal_basic_yesPos("bgezal", "Check that branch is taken if source "
+ "register is > 0. Also check that source isn't changed and the return "
+ "address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 17, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x3323);
+ bgezal_basic_yesPos.checkReg(8, 0x3323);
+ bgezal_basic_yesPos.checkReg(255, get_pc(testCPU) - 36);
+ bgezal_basic_yesPos.checkReg(31, get_pc(testCPU) + 8);
+ bgezal_basic_yesPos.perform_test(testCPU, testMem);
+
+ test bgezal_basic_no("bgezal", "Check that branch isn't taken if source "
+ "register is < 0. Also check that source isn't changed and the return "
+ "address is set", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(1, 8, 17, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x8349DE40);
+ bgezal_basic_no.checkReg(8, 0x8349DE40);
+ bgezal_basic_no.checkReg(255, get_pc(testCPU) + 8);
+ bgezal_basic_no.checkReg(31, get_pc(testCPU) + 8);
+ bgezal_basic_no.perform_test(testCPU, testMem);
+
+ test beq_no("beq", "Check that branch isn't taken if "
+ "source register != destination register. Also check that source, "
+ "destination aren't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(4, 8, 9, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0xBA11DEEE);
+ writeReg(testCPU, 9, 0xEEED11AB);
+ beq_no.checkReg(8, 0xBA11DEEE);
+ beq_no.checkReg(9, 0xEEED11AB);
+ beq_no.checkReg(255, get_pc(testCPU) + 8);
+ beq_no.perform_test(testCPU, testMem);
+
+ test bne_yes("bne", "Check that branch is taken if "
+ "source register != destination register. Also check that source, "
+ "destination aren't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(5, 8, 9, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0xBA11DEEE);
+ writeReg(testCPU, 9, 0xEEED11AB);
+ bne_yes.checkReg(8, 0xBA11DEEE);
+ bne_yes.checkReg(9, 0xEEED11AB);
+ bne_yes.checkReg(255, get_pc(testCPU) - 36);
+ bne_yes.perform_test(testCPU, testMem);
+
+ test beq_yes("beq", "Check that branch is taken if "
+ "source register = destination register. Also check that source, "
+ "destination aren't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(4, 8, 9, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1EAFEEEE);
+ writeReg(testCPU, 9, 0x1EAFEEEE);
+ beq_yes.checkReg(8, 0x1EAFEEEE);
+ beq_yes.checkReg(9, 0x1EAFEEEE);
+ beq_yes.checkReg(255, get_pc(testCPU) - 36);
+ beq_yes.perform_test(testCPU, testMem);
+
+ test bne_no("bne", "Check that the branch isn't taken if "
+ "source register = destination register. Also check that source, "
+ "destination aren't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(5, 8, 9, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x1EAFEEEE);
+ writeReg(testCPU, 9, 0x1EAFEEEE);
+ bne_no.checkReg(8, 0x1EAFEEEE);
+ bne_no.checkReg(9, 0x1EAFEEEE);
+ bne_no.checkReg(255, get_pc(testCPU) + 8);
+ bne_no.perform_test(testCPU, testMem);
+
+ test blez_yes("blez", "Check that the branch is taken if source < 0. Also "
+ "check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(6, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x80009D04);
+ blez_yes.checkReg(8, 0x80009D04);
+ blez_yes.checkReg(255, get_pc(testCPU) - 36);
+ blez_yes.perform_test(testCPU, testMem);
+
+ test blez_yesZero("blez", "Check that the branch is taken if source = 0. "
+ "Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(6, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ blez_yesZero.checkReg(8, 0);
+ blez_yesZero.checkReg(255, get_pc(testCPU) - 36);
+ blez_yesZero.perform_test(testCPU, testMem);
+
+ test blez_no("blez", "Check that the branch isn't taken if source > 0. Also "
+ "check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(6, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x333F125A);
+ blez_no.checkReg(8, 0x333F125A);
+ blez_no.checkReg(255, get_pc(testCPU) + 8);
+ blez_no.perform_test(testCPU, testMem);
+
+ test bgtz_no("bgtz", "Check that the branch isn't taken if source < 0. Also "
+ "check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(7, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x80009D04);
+ bgtz_no.checkReg(8, 0x80009D04);
+ bgtz_no.checkReg(255, get_pc(testCPU) + 8);
+ bgtz_no.perform_test(testCPU, testMem);
+
+ test bgtz_noZero("bgtz", "Check that the branch isn't taken if source = 0. "
+ "Also check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(7, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0);
+ bgtz_noZero.checkReg(8, 0);
+ bgtz_noZero.checkReg(255, get_pc(testCPU) + 8);
+ bgtz_noZero.perform_test(testCPU, testMem);
+
+ test bgtz_yes("bgtz", "Check that the branch is taken if source > 0. Also "
+ "check that source isn't changed", 2);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(7, 8, 0, 0xFFF6).data);
+ writeMem(testMem, get_pc(testCPU) + 4,
+ instruction_impl_r(0, 0, 0, 0, 0).data);
+ writeReg(testCPU, 8, 0x333F125A);
+ bgtz_yes.checkReg(8, 0x333F125A);
+ bgtz_yes.checkReg(255, get_pc(testCPU) - 36);
+ bgtz_yes.perform_test(testCPU, testMem);
+
+ test basic_addi("addi", "Verify the result of an addi where there is no "
+ "overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(8, 9, 8, 0x034D).data);
+ writeReg(testCPU, 9, 0x0BB8BB8F);
+ basic_addi.checkReg(8, 0x0BB8BEDC);
+ basic_addi.perform_test(testCPU, testMem);
+
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ test addi_overflow_pos("addi", "Check that dest register doesn't change if "
+ "positive overflow occurs in addi", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(8, 9, 8, 0x734D).data);
+ writeReg(testCPU, 9, 0x7FFFFBCD);
+ addi_overflow_pos.checkReg(8, 0xFAFAFAFA);
+ addi_overflow_pos.perform_test(testCPU, testMem);
+
+ writeReg(testCPU, 8, 0xFAFAFAFA);
+ test addi_overflow_neg("addi", "Check that dest register doesn't change if "
+ "negative overflow occurs in addi", 1, mips_ExceptionArithmeticOverflow);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(8, 9, 8, 0x8003).data);
+ writeReg(testCPU, 9, 0x80000014);
+ addi_overflow_neg.checkReg(8, 0xFAFAFAFA);
+ addi_overflow_neg.perform_test(testCPU, testMem);
+
+ test basic_addiu("addiu", "Verify the result of addiu with no overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(9, 9, 8, 0x1437).data);
+ writeReg(testCPU, 9, 0x1374BAB3);
+ basic_addiu.checkReg(8, 0x1374CEEA);
+ basic_addiu.perform_test(testCPU, testMem);
+
+ test addiu_overflow("addiu", "Verify that addiu result valid even with "
+ "overflow", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(9, 9, 8, 0xABCD).data);
+ writeReg(testCPU, 9, 0xFFFFFAB3);
+ addiu_overflow.checkReg(8, 0xFFFFA680);
+ addiu_overflow.perform_test(testCPU, testMem);
+
+ test slti_yesNeg("slti", "Verify that R8 is 1 when R9 is less than the "
+ "negative immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0xFFD3).data);
+ writeReg(testCPU, 9, 0xF14D3E0B);
+ writeReg(testCPU, 8, 2);
+ slti_yesNeg.checkReg(8, 1);
+ slti_yesNeg.perform_test(testCPU, testMem);
+
+ test slti_noNeg("slti", "Verify that R8 is 0 when R9 is more than the "
+ "negative immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0x80D3).data);
+ writeReg(testCPU, 9, 0xFFFFF329);
+ writeReg(testCPU, 8, 2);
+ slti_noNeg.checkReg(8, 0);
+ slti_noNeg.perform_test(testCPU, testMem);
+
+ test slti_yesPos("slti", "Verify that R8 is 1 when R9 is less than the "
+ "positive immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0x74D1).data);
+ writeReg(testCPU, 9, 0x63D0);
+ writeReg(testCPU, 8, 2);
+ slti_yesPos.checkReg(8, 1);
+ slti_yesPos.perform_test(testCPU, testMem);
+
+ test slti_noPos("slti", "Verify that R8 is 0 when R9 is more than the "
+ "positive immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0x034C).data);
+ writeReg(testCPU, 9, 0x1AAAAAA4);
+ writeReg(testCPU, 8, 2);
+ slti_noPos.checkReg(8, 0);
+ slti_noPos.perform_test(testCPU, testMem);
+
+ test slti_noPosEq("slti", "Verify that R8 is 0 when R9 is equal to the "
+ "positive immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0x3B3B).data);
+ writeReg(testCPU, 9, 0x3B3B);
+ writeReg(testCPU, 8, 2);
+ slti_noPosEq.checkReg(8, 0);
+ slti_noPosEq.perform_test(testCPU, testMem);
+
+ test slti_noNegEq("slti", "Verify that R8 is 0 when R9 is equal to the "
+ "negative immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(10, 9, 8, 0x8303).data);
+ writeReg(testCPU, 9, 0xFFFF8303);
+ writeReg(testCPU, 8, 2);
+ slti_noNegEq.checkReg(8, 0);
+ slti_noNegEq.perform_test(testCPU, testMem);
+
+ test sltiu_yesSmall("sltiu", "Verify that R8 is 1 when R9 is less than the "
+ "immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(11, 9, 8, 0x7432).data);
+ writeReg(testCPU, 9, 0x6DF0);
+ writeReg(testCPU, 8, 2);
+ sltiu_yesSmall.checkReg(8, 1);
+ sltiu_yesSmall.perform_test(testCPU, testMem);
+
+ test sltiu_yesBig("sltiu", "Verify that R8 is 1 when R9 is less than the "
+ "immediate using the fact the immediate is still sign extended", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(11, 9, 8, 0xFF14).data);
+ writeReg(testCPU, 9, 0xFFFF7D1b);
+ writeReg(testCPU, 8, 2);
+ sltiu_yesBig.checkReg(8, 1);
+ sltiu_yesBig.perform_test(testCPU, testMem);
+
+ test sltiu_noSmall("sltiu", "Verify that R8 is 0 when R9 is more than the "
+ "immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(11, 9, 8, 0x6B1F).data);
+ writeReg(testCPU, 9, 0x7BF12734);
+ writeReg(testCPU, 8, 2);
+ sltiu_noSmall.checkReg(8, 0);
+ sltiu_noSmall.perform_test(testCPU, testMem);
+
+ test sltiu_noBig("sltiu", "Verify that R8 is 0 when R9 is more than the "
+ "immediate using the fact the immediate is still sign extended", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(11, 9, 8, 0x8932).data);
+ writeReg(testCPU, 9, 0xFFFF9632);
+ writeReg(testCPU, 8, 2);
+ sltiu_noBig.checkReg(8, 0);
+ sltiu_noBig.perform_test(testCPU, testMem);
+
+ test basic_andi("andi", "Verify the result of R8 after R9 ANDed with "
+ "immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(12, 9, 8, 0xF6D7).data);
+ writeReg(testCPU, 9, 0xAB34965B);
+ basic_andi.checkReg(8, 0x9653);
+ basic_andi.perform_test(testCPU, testMem);
+
+ test basic_ori("ori", "Verify the result of R8 after R9 ORed with "
+ "immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(13, 9, 8, 0x2864).data);
+ writeReg(testCPU, 9, 0xFABADAB1);
+ basic_ori.checkReg(8, 0xFABAFAF5);
+ basic_ori.perform_test(testCPU, testMem);
+
+ test basic_xori("xori", "Verify the result of R8 after R9 XORed with "
+ "immediate", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(14, 9, 8, 0x31AB).data);
+ writeReg(testCPU, 9, 0x1DABAD00);
+ basic_xori.checkReg(8, 0x1DAB9CAB);
+ basic_xori.perform_test(testCPU, testMem);
+
+ test basic_lui("lui", "Verify that the immediate is placed in the 16 MSBs of "
+ "R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(15, 0, 8, 0xB153).data);
+ writeReg(testCPU, 8, 0xFABFABFA);
+ basic_lui.checkReg(8, 0xB1530000);
+ basic_lui.perform_test(testCPU, testMem);
+
+ test basic_lb("lb", "Verify that the byte from the effective address is "
+ "stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(32, 9, 8, 0xFFF2).data);
+ writeReg(testCPU, 9, 512);
+ writeMem(testMem, 496, 0xABAB1DAB);
+ basic_lb.checkReg(8, 0x1D);
+ basic_lb.perform_test(testCPU, testMem);
+
+ test lb_signExtend("lb", "Verify that the sign extended byte from the "
+ "effective address is stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(32, 9, 8, 0xFF8F).data);
+ writeReg(testCPU, 9, 616);
+ writeMem(testMem, 500, 0x777777F3);
+ lb_signExtend.checkReg(8, 0xFFFFFFF3);
+ lb_signExtend.perform_test(testCPU, testMem);
+
+ test lb_posOffset("lb", "Verify that the byte from the effective address "
+ "(generated with a positive offset) is stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(32, 9, 8, 15).data);
+ writeReg(testCPU, 9, 640);
+ writeMem(testMem, 652, 0xBFBFBF75);
+ lb_posOffset.checkReg(8, 0x00000075);
+ lb_posOffset.perform_test(testCPU, testMem);
+
+ test basic_lh("lh", "Verify that the half-word from the effective address is "
+ "stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(33, 9, 8, 0xFFF3).data);
+ writeReg(testCPU, 9, 551);
+ writeMem(testMem, 536, 0x55557B7B);
+ basic_lh.checkReg(8, 0x00007B7B);
+ basic_lh.perform_test(testCPU, testMem);
+
+ test lh_signExtend("lh", "Verify that the sign extended half-word from the "
+ "effective address is stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(33, 9, 8, 0xFFF4).data);
+ writeReg(testCPU, 9, 540);
+ writeMem(testMem, 528, 0x84F37676);
+ lh_signExtend.checkReg(8, 0xFFFF84F3);
+ lh_signExtend.perform_test(testCPU, testMem);
+
+ test lh_posOffset("lh", "Verify that the half-word from the effective "
+ "address (generated with a positive offset) is stored in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(33, 9, 8, 10).data);
+ writeReg(testCPU, 9, 510);
+ writeMem(testMem, 520, 0x7BBCC3D0);
+ lh_posOffset.checkReg(8, 0x00007BBC);
+ lh_posOffset.perform_test(testCPU, testMem);
+
+ test lh_unalignedReg("lh", "Verify that the destination register isn't "
+ "changed after an Invalid Alignment Exception", 1,
+ mips_ExceptionInvalidAlignment);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(33, 9, 8, 11).data);
+ writeReg(testCPU, 9, 520);
+ writeReg(testCPU, 8, 0xA4C3B177);
+ lh_unalignedReg.checkReg(8, 0xA4C3B177);
+ lh_unalignedReg.perform_test(testCPU, testMem);
+
+ test basic_lwl1("lwl", "Verify that the most significant byte of the "
+ "unaligned word replaces the most significant byte of R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(34, 9, 8, 3).data);
+ writeMem(testMem, 600, 0xF13BA4A4);
+ writeReg(testCPU, 8, 0x17462538);
+ writeReg(testCPU, 9, 600);
+ basic_lwl1.checkReg(8, 0xA4462538);
+ basic_lwl1.perform_test(testCPU, testMem);
+
+ test basic_lwl2("lwl", "Verify that the 2 most significant bytes of the "
+ "unaligned word replaces the 2 most significant bytes of R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(34, 9, 8, 2).data);
+ writeMem(testMem, 600, 0xF13BA4A4);
+ writeReg(testCPU, 8, 0x17462538);
+ writeReg(testCPU, 9, 600);
+ basic_lwl2.checkReg(8, 0xA4A42538);
+ basic_lwl2.perform_test(testCPU, testMem);
+
+ test basic_lw("lw", "Verify that the contents of the aligned word are loaded "
+ "into R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(35, 9, 8, -3).data);
+ writeReg(testCPU, 9, 543);
+ writeMem(testMem, 540, 0xBADBADBA);
+ basic_lw.checkReg(8, 0xBADBADBA);
+ basic_lw.perform_test(testCPU, testMem);
+
+ test lw_unaligned("lw", "Verify an Invalid Aligment error occurs for lw", 1,
+ mips_ExceptionInvalidAlignment);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(35, 9, 8, 0).data);
+ writeReg(testCPU, 9, 474);
+ lw_unaligned.perform_test(testCPU, testMem);
+
+ test basic_lbu("lbu", "Verify that the byte is not sign extended when loaded "
+ "into R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(36, 9, 8, 24).data);
+ writeReg(testCPU, 9, 500);
+ writeMem(testMem, 524, 0x83D14751);
+ basic_lbu.checkReg(8, 0x00000083);
+ basic_lbu.perform_test(testCPU, testMem);
+
+ test basic_lhu("lhu", "Verify that the half-word is not sign extended when "
+ "loaded into R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(37, 9, 8, 8).data);
+ writeReg(testCPU, 9, 540);
+ writeMem(testMem, 548, 0x01189998);
+ basic_lhu.checkReg(8, 0x00000118);
+ basic_lhu.perform_test(testCPU, testMem);
+
+ test lhu_unaligned("lhu", "Verify an Invalid Alignment error occurs for lhu",
+ 1, mips_ExceptionInvalidAlignment);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(37, 9, 8, 3).data);
+ writeReg(testCPU, 9, 574);
+ lhu_unaligned.perform_test(testCPU, testMem);
+
+ test basic_lwr1("lwr", "Verify that the least significant byte of an "
+ "unaligned word replaces the least significant byte in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(38, 9, 8, 0).data);
+ writeMem(testMem, 564, 0x73B04E1C);
+ writeReg(testCPU, 8, 0x075936AB);
+ writeReg(testCPU, 9, 564);
+ basic_lwr1.checkReg(8, 0x07593673);
+ basic_lwr1.perform_test(testCPU, testMem);
+
+ test basic_lwr2("lwr", "Verify that the 3 least significant bytes of an "
+ "unaligned word replace the 3 least significant bytes in R8", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(38, 9, 8, 2).data);
+ writeMem(testMem, 564, 0x73B04E1C);
+ writeReg(testCPU, 8, 0x075936AB);
+ writeReg(testCPU, 9, 564);
+ basic_lwr2.checkReg(8, 0x0773B04E);
+ basic_lwr2.perform_test(testCPU, testMem);
+
+ test basic_sb("sb",
+ "Verify that the least significant byte of R8 is stored in the effective "
+ "address without overwriting the rest of the word in memory", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(40, 9, 8, 3).data);
+ writeMem(testMem, 540, 0x1ACD4B3D);
+ writeReg(testCPU, 8, 0xABCDEF93);
+ writeReg(testCPU, 9, 540);
+ basic_sb.checkMem(540, 0x1ACD4B93);
+ basic_sb.perform_test(testCPU, testMem);
+
+ test basic_sb1("sb", "With offset 0, verify that the least significant byte "
+ "of R8 is stored in the effective address without overwriting the rest of "
+ "the word in memory", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(40, 9, 8, 0).data);
+ writeMem(testMem, 536, 0xB3310463);
+ writeReg(testCPU, 8, 0x123B4582);
+ writeReg(testCPU, 9, 536);
+ basic_sb1.checkMem(536, 0x82310463);
+ basic_sb1.perform_test(testCPU, testMem);
+
+ test basic_sh("sh", "Verify that the least significant half-word of R8 is "
+ "stored in the effective address without overwriting the rest of the word "
+ "in memory", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(41, 9, 8, 2).data);
+ writeMem(testMem, 544, 0x3E459C12);
+ writeReg(testCPU, 8, 0xABCD1149);
+ writeReg(testCPU, 9, 544);
+ basic_sh.checkMem(544, 0x3E451149);
+ basic_sh.perform_test(testCPU, testMem);
+
+ test basic_sh1("sh", "With offset 0, verify that the least significant "
+ "half-word of R8 is stored in the effective address without overwriting "
+ "the rest of the word in memory", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(41, 9, 8, 0).data);
+ writeMem(testMem, 548, 0xBB8C13D0);
+ writeReg(testCPU, 8, 0x9932B712);
+ writeReg(testCPU, 9, 548);
+ basic_sh1.checkMem(548, 0xB71213D0);
+ basic_sh1.perform_test(testCPU, testMem);
+
+ test basic_sw("sw", "Check that the value from R8 is correctly loaded into "
+ "memory", 1);
+ writeMem(testMem, get_pc(testCPU), instruction_impl_i(43, 9, 8, 0).data);
+ writeMem(testMem, 552, 0xABABABAB);
+ writeReg(testCPU, 8, 0x01590624);
+ writeReg(testCPU, 9, 552);
+ basic_sw.checkMem(552, 0x01590624);
+ basic_sw.perform_test(testCPU, testMem);
+
+ // This test ensures that instructions don't just work independantly
+ // Expected number of steps is 5496 for 12th fibonacci number
+ test fib("<internal>", "Check that the CPU can calculate the 12th fibonacci "
+ "number using various instructions", 5496);
+ writeMem(testMem, 0x0, 0x27bdffe0); // addiu sp,sp,-32
+ writeMem(testMem, 0x4, 0x2c820002); // sltiu v0,a0,2
+ writeMem(testMem, 0x8, 0xafb20018); // sw s2,24(sp);
+ writeMem(testMem, 0xc, 0xafbf001c); // sw ra,28(sp);
+ writeMem(testMem, 0x10, 0xafb10014); // sw s1,20(sp);
+ writeMem(testMem, 0x14, 0xafb00010); // sw s0,16(sp);
+ writeMem(testMem, 0x18, 0x14400011); // bnez v0,60 <f_fibonacci+0x60>
+ writeMem(testMem, 0x1c, 0x00809021); // move s2,a0
+ writeMem(testMem, 0x20, 0x00808021); // move s0,a0
+ writeMem(testMem, 0x24, 0x00008821); // move s1,zero
+ writeMem(testMem, 0x28, 0x2604ffff); // addiu a0,s0,-1
+ writeMem(testMem, 0x2c, 0x0c000000); // jal 0 <f_fibonacci>
+ writeMem(testMem, 0x30, 0x2610fffe); // addiu s0,s0,-2
+ writeMem(testMem, 0x34, 0x2e030002); // sltiu v1,s0,2
+ writeMem(testMem, 0x38, 0x1060fffb); // beqz v1,28 <f_fibonacci+0x28>
+ writeMem(testMem, 0x3c, 0x02228821); // addu s1,s1,v0
+ writeMem(testMem, 0x40, 0x32520001); // andi s2,s2,0x1
+ writeMem(testMem, 0x44, 0x8fbf001c); // lw ra,28(sp);
+ writeMem(testMem, 0x48, 0x02321021); // addu v0,s1,s2
+ writeMem(testMem, 0x4c, 0x8fb00010); // lw s0,16(sp);
+ writeMem(testMem, 0x50, 0x8fb20018); // lw s2,24(sp);
+ writeMem(testMem, 0x54, 0x8fb10014); // lw s1,20(sp);
+ writeMem(testMem, 0x58, 0x03e00008); // jr ra
+ writeMem(testMem, 0x5c, 0x27bd0020); // addiu sp,sp,32
+ writeMem(testMem, 0x60, 0x08000011); // j 44 <f_fibonacci+0x44>
+ writeMem(testMem, 0x64, 0x00008821); // move s1,zero
+ writeReg(testCPU, 31, 0x10000000);
+ writeReg(testCPU, 4, 12); // 12th fibonacci number
+ writeReg(testCPU, 29, 0x1000); // stack pointer
+ fib.checkReg(2, 144); // Expected result is 144
+ fib.perform_test(testCPU, testMem);
+
+ mips_mem_free(testMem);
+ testMem = NULL;
+ mips_cpu_free(testCPU);
+ testCPU = NULL;
+
+ mips_test_end_suite();
+
+ return 0;
}
-int test_bitwise(mips_mem_h ram, mips_cpu_h cpu, uint8_t op) {
- uint32_t a, b, ans, inst;
- int passed;
- for(unsigned i = 0; i < 10; ++i) {
- passed = 0;
- mips_cpu_reset(cpu);
- inst = change_endianness(gen_instruction(8, 9, 7, 0, op));
-
- a = rand() % 0xffffffff;
- b = rand() % 0xffffffff;
-
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
-
- mips_cpu_set_register(cpu, 8, a);
- mips_cpu_set_register(cpu, 9, b);
-
- mips_error mips_err = mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 7, &ans);
-
- if(op == AND) {
- //printf("%#10x & %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
- if((a & b) == ans) {
- passed = 1;
- }
- } else if(op == OR) {
- //printf("%#10x | %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
- if((a | b) == ans) {
- passed = 1;
- }
- } else {
- //printf("%#10x ^ %#10x = %#10x\t%#10x\n", a, b, ans, mips_err);
- if((a ^ b) == ans) {
- passed = 1;
- }
- }
-
-
- if(mips_err != mips_Success || !passed) {
- return 0;
- }
- }
- return 1;
+uint32_t get_pc(mips_cpu_h state){
+ uint32_t pc;
+ mips_cpu_get_pc(state, &pc);
+ return pc;
}
-int test_I(mips_mem_h ram, mips_cpu_h cpu, uint32_t type,
- uint32_t num1, uint32_t num2) {
- int passed = 0;
- uint32_t result, inst;
-
- mips_cpu_reset(cpu);
- inst = change_endianness(gen_instruction(type, 8, 7, num1));
-
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
- mips_cpu_set_register(cpu, 8, num2);
+mips_error test::perform_test(mips_cpu_h state, mips_mem_h mem){
- mips_cpu_step(cpu);
+ mips_error lastError = mips_Success;
- mips_cpu_get_register(cpu, 7, &result);
+ int testID = mips_test_begin_test(testName);
- switch(type) {
- case 8:
- if(result == num1 + num2) {
- passed = 1;
- }
- case 9:
- if(result == num1 + num2) {
- passed = 1;
- }
- case 12:
- if(result == (num1 & num2)) {
- passed = 1;
- }
- case 13:
- if(result == (num1 | num2)) {
- passed = 1;
- }
- case 14:
- if(result == (num1 ^ num2)) {
- passed = 1;
- }
- default:;
+ // Make the CPU perform the required number of instructions for the test
+ for(unsigned i = 0; i < numInstructions; i++){
+ mips_error attemptStep = mips_cpu_step(state);
+ if(attemptStep != mips_Success){
+ lastError = attemptStep;
}
-
- return passed;
-}
-
-int test_branch(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t a, uint8_t l, uint32_t opc2, uint32_t b) {
- int passed = 0;
- int pass = 0;
- uint32_t reg10, reg11, reg31, pc_set;
- pc_set = 32;
- mips_cpu_reset(cpu);
- mips_cpu_set_pc(cpu, pc_set);
-
- uint32_t inst = change_endianness(gen_instruction(opcode, 8, opc2, 3));
- mips_mem_write(ram, pc_set, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(8, 9, 10, 0, ADDU));
- mips_mem_write(ram, pc_set+4, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(8, 12, 11, 0, ADDU));
- mips_mem_write(ram, pc_set+16, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(8, 13, 10, 0, ADDU));
- mips_mem_write(ram, pc_set+8, 4, (uint8_t*)&inst);
-
- mips_cpu_set_register(cpu, 8, a);
- mips_cpu_set_register(cpu, 9, b);
- mips_cpu_set_register(cpu, 12, 30);
- mips_cpu_set_register(cpu, 13, 100);
-
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 10, &reg10);
- mips_cpu_get_register(cpu, 11, &reg11);
-
- if(l == 1) {
- mips_cpu_get_register(cpu, 31, &reg31);
- if(reg31 == pc_set+8) {
- pass = 1;
- }
- } else {
- pass = 1;
+ }
+
+ // Check the state of the mem is as expected afterward
+ for(unsigned i = 0; i < unsigned(memCheck.size()); i++){
+ uint32_t testValue;
+ mips_mem_read(mem, memCheck[i].address, 4, (uint8_t*)&testValue);
+ byte_swap_test(testValue);
+ if (testValue != memCheck[i].value) {
+ fprintf(stderr, "[Test %d] Mem[0x%X] is 0x%X - Expected 0x%X\n",
+ testID, memCheck[i].address, testValue, memCheck[i].value);
+ success = 0;
}
-
- if(reg10 == a+b && reg11 == a+30 && pass) {
- passed = 1;
- } else {
- passed = 0;
+ }
+
+ // Check the state of the regs is as expected afterward
+ for(unsigned i = 0; i < unsigned(regCheck.size()); i++){
+ uint32_t testValue = 0;
+ if (regCheck[i].index < 32){
+ mips_cpu_get_register(state, unsigned(regCheck[i].index), &testValue);
+ if (testValue != regCheck[i].value){
+ fprintf(stderr, "[Test %d] Reg[%d] is 0x%X - Expected 0x%X\n",
+ testID, regCheck[i].index, testValue, regCheck[i].value);
+ success = 0;
+ }
+ } else if (regCheck[i].index == 255){
+ mips_cpu_get_pc(state, &testValue);
+ if (testValue != regCheck[i].value){
+ fprintf(stderr, "[Test %d] PC is 0x%X - Expected 0x%X\n",
+ testID, testValue, regCheck[i].value);
+ success = 0;
+ }
}
-
- return passed;
-}
-int test_jump(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode) {
- int passed = 0;
- uint32_t inst, reg10, reg13, reg16, reg31;
+ }
- mips_cpu_reset(cpu);
+ if (expectedError != lastError){
+ fprintf(stderr, "[Test %d] Returned error 0x%X - Expected error 0x%X\n",
+ testID, lastError, expectedError);
+ success = 0;
+ }
- if(opcode == 2 || opcode == 3) {
- inst = change_endianness(gen_instruction(opcode, 0x20));
- } else if(opcode == 8 || opcode == 9) {
- inst = change_endianness(gen_instruction(25, 0, 31, 0, opcode));
- }
+ if (success == 0){
+ // Test has failed
+ fprintf(stderr, "[Test %d] FAILED\n", testID);
+ fprintf(stderr, "[Test %d] '%s' - %s\n", testID, testName, testDescription);
+ fprintf(stderr, "-------------------------------------------\n");
+ }
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
-
- inst = change_endianness(gen_instruction(8, 9, 10, 0, ADDU));
- mips_mem_write(ram, 4, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(11, 12, 13, 0, ADDU));
- mips_mem_write(ram, 8, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(14, 15, 16, 0, ADDU));
- mips_mem_write(ram, 0x20<<2, 4, (uint8_t*)&inst);
-
- mips_cpu_set_register(cpu, 8, 8);
- mips_cpu_set_register(cpu, 9, 9);
- mips_cpu_set_register(cpu, 10, 10);
- mips_cpu_set_register(cpu, 11, 11);
- mips_cpu_set_register(cpu, 12, 12);
- mips_cpu_set_register(cpu, 13, 13);
- mips_cpu_set_register(cpu, 14, 14);
- mips_cpu_set_register(cpu, 15, 15);
- mips_cpu_set_register(cpu, 16, 16);
- mips_cpu_set_register(cpu, 25, 0x20<<2);
-
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 10, &reg10);
- mips_cpu_get_register(cpu, 13, &reg13);
- mips_cpu_get_register(cpu, 16, &reg16);
- mips_cpu_get_register(cpu, 31, &reg31);
-
- if(reg10 == 9+8 && reg13 == 13 && reg16 == 14+15) {
- passed = 1;
- }
-
- if((opcode == 3 || opcode == 9) && reg31 != 8) {
- passed = 0;
- }
+ mips_test_end_test(testID, success, testDescription);
- return passed;
-}
-
-int test_load(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t word) {
- int passed = 0;
- uint16_t half_word;
- uint8_t byte;
- uint32_t res;
-
- half_word = (uint16_t)word;
- byte = (uint8_t)word;
-
- mips_cpu_reset(cpu);
-
- uint32_t inst = change_endianness(gen_instruction(opcode, 8, 9, 4));
-
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
-
- if(opcode == LB || opcode == LBU) {
- mips_mem_write(ram, 0x30, 1, &byte);
- } else if(opcode == LH || opcode == LHU) {
- uint16_t tmp = (half_word<<8) | (half_word>>8);
- mips_mem_write(ram, 0x30, 2, (uint8_t*)&tmp);
- } else {
- uint32_t tmp = change_endianness(word);
- mips_mem_write(ram, 0x30, 4, (uint8_t*)&tmp);
- }
+ // Reset the state of the CPU after each test to ensure independance
+ mips_cpu_reset(state);
- mips_cpu_set_register(cpu, 8, 0x2c);
- if(opcode == LWR) {
- mips_cpu_set_register(cpu, 8, 0x2f);
- }
- mips_cpu_set_register(cpu, 9, 0xbabacdcd);
-
- mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 9, &res);
-
- if((res == (uint32_t)(int8_t)byte && opcode == LB) || (res == (uint32_t)byte && opcode == LBU) || (res == (uint32_t)(int16_t)half_word && opcode == LH) || (res == (uint32_t)half_word && opcode == LHU) || (res == word && opcode == LW) || (res == 4<<16 && opcode == LUI) || (res == ((word&0xffff)|(0xbaba0000)) && (opcode == LWR)) || (res == ((word&0xffff0000)|(0xcdcd)))) {
- passed = 1;
- }
-
- return passed;
+ return lastError;
}
-int test_mult_div(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t num1, uint32_t num2) {
- int passed = 0;
- uint64_t result;
- uint32_t hi, lo;
-
- mips_cpu_reset(cpu);
-
- uint32_t inst = change_endianness(gen_instruction(8, 9, 0, 0, opcode));
- mips_mem_write(ram, 0, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(0, 0, 10, 0, MFHI));
- mips_mem_write(ram, 4, 4, (uint8_t*)&inst);
- inst = change_endianness(gen_instruction(0, 0, 11, 0, MFLO));
- mips_mem_write(ram, 8, 4, (uint8_t*)&inst);
-
- mips_cpu_set_register(cpu, 8, num1);
- mips_cpu_set_register(cpu, 9, num2);
- mips_cpu_set_register(cpu, 10, 0xabcde);
- mips_cpu_set_register(cpu, 11, 0xf193b);
-
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
- mips_cpu_step(cpu);
-
- mips_cpu_get_register(cpu, 10, &hi);
- mips_cpu_get_register(cpu, 11, &lo);
-
- result = (((uint64_t)hi)<<32) | ((uint64_t)lo);
+void writeMem(mips_mem_h mem, uint32_t address, uint32_t value){
+ byte_swap_test(value);
+ mips_mem_write(mem, address, 4, (uint8_t*)&value);
+}
- if((opcode == MULT && result == (uint64_t)((int64_t)(int32_t)num1*(int64_t)(int32_t)num2)) || (opcode == MULTU && result == (uint64_t)((uint32_t)num1)*(uint32_t)num2) || (opcode == DIV && lo == (uint32_t)((int32_t)num1/(int32_t)num2) && hi == (uint32_t)((int32_t)num1%(int32_t)num2)) || (opcode == DIVU && lo == num1/num2 && hi == num1%num2)) {
- passed = 1;
- }
+void writeReg(mips_cpu_h state, uint8_t index, uint32_t value){
+ if (index < 32){
+ mips_cpu_set_register(state, index, value);
+ } else if (index == 255){
+ mips_cpu_set_pc(state, value);
+ }
+}
- return passed;
+void byte_swap_test(uint32_t &value){
+ value =
+ (value<<24) |
+ ((value>>8)&0x0000FF00) |
+ ((value<<8)&0x00FF0000) |
+ (value>>24);
}
diff --git a/src/ymh15/test_mips.h b/src/ymh15/test_mips.h
new file mode 100644
index 0000000..adf4b35
--- /dev/null
+++ b/src/ymh15/test_mips.h
@@ -0,0 +1,74 @@
+#include "mips_instruction_test.h"
+
+#include <vector>
+
+using namespace std;
+
+struct memory_state{
+ uint32_t address;
+ uint32_t value;
+
+ memory_state(uint32_t addressIn, uint32_t valueIn):
+ address(addressIn),
+ value(valueIn){}
+};
+
+struct register_state{
+ uint8_t index; // 255 for checking program counter
+ uint32_t value;
+
+ register_state(uint8_t indexIn, uint32_t valueIn):
+ index(indexIn),
+ value(valueIn){}
+};
+
+struct test{
+ const char* testName;
+ const char* testDescription;
+ unsigned numInstructions;
+ vector<memory_state> memCheck;
+ vector<register_state> regCheck;
+ int success;
+ mips_error expectedError;
+
+ // Constructor for test
+ test(
+ const char* testNameIn,
+ const char* testDescriptionIn,
+ unsigned numInstructionsIn):
+ testName(testNameIn),
+ testDescription(testDescriptionIn),
+ numInstructions(numInstructionsIn),
+ // Assume the test passes
+ success(1),
+ expectedError(mips_Success){}
+
+ // Constructor for test where the expected error isn't mips_Success
+ test(
+ const char* testNameIn,
+ const char* testDescriptionIn,
+ unsigned numInstructionsIn,
+ mips_error expectedErrorIn):
+ testName(testNameIn),
+ testDescription(testDescriptionIn),
+ numInstructions(numInstructionsIn),
+ // Assume the test passes
+ success(1),
+ expectedError(expectedErrorIn){}
+
+ mips_error perform_test(mips_cpu_h state, mips_mem_h mem);
+
+ void checkMem(uint32_t address, uint32_t value){
+ memCheck.push_back(memory_state(address, value));
+ }
+
+ void checkReg(uint8_t index, uint32_t value){
+ regCheck.push_back(register_state(index, value));
+ }
+};
+
+uint32_t get_pc(mips_cpu_h state);
+void writeMem(mips_mem_h mem, uint32_t address, uint32_t value);
+void writeReg(mips_cpu_h state, uint8_t index, uint32_t value);
+
+void byte_swap_test(uint32_t &value);
diff --git a/src/ymh15/test_mips.o b/src/ymh15/test_mips.o
index 32a3fd1..2e4b3df 100644
--- a/src/ymh15/test_mips.o
+++ b/src/ymh15/test_mips.o
Binary files differ
diff --git a/src/ymh15/test_mips_ymh15.hpp b/src/ymh15/test_mips_ymh15.hpp
index 054068b..ca9f9fe 100644
--- a/src/ymh15/test_mips_ymh15.hpp
+++ b/src/ymh15/test_mips_ymh15.hpp
@@ -6,6 +6,7 @@
#include <ctime>
// Functions
+#define NOOP 0x0
#define SLL 0x0
#define SRL 0x2
#define SRA 0x3