From 72b51899b0d71a43af81c89a5eeeedb08c2b6d0b Mon Sep 17 00:00:00 2001 From: zedarider Date: Thu, 27 Oct 2016 18:53:16 +0100 Subject: Finished cpu completely except some corner cases --- src/shared/mips_mem_ram.o | Bin 10000 -> 10016 bytes src/ymh15/.#mips_cpu.cpp | 1 - src/ymh15/2test_mips.cpp | 482 +++++++++++ src/ymh15/mips_cpu.cpp | 270 +++--- src/ymh15/mips_cpu.o | Bin 25904 -> 27856 bytes src/ymh15/mips_cpu_ymh15.hpp | 2 + src/ymh15/mips_instruction_test.h | 74 ++ src/ymh15/test_mips | Bin 341840 -> 448336 bytes src/ymh15/test_mips.cpp | 1639 ++++++++++++++++++++++++++----------- src/ymh15/test_mips.h | 74 ++ src/ymh15/test_mips.o | Bin 46200 -> 216592 bytes src/ymh15/test_mips_ymh15.hpp | 1 + 12 files changed, 1971 insertions(+), 572 deletions(-) delete mode 120000 src/ymh15/.#mips_cpu.cpp create mode 100644 src/ymh15/2test_mips.cpp create mode 100644 src/ymh15/mips_instruction_test.h create mode 100644 src/ymh15/test_mips.h diff --git a/src/shared/mips_mem_ram.o b/src/shared/mips_mem_ram.o index 718d8dc..b954d72 100644 Binary files a/src/shared/mips_mem_ram.o and b/src/shared/mips_mem_ram.o 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 + +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, ®10); + mips_cpu_get_register(cpu, 11, ®11); + + if(l == 1) { + mips_cpu_get_register(cpu, 31, ®31); + 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, ®10); + mips_cpu_get_register(cpu, 13, ®13); + mips_cpu_get_register(cpu, 16, ®16); + mips_cpu_get_register(cpu, 31, ®31); + + 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], ®_s); - if(imm == 0) { + if(!imm) { mips_cpu_get_register(state, var[REG_T], ®_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], ®_s); + + if(!imm) { + mips_cpu_get_register(state, var[REG_T], ®_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 Binary files a/src/ymh15/mips_cpu.o and b/src/ymh15/mips_cpu.o 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 Binary files a/src/ymh15/test_mips and b/src/ymh15/test_mips 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 - -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("", "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("", "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("", "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("", "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("", + "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("", "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("", "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 + 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 + writeMem(testMem, 0x30, 0x2610fffe); // addiu s0,s0,-2 + writeMem(testMem, 0x34, 0x2e030002); // sltiu v1,s0,2 + writeMem(testMem, 0x38, 0x1060fffb); // beqz v1,28 + 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 + 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, ®10); - mips_cpu_get_register(cpu, 11, ®11); - - if(l == 1) { - mips_cpu_get_register(cpu, 31, ®31); - 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, ®10); - mips_cpu_get_register(cpu, 13, ®13); - mips_cpu_get_register(cpu, 16, ®16); - mips_cpu_get_register(cpu, 31, ®31); - - 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 + +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 memCheck; + vector 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 Binary files a/src/ymh15/test_mips.o and b/src/ymh15/test_mips.o 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 // Functions +#define NOOP 0x0 #define SLL 0x0 #define SRL 0x2 #define SRA 0x3 -- cgit