diff options
Diffstat (limited to 'src/ymh15/mips_cpu.cpp')
-rw-r--r-- | src/ymh15/mips_cpu.cpp | 270 |
1 files changed, 158 insertions, 112 deletions
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; } |