aboutsummaryrefslogtreecommitdiffstats
path: root/src/ymh15/mips_cpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ymh15/mips_cpu.cpp')
-rw-r--r--src/ymh15/mips_cpu.cpp270
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], &reg_s);
- if(imm == 0) {
+ if(!imm) {
mips_cpu_get_register(state, var[REG_T], &reg_t);
} else {
- reg_t = var[IMM];
+ reg_t = var[IMM]&0x0000ffff;
}
// performs correct bitwise operation and sets register;
- if((var[FUNC]&0xf) == 4 || var[OPCODE] == 0xc) reg_d = reg_s & reg_t;
- else if((var[FUNC]&0xf) == 5 || var[OPCODE] == 0xd) reg_d = reg_s | reg_t;
- else reg_d = reg_s ^ reg_t;
+ if(var[FUNC] == AND || var[OPCODE] == ANDI) {
+ reg_d = reg_s & reg_t;
+ }
+ else if(var[FUNC] == OR || var[OPCODE] == ORI) {
+ reg_d = reg_s | reg_t;
+ }
+ else {
+ reg_d = reg_s ^ reg_t;
+ }
// set register to the answer
mips_cpu_set_register(state, var[REG_D], reg_d);
@@ -372,12 +366,12 @@ mips_error branch(mips_cpu_h state, uint32_t var[8]) {
state->regs[31] = state->pc+8;
}
- if((state->regs[var[REG_S]] == state->regs[var[REG_D]] && var[OPCODE] == 4) || // bez
- (state->regs[var[REG_S]] != state->regs[var[REG_D]] && var[OPCODE] == 5) || // bne
- (((int32_t)state->regs[var[REG_S]] >= 0) && (var[OPCODE] == 1) && (var[REG_D]&1) == 1) || // bgez / bgezal
- ((int32_t)state->regs[var[REG_S]] < 0 && var[OPCODE] == 1 && (var[REG_D]&1) == 0) || // bltz / bltzal
- ((int32_t)state->regs[var[REG_S]] > 0 && var[OPCODE] == 7 && (var[REG_D]&1) == 0) || // bgtz
- ((int32_t)state->regs[var[REG_S]] <= 0 && var[OPCODE] == 6 && (var[REG_D]&1) == 0)) { // blez
+ if((state->regs[var[REG_S]] == state->regs[var[REG_D]] && var[OPCODE] == BEQ) ||
+ (state->regs[var[REG_S]] != state->regs[var[REG_D]] && var[OPCODE] == BNE) ||
+ (((int32_t)state->regs[var[REG_S]] >= 0) && (var[OPCODE] == BGEZ) && (var[REG_D]&1) == 1) ||
+ ((int32_t)state->regs[var[REG_S]] < 0 && var[OPCODE] == BLTZ && (var[REG_D]&1) == 0) ||
+ ((int32_t)state->regs[var[REG_S]] > 0 && var[OPCODE] == BGTZ && (var[REG_D]&1) == 0) ||
+ ((int32_t)state->regs[var[REG_S]] <= 0 && var[OPCODE] == BLEZ && (var[REG_D]&1) == 0)) {
state->next_pc += (var[IMM]<<2);
state->delay_slot += 1;
@@ -389,78 +383,90 @@ mips_error branch(mips_cpu_h state, uint32_t var[8]) {
mips_error jump(mips_cpu_h state, uint32_t var[8], uint8_t link) {
uint8_t reg_d;
uint32_t jump_loc;
- if(var[FUNC] == 9 || var[FUNC] == 8) {
+ if(var[FUNC] == JALR || var[FUNC] == JR) {
jump_loc = state->regs[var[REG_S]];
reg_d = var[REG_D];
+ state->next_pc = jump_loc;
} else {
jump_loc = var[MEM]<<2;
reg_d = 31;
+ state->next_pc = (state->next_pc&0xf0000000) | (jump_loc&0xfffffff);
}
if(link) {
state->regs[reg_d] = state->pc+8;
}
- state->next_pc = jump_loc;
state->delay_slot += 1;
return mips_Success;
}
mips_error load(mips_cpu_h state, uint32_t var[8]) {
- uint32_t addr;
- uint8_t mem_byte;
- uint16_t mem_halfword;
- uint32_t mem_word;
+ uint32_t addr = 0;
+ uint8_t mem_byte = 0;
+ uint16_t mem_halfword = 0;
+ uint32_t mem_word = 0;
+ unsigned i = 0;
addr = state->regs[var[REG_S]] + var[IMM];
- if(var[OPCODE] == 0x24 || var[OPCODE] == 0x20) { // lb lbu
+ if(var[OPCODE] == LB || var[OPCODE] == LBU) {
mips_mem_read(state->mem, addr, 1, &mem_byte);
- } else if(var[OPCODE] == 0x21 || var[OPCODE] == 0x25) { // lh lhu
+ } else if(var[OPCODE] == LH || var[OPCODE] == LHU) {
if((addr&0b1) == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
mips_mem_read(state->mem, addr, 2, (uint8_t*)&mem_halfword);
mem_halfword = mem_halfword>>8 | mem_halfword<<8;
- } else if(var[OPCODE] == 0x23 || var[OPCODE] == 0x22) { // lw lwl
+ } else if(var[OPCODE] == LW) {
if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
mips_mem_read(state->mem, addr, 4, (uint8_t*)&mem_word);
mem_word = (mem_word<<24) | ((mem_word>>8)&0xff00) | ((mem_word<<8)&0xff0000) | (mem_word>>24);
- } else if(var[OPCODE] == 0x26) { // lwr
- if((addr&0b1) == 0 || (addr&0b10)>>1 == 0) {
- return mips_ExceptionInvalidAddress;
+ } else if(var[OPCODE] == LWL) {
+ i = 3;
+ while((addr&3) != 0) {
+ mips_mem_read(state->mem, addr, 1, &mem_byte);
+ mem_word = mem_word | ((uint32_t)mem_byte<<(i*8));
+ ++addr;
+ --i;
+ }
+ } else if(var[OPCODE] == LWR) {
+ i = 0;
+ while((addr&3) != 3) {
+ mips_mem_read(state->mem, addr, 1, &mem_byte);
+ mem_word = mem_word | ((uint32_t)mem_byte<<(i*8));
+ --addr;
+ ++i;
}
- mips_mem_read(state->mem, addr-3, 4, (uint8_t*)&mem_word);
- mem_word = (mem_word<<24) | ((mem_word>>8)&0xff00) | ((mem_word<<8)&0xff0000) | (mem_word>>24);
}
-
+
switch(var[OPCODE]) {
- case 0xf:
+ case LUI:
state->regs[var[REG_D]] = var[IMM]<<16;
return mips_Success;
- case 0x20:
+ case LB:
state->regs[var[REG_D]] = (uint32_t)(int8_t)mem_byte;
return mips_Success;
- case 0x21:
+ case LH:
state->regs[var[REG_D]] = (uint32_t)(int16_t)mem_halfword;
return mips_Success;
- case 0x22:
- state->regs[var[REG_D]] = (mem_word&0xffff0000)|(state->regs[var[REG_D]]&0xffff);
+ case LWL:
+ state->regs[var[REG_D]] = (state->regs[var[REG_D]]&(0xffffffff>>((3-i)*8))) | (mem_word&(0xffffffff<<((i+1)*8)));
return mips_Success;
- case 0x23:
+ case LW:
state->regs[var[REG_D]] = mem_word;
return mips_Success;
- case 0x24:
+ case LBU:
state->regs[var[REG_D]] = (uint32_t)mem_byte;
return mips_Success;
- case 0x25:
+ case LHU:
state->regs[var[REG_D]] = (uint32_t)mem_halfword;
return mips_Success;
- case 0x26:
- state->regs[var[REG_D]] = (state->regs[var[REG_D]]&0xffff0000)|(mem_word&0xffff);
+ case LWR:
+ state->regs[var[REG_D]] = (state->regs[var[REG_D]]&(0xffffffff<<(i*8))) | (mem_word&(0xffffffff>>((4-i)*8)));
return mips_Success;
default:
return mips_ExceptionInvalidInstruction;
@@ -478,17 +484,17 @@ mips_error store(mips_cpu_h state, uint32_t var[8]) {
half_word = (uint16_t)state->regs[var[REG_D]];
byte = (uint8_t)state->regs[var[REG_D]];
- if(var[OPCODE] == 0x28) {
+ if(var[OPCODE] == SB) {
mips_mem_write(state->mem, addr, 1, &byte);
- } else if(var[OPCODE] == 0x29) {
+ } else if(var[OPCODE] == SH) {
if((addr&0b1) == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
uint16_t tmp = half_word << 8 | half_word >> 8;
mips_mem_write(state->mem, addr, 2, (uint8_t*)&tmp);
- } else if(var[OPCODE] == 0x2b) {
+ } else if(var[OPCODE] == SW) {
if((addr&0b1) == 1 || (addr&0b10)>>1 == 1) {
- return mips_ExceptionInvalidAddress;
+ return mips_ExceptionInvalidAlignment;
}
uint32_t tmp = word<<24 | ((word>>8)&0xff00) | ((word<<8)&0xff0000) | word>>24;
mips_mem_write(state->mem, addr, 4, (uint8_t*)&tmp);
@@ -500,14 +506,14 @@ mips_error store(mips_cpu_h state, uint32_t var[8]) {
mips_error move(mips_cpu_h state, uint32_t var[8]) {
switch(var[FUNC]) {
- case 0x10:
+ case MFHI:
return mips_cpu_set_register(state, var[REG_D], state->hi);
- case 0x11:
- return mips_cpu_get_register(state, var[REG_D], &state->hi);
- case 0x12:
+ case MTHI:
+ return mips_cpu_get_register(state, var[REG_S], &state->hi);
+ case MFLO:
return mips_cpu_set_register(state, var[REG_D], state->lo);
- case 0x13:
- return mips_cpu_get_register(state, var[REG_D], &state->lo);
+ case MTLO:
+ return mips_cpu_get_register(state, var[REG_S], &state->lo);
default:
return mips_ExceptionInvalidInstruction;
}
@@ -517,19 +523,19 @@ mips_error move(mips_cpu_h state, uint32_t var[8]) {
mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
uint64_t unsigned_result, signed_result;
switch(var[FUNC]) {
- case 0x18: // mult
+ case MULT:
signed_result = ((int64_t)(int32_t)state->regs[var[REG_S]])*((int64_t)(int32_t)state->regs[var[REG_T]]);
state->lo = (uint32_t)signed_result;
state->hi = (uint32_t)(signed_result>>32);
return mips_Success;
- case 0x19: // multu
+ case MULTU:
unsigned_result = ((uint64_t)state->regs[var[REG_S]])*((uint64_t)state->regs[var[REG_T]]);
state->lo = (uint32_t)unsigned_result;
state->hi = (uint32_t)(unsigned_result>>32);
return mips_Success;
- case 0x1a: // div
+ case DIV:
if(var[REG_T] == 0) {
state->lo = 0;
state->hi = 0;
@@ -540,7 +546,7 @@ mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
state->hi = ((int32_t)state->regs[var[REG_S]])%((int32_t)state->regs[var[REG_T]]);
return mips_Success;
- case 0x1b: // divu
+ case DIVU:
if(var[REG_T] == 0) {
state->lo = 0;
state->hi = 0;
@@ -557,10 +563,50 @@ mips_error mult_div(mips_cpu_h state, uint32_t var[8]) {
}
mips_error shift(mips_cpu_h state, uint32_t var[8]) {
- if(var[FUNC] == 0 && var[OPCODE] == 0) {
+ if(var[FUNC] == SLL && var[OPCODE] == 0) {
state->regs[var[REG_D]] = state->regs[var[REG_T]] << var[SHIFT];
- } else if(var[FUNC] == 4) {
+ } else if(var[FUNC] == SLLV) {
state->regs[var[REG_D]] = state->regs[var[REG_T]] << state->regs[var[REG_S]];
- } else if(var[FUNC] == 2/*TODO*/);
+ } else if(var[FUNC] == SRA) {
+ state->regs[var[REG_D]] = (int32_t)state->regs[var[REG_T]] >> var[SHIFT];
+ } else if(var[FUNC] == SRAV) {
+ state->regs[var[REG_D]] = ((int32_t)state->regs[var[REG_T]]) >> state->regs[var[REG_S]];
+ } else if(var[FUNC] == SRL) {
+ state->regs[var[REG_D]] = state->regs[var[REG_T]] >> var[SHIFT];
+ } else if(var[FUNC] == SRLV) {
+ state->regs[var[REG_D]] = state->regs[var[REG_T]] >> state->regs[var[REG_S]];
+ }
+ return mips_Success;
+}
+
+mips_error set(mips_cpu_h state, uint32_t var[8], uint32_t imm) {
+ uint32_t reg_s, reg_t, reg_d;
+
+ mips_cpu_get_register(state, var[REG_S], &reg_s);
+
+ if(!imm) {
+ mips_cpu_get_register(state, var[REG_T], &reg_t);
+ } else {
+ reg_t = var[IMM];
+ }
+
+ if(var[FUNC] == SLT || var[OPCODE] == SLTI) {
+ if(((int32_t)reg_s) < ((int32_t)reg_t)) {
+ reg_d = 1;
+ } else {
+ reg_d = 0;
+ }
+ } else if(var[FUNC] == SLTU || var[OPCODE] == SLTIU) {
+ if(reg_s < reg_t) {
+ reg_d = 1;
+ } else {
+ reg_d = 0;
+ }
+ } else {
+ return mips_ExceptionInvalidInstruction;
+ }
+
+ mips_cpu_set_register(state, var[REG_D], reg_d);
+
return mips_Success;
}