diff options
-rwxr-xr-x | makefile | 2 | ||||
-rw-r--r-- | src/shared/mips_mem_ram.o | bin | 0 -> 10000 bytes | |||
-rw-r--r-- | src/shared/mips_test_framework.o | bin | 0 -> 337728 bytes | |||
l--------- | src/ymh15/.#mips_cpu.cpp | 1 | ||||
-rw-r--r-- | src/ymh15/mips_cpu.cpp | 566 | ||||
-rw-r--r-- | src/ymh15/mips_cpu.o | bin | 0 -> 25904 bytes | |||
-rw-r--r-- | src/ymh15/mips_cpu_ymh15.hpp | 93 | ||||
-rw-r--r-- | src/ymh15/test.s | 15 | ||||
-rwxr-xr-x | src/ymh15/test_mips | bin | 0 -> 341840 bytes | |||
-rw-r--r-- | src/ymh15/test_mips.cpp | 482 | ||||
-rw-r--r-- | src/ymh15/test_mips.o | bin | 0 -> 46200 bytes | |||
-rw-r--r-- | src/ymh15/test_mips_ymh15.hpp | 82 |
12 files changed, 1240 insertions, 1 deletions
@@ -1,6 +1,6 @@ # Your login. For example, mine is dt10. Yours # won't be eie2ugs... -LOGIN ?= eie2ugs +LOGIN ?= ymh15 # Turn on all warnings CPPFLAGS += -W -Wall diff --git a/src/shared/mips_mem_ram.o b/src/shared/mips_mem_ram.o Binary files differnew file mode 100644 index 0000000..718d8dc --- /dev/null +++ b/src/shared/mips_mem_ram.o diff --git a/src/shared/mips_test_framework.o b/src/shared/mips_test_framework.o Binary files differnew file mode 100644 index 0000000..9790ca3 --- /dev/null +++ b/src/shared/mips_test_framework.o diff --git a/src/ymh15/.#mips_cpu.cpp b/src/ymh15/.#mips_cpu.cpp new file mode 120000 index 0000000..5a5142f --- /dev/null +++ b/src/ymh15/.#mips_cpu.cpp @@ -0,0 +1 @@ +yannherklotz@Yann-Arch.800:1477569971
\ No newline at end of file diff --git a/src/ymh15/mips_cpu.cpp b/src/ymh15/mips_cpu.cpp new file mode 100644 index 0000000..34107de --- /dev/null +++ b/src/ymh15/mips_cpu.cpp @@ -0,0 +1,566 @@ +#include "../../include/mips.h" +#include "mips_cpu_ymh15.hpp" + +struct mips_cpu_impl { + mips_mem_h mem; + uint32_t regs[32]; + // lo and hi registers + uint32_t lo, hi; + // program counter + uint32_t pc; + // next pc used for branches and set the pc correctly + uint32_t next_pc; + // delay slot that makes branches work as expected + uint32_t delay_slot; + + // sets the debug level so that you can print more information + int debug_level; + FILE *debug_type; +}; + +mips_cpu_h mips_cpu_create(mips_mem_h mem) { + // creates new instance of a cpu explicitly + mips_cpu_impl* state = new mips_cpu_impl; + + // reset all the variables + state->mem = mem; + state->pc = 0; + state->next_pc = state->pc + 4; + state->delay_slot = 0; + state->lo = 0; + state->hi = 0; + + state->debug_level = 0; + state->debug_type = NULL; + + // sets all registers to 0 + for(int i = 0; i < 32; ++i) { + state->regs[i] = 0; + } + + return state; +} + +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; + state->delay_slot = 0; + state->hi = 0; + state->lo = 0; + + // and registers + for(int i = 0; i < 32; ++i) { + state->regs[i] = 0; + } + + return mips_Success; +} + +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]; + + return mips_Success; +} + +mips_error mips_cpu_set_register(mips_cpu_h state, unsigned index, + uint32_t value) { + if(!state || index > 31 || index == 0) { + return mips_ErrorInvalidArgument; + } + + // set reg state + state->regs[index] = value; + + return mips_Success; +} + + +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; + + return mips_Success; +} + +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; + + return mips_Success; +} + +// 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); + + // change the instruction back from big endian as it was read as little endian + inst = (inst<<24) | ((inst>>8)&0xff00) | ((inst<<8)&0xff0000) | (inst>>24); + + // it then executes the instruction by decoding it first and returns + // the state of the instruction + mips_error mips_err = exec_instruction(state, inst); + + + if(state->debug_level > 0) { + fprintf(state->debug_type, "pc: %d\tpc_next: %d\tinst: %#10x\tdelay_slot: %d\n", state->pc, state->next_pc, inst, state->delay_slot); + } + + // if the debug level is 2 or higher it will print the register state + if(state->debug_level > 1) { + fprintf(state->debug_type, "\nCPU register state:\n"); + for(unsigned i = 0; i < 32; ++i) { + fprintf(state->debug_type, "R%d:\t%#10x\n", i, + state->regs[i]); + } + fprintf(state->debug_type, "\n\n"); + } + + if(state->debug_level > 2) { + char c = getchar(); + } + + // it then updates the pc to next_pc which could have been changed + // by a branch, it only does this if it is not in a delay slot + if(!state->delay_slot) { + state->pc = state->next_pc; + state->next_pc += 4; + } else { + state->pc += 4; + --state->delay_slot; + } + + // returns the operation error such as arithmetic overflow + return mips_err; +} + +mips_error mips_cpu_set_debug_level(mips_cpu_h state, unsigned level, + FILE *dest) { + if(!state) { + return mips_ErrorInvalidArgument; + } + + // just sets the cpu values for the debug level + state->debug_level = level; + state->debug_type = dest; + + return mips_Success; +} + +void mips_cpu_free(mips_cpu_h state) { + // deletes the state pointer of mips_cpu_impl* type + if(state) { + delete state; + } +} + +// The following functions are not present in the api as they are +// functions defined in a private header file + +mips_error exec_instruction(mips_cpu_h state, uint32_t inst) { + // creates var that holds all the information of the instruction + uint32_t var[8]; + + // prints pc and instruction every clock cycle + + for(int i = 0; i < 8; ++i) { + var[i] = 0; + } + + // decodes the instruction + + // if first 6 bits are 0 then it is a R instruction + if(((inst >> 26)&0x3f) == 0) { + // R Type: set all necessary variables + var[REG_S] = inst >> 21; + var[REG_T] = (inst >> 16)&0x1f; + var[REG_D] = (inst >> 11)&0x1f; + var[SHIFT] = (inst >> 6)&0x1f; + var[FUNC] = inst&0x3f; + + // 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 + var[OPCODE] = inst >> 26; // it has to be J type + var[MEM] = inst&0x3ffffff; + return exec_J(state, var); + } else { // otherwise it is an I type + 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); + } + + return exec_I(state, var); + } +} + +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) { + // 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); + + } else if((var[FUNC]&0xf0) == 0x20 && (var[FUNC]&0xf) < 7) { + // else if the number is between 0x23 and 0x27 which means it + // is a bitwise operation + return bitwise(state, var, 0); + + } else if(var[FUNC] == 8) { + // jr + return jump(state, var, 0); + + } else if(var[FUNC] == 9) { + // jalr + return jump(state, var, 1); + + } else if(var[FUNC] >= 0x10 && var[FUNC] <= 0x13) { + // mfhi mthi mflo mtlo + return move(state, var); + + } else if(var[FUNC] >= 0x18 && var[FUNC] <= 0x1b) { + // mult multu div divu + return mult_div(state, var); + + } else { + // otherwise return that it was an invalid instruction + return mips_ExceptionInvalidInstruction; + } +} + +mips_error exec_J(mips_cpu_h state, uint32_t var[8]) { + switch(var[OPCODE]) { + case 0: + case 2: // j + return jump(state, var, 0); + case 3: // jal + return jump(state, var, 1); + default: + return mips_ExceptionInvalidInstruction; + } +} + +mips_error exec_I(mips_cpu_h state, uint32_t var[8]) { + switch(var[OPCODE]) { + case 0x1: // bgez, bgezal, bltz, bltzal + return branch(state, var); + case 0x4: // beq + return branch(state, var); + case 0x5: // bne + return branch(state, var); + case 0x6: // blez + return branch(state, var); + case 0x7: // bgtz + return branch(state, var); + case 0x8: // addi + return add_sub(state, var, 1, 1); + case 0x9: // addiu + return add_sub(state, var, 1, 2); + case 0xc: // andi + return bitwise(state, var, 1); + case 0xd: // ori + return bitwise(state, var, 1); + case 0xe: // xori + return bitwise(state, var, 1); + case 0xf: // lui + return load(state, var); + case 0x20: // lb + return load(state, var); + case 0x21: // lh + return load(state, var); + case 0x22: // lwl + return load(state, var); + case 0x23: // lw + return load(state, var); + case 0x24: // lbu + return load(state, var); + case 0x25: // lhu + return load(state, var); + case 0x26: // lwr + return load(state, var); + case 0x28: // sb + return store(state, var); + case 0x29: // sh + return store(state, var); + case 0x2b: // sw + return store(state, var); + default: + return mips_ExceptionInvalidInstruction; + } +} + +mips_error add_sub(mips_cpu_h state, uint32_t var[8], int32_t add_sub, + int32_t imm) { + // sets initial values of the registers as local variables + int32_t reg_s, reg_t, reg_d; + + // set the locals to the correct value from the register + mips_cpu_get_register(state, var[REG_S], (uint32_t*)®_s); + if(imm > 0) { + reg_t = (int32_t)var[IMM]; + } else { + mips_cpu_get_register(state, var[REG_T], (uint32_t*)®_t); + } + + // perform the addition or subtraction + reg_d = reg_s + add_sub*reg_t; + + // check for overflow conditions and if it is an unsigned operation + if((var[FUNC]&0x1) == 1 || imm > 1 || !((reg_s > 0 && add_sub*reg_t > 0 && reg_d < 0) || (reg_s < 0 && add_sub*reg_t < 0 && reg_d > 0))) { + + // sets the destination register to the right answer + mips_cpu_set_register(state, var[REG_D], (uint32_t)reg_d); + return mips_Success; + } + + return mips_ExceptionArithmeticOverflow; +} + +mips_error bitwise(mips_cpu_h state, uint32_t var[8], unsigned imm) { + // selects the right bitwise operation to perform then sets the register to the right value + uint32_t reg_s, reg_t, reg_d; + + mips_cpu_get_register(state, var[REG_S], ®_s); + if(imm == 0) { + mips_cpu_get_register(state, var[REG_T], ®_t); + } else { + reg_t = var[IMM]; + } + + // 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; + + // set register to the answer + mips_cpu_set_register(state, var[REG_D], reg_d); + + return mips_Success; +} + +mips_error branch(mips_cpu_h state, uint32_t var[8]) { + if(var[OPCODE] == 1 && (var[REG_D] == 0x11 || var[REG_D] == 0x10)) { + 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 + + state->next_pc += (var[IMM]<<2); + state->delay_slot += 1; + } + + return mips_Success; +} + +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) { + jump_loc = state->regs[var[REG_S]]; + reg_d = var[REG_D]; + } else { + jump_loc = var[MEM]<<2; + reg_d = 31; + } + + 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; + + addr = state->regs[var[REG_S]] + var[IMM]; + + if(var[OPCODE] == 0x24 || var[OPCODE] == 0x20) { // lb lbu + mips_mem_read(state->mem, addr, 1, &mem_byte); + } else if(var[OPCODE] == 0x21 || var[OPCODE] == 0x25) { // lh lhu + if((addr&0b1) == 1) { + return mips_ExceptionInvalidAddress; + } + 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 + if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) { + return mips_ExceptionInvalidAddress; + } + 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; + } + 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: + state->regs[var[REG_D]] = var[IMM]<<16; + return mips_Success; + case 0x20: + state->regs[var[REG_D]] = (uint32_t)(int8_t)mem_byte; + return mips_Success; + case 0x21: + 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); + return mips_Success; + case 0x23: + state->regs[var[REG_D]] = mem_word; + return mips_Success; + case 0x24: + state->regs[var[REG_D]] = (uint32_t)mem_byte; + return mips_Success; + case 0x25: + 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); + return mips_Success; + default: + return mips_ExceptionInvalidInstruction; + } +} + +mips_error store(mips_cpu_h state, uint32_t var[8]) { + uint32_t addr; + uint32_t word; + uint16_t half_word; + uint8_t byte; + + addr = state->regs[var[REG_S]] + var[IMM]; + word = state->regs[var[REG_D]]; + half_word = (uint16_t)state->regs[var[REG_D]]; + byte = (uint8_t)state->regs[var[REG_D]]; + + if(var[OPCODE] == 0x28) { + mips_mem_write(state->mem, addr, 1, &byte); + } else if(var[OPCODE] == 0x29) { + if((addr&0b1) == 1) { + return mips_ExceptionInvalidAddress; + } + uint16_t tmp = half_word << 8 | half_word >> 8; + mips_mem_write(state->mem, addr, 2, (uint8_t*)&tmp); + } else if(var[OPCODE] == 0x2b) { + if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) { + return mips_ExceptionInvalidAddress; + } + uint32_t tmp = word<<24 | ((word>>8)&0xff00) | ((word<<8)&0xff0000) | word>>24; + mips_mem_write(state->mem, addr, 4, (uint8_t*)&tmp); + } else { + return mips_ExceptionInvalidInstruction; + } + return mips_Success; +} + +mips_error move(mips_cpu_h state, uint32_t var[8]) { + switch(var[FUNC]) { + case 0x10: + 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: + return mips_cpu_set_register(state, var[REG_D], state->lo); + case 0x13: + return mips_cpu_get_register(state, var[REG_D], &state->lo); + default: + return mips_ExceptionInvalidInstruction; + } + return mips_Success; +} + +mips_error mult_div(mips_cpu_h state, uint32_t var[8]) { + uint64_t unsigned_result, signed_result; + switch(var[FUNC]) { + case 0x18: // 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 + 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 + if(var[REG_T] == 0) { + state->lo = 0; + state->hi = 0; + return mips_Success; + } + + state->lo = ((int32_t)state->regs[var[REG_S]])/((int32_t)state->regs[var[REG_T]]); + state->hi = ((int32_t)state->regs[var[REG_S]])%((int32_t)state->regs[var[REG_T]]); + return mips_Success; + + case 0x1b: // divu + if(var[REG_T] == 0) { + state->lo = 0; + state->hi = 0; + return mips_Success; + } + + state->lo = (state->regs[var[REG_S]])/(state->regs[var[REG_T]]); + state->hi = (state->regs[var[REG_S]])%(state->regs[var[REG_T]]); + return mips_Success; + + default: + return mips_ExceptionInvalidInstruction; + } +} + +mips_error shift(mips_cpu_h state, uint32_t var[8]) { + if(var[FUNC] == 0 && var[OPCODE] == 0) { + state->regs[var[REG_D]] = state->regs[var[REG_T]] << var[SHIFT]; + } else if(var[FUNC] == 4) { + state->regs[var[REG_D]] = state->regs[var[REG_T]] << state->regs[var[REG_S]]; + } else if(var[FUNC] == 2/*TODO*/); + return mips_Success; +} diff --git a/src/ymh15/mips_cpu.o b/src/ymh15/mips_cpu.o Binary files differnew file mode 100644 index 0000000..4092c0a --- /dev/null +++ b/src/ymh15/mips_cpu.o diff --git a/src/ymh15/mips_cpu_ymh15.hpp b/src/ymh15/mips_cpu_ymh15.hpp new file mode 100644 index 0000000..085c59c --- /dev/null +++ b/src/ymh15/mips_cpu_ymh15.hpp @@ -0,0 +1,93 @@ +#ifndef MIPS_CPU_YMH15_H +#define MIPS_CPU_YMH15_H + +#include <cstdio> + +#include "../../include/mips.h" + +// defines the location of the things in the array var +#define OPCODE 0 +#define REG_S 1 +#define REG_T 2 +#define REG_D 3 +#define SHIFT 4 +#define FUNC 5 +#define IMM 6 +#define MEM 7 + +// Functions +#define SLL 0x0 +#define SRL 0x2 +#define SRA 0x3 +#define SLLV 0x4 +#define SRLV 0x6 +#define SRAV 0x7 +#define JR 0x8 +#define JALR 0x9 +#define MFHI 0x10 +#define MTHI 0x11 +#define MFLO 0x12 +#define MTLO 0x13 +#define MULT 0x18 +#define MULTU 0x19 +#define DIV 0x1a +#define DIVU 0x1b +#define ADD 0x20 +#define ADDU 0x21 +#define SUB 0x22 +#define SUBU 0x23 +#define AND 0x24 +#define OR 0x25 +#define XOR 0x26 +#define SLT 0x2a +#define SLTU 0x2b + +// OPcodes +#define BGEZ 0x1 +#define BGEZAL 0x1 +#define BLTZ 0x1 +#define BLTZAL 0x1 +#define J 0x2 +#define JAL 0x3 +#define BEQ 0x4 +#define BNE 0x5 +#define BLEZ 0x6 +#define BGTZ 0x7 +#define ADDI 0x8 +#define ADDIU 0x9 +#define SLTI 0xa +#define SLTIU 0xb +#define ANDI 0xc +#define ORI 0xd +#define XORI 0xe +#define LUI 0xf +#define LB 0x20 +#define LH 0x21 +#define LWL 0x22 +#define LW 0x23 +#define LBU 0x24 +#define LHU 0x25 +#define LWR 0x26 +#define SB 0x28 +#define SH 0x29 +#define SW 0x2b + +// executes an instruction by first decoding it and sending the right +// variables to the different functions to be correctly interpreted +mips_error exec_instruction(mips_cpu_h state, uint32_t inst); +mips_error exec_R(mips_cpu_h state, uint32_t var[8]); +mips_error exec_J(mips_cpu_h state, uint32_t var[8]); +mips_error exec_I(mips_cpu_h state, uint32_t var[8]); +// performs addition and subtraction +mips_error add_sub(mips_cpu_h state, uint32_t var[8], int32_t add_sub,int32_t imm); +// performs bitwise operations +mips_error bitwise(mips_cpu_h state, uint32_t var[8], unsigned imm); +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); +mips_error load(mips_cpu_h state, uint32_t var[8]); +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]); + +#endif // MIPS_CPU_YMH15_H diff --git a/src/ymh15/test.s b/src/ymh15/test.s new file mode 100644 index 0000000..80f645a --- /dev/null +++ b/src/ymh15/test.s @@ -0,0 +1,15 @@ + .text + .globl main + +main: + li $8, 10 + li $9, 0 + li $10, 17 +loop: + beq $9, $8, end + add $10, $10, $9 + addi $9, $9, 1 + j loop +end: + ori $2, $0, 10 + syscall diff --git a/src/ymh15/test_mips b/src/ymh15/test_mips Binary files differnew file mode 100755 index 0000000..3c01c18 --- /dev/null +++ b/src/ymh15/test_mips diff --git a/src/ymh15/test_mips.cpp b/src/ymh15/test_mips.cpp new file mode 100644 index 0000000..75afaa8 --- /dev/null +++ b/src/ymh15/test_mips.cpp @@ -0,0 +1,482 @@ +#include "../../include/mips.h" +#include "test_mips_ymh15.hpp" + +#include <iostream> + +using namespace std; + +int main(int argc, char** argv) { + mips_mem_h ram = mips_mem_create_ram(4096); + mips_cpu_h cpu = mips_cpu_create(ram); + + srand(time(NULL)); + + if(argc == 2) { + mips_cpu_set_debug_level(cpu, argv[1][0]-'0', stdout); + } else { + mips_cpu_set_debug_level(cpu, 0, NULL); + } + + mips_test_begin_suite(); + + int testId = mips_test_begin_test("ADD"); + mips_test_end_test(testId, test_add(ram, cpu, ADD, 0x3fffffff, 0, 10), "Testing the adder without overflow"); + + testId = mips_test_begin_test("ADD"); + mips_test_end_test(testId, !test_add(ram, cpu, ADD, 0x7fffffff, 1, 1), "Testing the adder with overflow"); + + testId = mips_test_begin_test("ADDU"); + mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x3fffffff, 0, 10), "testing without overflow"); + + testId = mips_test_begin_test("ADDU"); + mips_test_end_test(testId, test_add(ram, cpu, ADDU, 0x7fffffff, 1, 1), "Testing the adder with overflow"); + + testId = mips_test_begin_test("SUB"); + mips_test_end_test(testId, test_add(ram, cpu, SUB, 0x3fffffff, 0, 10), "Testing the adder without overflow"); + + testId = mips_test_begin_test("SUB"); + mips_test_end_test(testId, !test_add(ram, cpu, SUB, 0x7fffffff, 1, 1), "Testing the adder with overflow"); + + testId = mips_test_begin_test("SUBU"); + mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x3fffffff, 0, 10), "Testing the adder without overflow"); + + testId = mips_test_begin_test("SUBU"); + mips_test_end_test(testId, test_add(ram, cpu, SUBU, 0x7fffffff, 1, 1), "Testing the adder with overflow"); + + testId = mips_test_begin_test("AND"); + mips_test_end_test(testId, test_bitwise(ram, cpu, AND), "Testing bitwise and"); + + testId = mips_test_begin_test("OR"); + mips_test_end_test(testId, test_bitwise(ram, cpu, OR), "Testing bitwise or"); + + testId = mips_test_begin_test("XOR"); + mips_test_end_test(testId, test_bitwise(ram, cpu, XOR), "Testing bitwise xor"); + + testId = mips_test_begin_test("ADDI"); + mips_test_end_test(testId, test_I(ram, cpu, ADDI, 20, 10), "Testing addi"); + + testId = mips_test_begin_test("ADDIU"); + mips_test_end_test(testId, test_I(ram, cpu, ADDIU, 20, 10), "Testing addiu"); + + testId = mips_test_begin_test("ANDI"); + mips_test_end_test(testId, test_I(ram, cpu, ANDI, 20, 10), "Testing addi"); + + testId = mips_test_begin_test("ORI"); + mips_test_end_test(testId, test_I(ram, cpu, ORI, 20, 10), "Testing addi"); + + testId = mips_test_begin_test("XORI"); + mips_test_end_test(testId, test_I(ram, cpu, XORI, 20, 10), "Testing addi"); + + testId = mips_test_begin_test("BEQ"); + mips_test_end_test(testId, test_branch(ram, cpu, 4, 4, 0, 9, 4), "Testing BEQ"); + + testId = mips_test_begin_test("BNE"); + mips_test_end_test(testId, test_branch(ram, cpu, 5, 4, 0, 9, 10), "Testing BNE"); + + testId = mips_test_begin_test("BGEZ"); + mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 0, 1, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("BLEZ"); + mips_test_end_test(testId, test_branch(ram, cpu, 6, -1, 0, 0, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("BGTZ"); + mips_test_end_test(testId, test_branch(ram, cpu, 7, 4, 0, 0, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("BGEZAL"); + mips_test_end_test(testId, test_branch(ram, cpu, 1, 4, 1, 17, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("BLTZAL"); + mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 1, 16, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("BLTZ"); + mips_test_end_test(testId, test_branch(ram, cpu, 1, -1, 0, 16, 20), "Testing BGEZ"); + + testId = mips_test_begin_test("J"); + mips_test_end_test(testId, test_jump(ram, cpu, J), "Testing J"); + + testId = mips_test_begin_test("JAL"); + mips_test_end_test(testId, test_jump(ram, cpu, JAL), "Testing JAL"); + + testId = mips_test_begin_test("JALR"); + mips_test_end_test(testId, test_jump(ram, cpu, JALR), "Testing JALR"); + + testId = mips_test_begin_test("JR"); + mips_test_end_test(testId, test_jump(ram, cpu, JR), "Testing JR"); + + testId = mips_test_begin_test("LB"); + mips_test_end_test(testId, test_load(ram, cpu, LB, 0xf7), "Testing LB"); + + testId = mips_test_begin_test("LBU"); + mips_test_end_test(testId, test_load(ram, cpu, LBU, 0xf7), "Testing LBU"); + + testId = mips_test_begin_test("LH"); + mips_test_end_test(testId, test_load(ram, cpu, LH, 0xff7f), "Testing LH"); + + testId = mips_test_begin_test("LHU"); + mips_test_end_test(testId, test_load(ram, cpu, LHU, 0xff7f), "Testing LHU"); + + testId = mips_test_begin_test("LW"); + mips_test_end_test(testId, test_load(ram, cpu, LW, 0xffffff7f), "Testing LW"); + + testId = mips_test_begin_test("LUI"); + mips_test_end_test(testId, test_load(ram, cpu, LUI, 0xff7f), "Testing LUI"); + + testId = mips_test_begin_test("LWL"); + mips_test_end_test(testId, test_load(ram, cpu, LWL, 0xff6fff7f), "Testing LWL"); + + testId = mips_test_begin_test("LWR"); + mips_test_end_test(testId, test_load(ram, cpu, LWR, 0xff6fff7f), "Testing LWR"); + + testId = mips_test_begin_test("MULT"); + mips_test_end_test(testId, test_mult_div(ram, cpu, MULT, 5, -4), "Testing LWR"); + + testId = mips_test_begin_test("MULTU"); + mips_test_end_test(testId, test_mult_div(ram, cpu, MULTU, 5, -4), "Testing LWR"); + + testId = mips_test_begin_test("DIV"); + mips_test_end_test(testId, test_mult_div(ram, cpu, DIV, 5, -4), "Testing LWR"); + + testId = mips_test_begin_test("DIVU"); + mips_test_end_test(testId, test_mult_div(ram, cpu, DIVU, 5, -4), "Testing LWR"); + + mips_test_end_suite(); + return 0; +} + +// R Type +uint32_t gen_instruction(uint32_t src1, uint32_t src2, uint32_t dest, + uint32_t shift, uint32_t function) { + uint32_t inst = 0; + inst = inst | src1 << 21 | src2 << 16 | dest << 11 | shift << 6 | + function; + return inst; +} + +// I Type +uint32_t gen_instruction(uint32_t opcode, uint32_t src, uint32_t dest, + uint32_t Astart) { + uint32_t inst = 0; + inst = inst | opcode << 26 | src << 21 | dest << 16 | Astart; + return inst; +} + +// J Type +uint32_t gen_instruction(uint32_t opcode, uint32_t memory) { + uint32_t inst = 0; + inst = inst | opcode << 26 | memory; + return inst; +} + +uint32_t change_endianness(uint32_t inst) { + inst = (inst << 24 | ((inst << 8)&0xff0000) | + ((inst >> 8)&0xff00) |inst >> 24); + return inst; +} + +int test_add(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, uint32_t max, uint8_t value, unsigned i_t) { + + uint32_t inst, ans, a, b; + + for(unsigned i = 0; i < i_t; ++i) { + mips_error mips_err; + mips_cpu_reset(cpu); + inst = change_endianness(gen_instruction(9, 10, 8, 0, type)); + if(value) { + a = max; + if(type > 0x21) { + b = -max; + } else { + b = max; + } + } else { + a = rand() % max; + b = rand() % max; + } + + mips_mem_write(ram, 0, 4, (uint8_t*)&inst); + + mips_cpu_set_register(cpu, 9, a); + mips_cpu_set_register(cpu, 10, b); + + mips_err = mips_cpu_step(cpu); + + mips_cpu_get_register(cpu, 8, &ans); + + if(type < 0x22) { + //printf("%#10x + %#10x = %#10x\t%#10x\n", a, b, ans, mips_err); + if(mips_err == mips_ExceptionArithmeticOverflow || a+b!=ans) { + return 0; + } + } else { + //printf("%#10x - %#10x = %#10x\t%#10x\n", a, b, ans, mips_err); + if(mips_err == mips_ExceptionArithmeticOverflow || a-b!=ans) { + return 0; + } + } + } + + return 1; +} + +int test_bitwise(mips_mem_h ram, mips_cpu_h cpu, uint8_t op) { + uint32_t a, b, ans, inst; + int passed; + for(unsigned i = 0; i < 10; ++i) { + passed = 0; + mips_cpu_reset(cpu); + inst = change_endianness(gen_instruction(8, 9, 7, 0, op)); + + a = rand() % 0xffffffff; + b = rand() % 0xffffffff; + + mips_mem_write(ram, 0, 4, (uint8_t*)&inst); + + mips_cpu_set_register(cpu, 8, a); + mips_cpu_set_register(cpu, 9, b); + + mips_error mips_err = mips_cpu_step(cpu); + + mips_cpu_get_register(cpu, 7, &ans); + + if(op == AND) { + //printf("%#10x & %#10x = %#10x\t%#10x\n", a, b, ans, mips_err); + if((a & b) == ans) { + passed = 1; + } + } else if(op == OR) { + //printf("%#10x | %#10x = %#10x\t%#10x\n", a, b, ans, mips_err); + if((a | b) == ans) { + passed = 1; + } + } else { + //printf("%#10x ^ %#10x = %#10x\t%#10x\n", a, b, ans, mips_err); + if((a ^ b) == ans) { + passed = 1; + } + } + + + if(mips_err != mips_Success || !passed) { + return 0; + } + } + return 1; +} + +int test_I(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, + uint32_t num1, uint32_t num2) { + int passed = 0; + uint32_t result, inst; + + mips_cpu_reset(cpu); + inst = change_endianness(gen_instruction(type, 8, 7, num1)); + + mips_mem_write(ram, 0, 4, (uint8_t*)&inst); + mips_cpu_set_register(cpu, 8, num2); + + mips_cpu_step(cpu); + + mips_cpu_get_register(cpu, 7, &result); + + switch(type) { + case 8: + if(result == num1 + num2) { + passed = 1; + } + case 9: + if(result == num1 + num2) { + passed = 1; + } + case 12: + if(result == (num1 & num2)) { + passed = 1; + } + case 13: + if(result == (num1 | num2)) { + passed = 1; + } + case 14: + if(result == (num1 ^ num2)) { + passed = 1; + } + default:; + } + + return passed; +} + +int test_branch(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t a, uint8_t l, uint32_t opc2, uint32_t b) { + int passed = 0; + int pass = 0; + uint32_t reg10, reg11, reg31, pc_set; + pc_set = 32; + mips_cpu_reset(cpu); + mips_cpu_set_pc(cpu, pc_set); + + uint32_t inst = change_endianness(gen_instruction(opcode, 8, opc2, 3)); + mips_mem_write(ram, pc_set, 4, (uint8_t*)&inst); + inst = change_endianness(gen_instruction(8, 9, 10, 0, ADDU)); + mips_mem_write(ram, pc_set+4, 4, (uint8_t*)&inst); + inst = change_endianness(gen_instruction(8, 12, 11, 0, ADDU)); + mips_mem_write(ram, pc_set+16, 4, (uint8_t*)&inst); + inst = change_endianness(gen_instruction(8, 13, 10, 0, ADDU)); + mips_mem_write(ram, pc_set+8, 4, (uint8_t*)&inst); + + mips_cpu_set_register(cpu, 8, a); + mips_cpu_set_register(cpu, 9, b); + mips_cpu_set_register(cpu, 12, 30); + mips_cpu_set_register(cpu, 13, 100); + + mips_cpu_step(cpu); + mips_cpu_step(cpu); + mips_cpu_step(cpu); + + mips_cpu_get_register(cpu, 10, ®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/test_mips.o b/src/ymh15/test_mips.o Binary files differnew file mode 100644 index 0000000..32a3fd1 --- /dev/null +++ b/src/ymh15/test_mips.o diff --git a/src/ymh15/test_mips_ymh15.hpp b/src/ymh15/test_mips_ymh15.hpp new file mode 100644 index 0000000..054068b --- /dev/null +++ b/src/ymh15/test_mips_ymh15.hpp @@ -0,0 +1,82 @@ +#ifndef TEST_MIPS_YMH15_H +#define TEST_MIPS_YMH15_H + +#include "../../include/mips.h" +#include <cstdlib> +#include <ctime> + +// Functions +#define SLL 0x0 +#define SRL 0x2 +#define SRA 0x3 +#define SLLV 0x4 +#define SRLV 0x6 +#define SRAV 0x7 +#define JR 0x8 +#define JALR 0x9 +#define MFHI 0x10 +#define MTHI 0x11 +#define MFLO 0x12 +#define MTLO 0x13 +#define MULT 0x18 +#define MULTU 0x19 +#define DIV 0x1a +#define DIVU 0x1b +#define ADD 0x20 +#define ADDU 0x21 +#define SUB 0x22 +#define SUBU 0x23 +#define AND 0x24 +#define OR 0x25 +#define XOR 0x26 +#define SLT 0x2a +#define SLTU 0x2b + +// OPcodes +#define BGEZ 0x1 +#define BGEZAL 0x1 +#define BLTZ 0x1 +#define BLTZAL 0x1 +#define J 0x2 +#define JAL 0x3 +#define BEQ 0x4 +#define BNE 0x5 +#define BLEZ 0x6 +#define BGTZ 0x7 +#define ADDI 0x8 +#define ADDIU 0x9 +#define SLTI 0xa +#define SLTIU 0xb +#define ANDI 0xc +#define ORI 0xd +#define XORI 0xe +#define LUI 0xf +#define LB 0x20 +#define LH 0x21 +#define LWL 0x22 +#define LW 0x23 +#define LBU 0x24 +#define LHU 0x25 +#define LWR 0x26 +#define SB 0x28 +#define SH 0x29 +#define SW 0x2b + +uint32_t gen_instruction(uint32_t src1, uint32_t src2, uint32_t dest, + uint32_t shift, uint32_t function); +uint32_t gen_instruction(uint32_t opcode, uint32_t src, uint32_t dest, + uint32_t Astart); +uint32_t gen_instruction(uint32_t opcode, uint32_t memory); +uint32_t change_endianness(uint32_t inst); + +int test_add(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, uint32_t max, + uint8_t value, unsigned i_t); +int test_bitwise(mips_mem_h ram, mips_cpu_h cpu, uint8_t op); +int test_I(mips_mem_h ram, mips_cpu_h cpu, uint32_t type, uint32_t num1, + uint32_t num2); +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 test_jump(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode); +int test_load(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t word); +int test_mult_div(mips_mem_h ram, mips_cpu_h cpu, uint32_t opcode, uint32_t num1, uint32_t num2); + +#endif // TEST_MIPS_YMH15_H |