void CPU::exec32(const Instruction32 &insn) { switch(insn.OP) { case 0x00: { uint32_t &rD = r[insn.spform.rD]; uint32_t &rA = r[insn.spform.rA]; uint32_t &rB = r[insn.spform.rB]; switch(insn.spform.func6) { // nop case 0x00: /* nothing */ break; // br{cond}[l] rA case 0x04: if(conditional(insn.spform.rB)) branch(rA - 4, insn.spform.CU); break; // add[.c] rD, rA, rB case 0x08: rD = add(rA, rB, insn.spform.CU); break; // addc[.c] rD, rA, rB case 0x09: rD = addc(rA, rB, insn.spform.CU); break; // sub[.c] rD, rA, rB case 0x0A: rD = sub(rA, rB, insn.spform.CU); break; // subc[.c] rD, rA, rB case 0x0B: rD = subc(rA, rB, insn.spform.CU); break; // cmp{tcs}.c rA, rB case 0x0C: cmp(rA, rB, insn.spform.rD & 0x03, insn.spform.CU); break; // cmpz{tcs}.c rA, rB case 0x0D: cmp(rA, 0, insn.spform.rD & 0x03, insn.spform.CU); break; // neg[.c] rD, rA case 0x0F: rD = sub(0, rA, insn.spform.CU); break; // and[.c] rD, rA, rB case 0x10: rD = bit_and(rA, rB, insn.spform.CU); break; // or[.c] rD, rA, rB case 0x11: rD = bit_or(rA, rB, insn.spform.CU); break; // not[.c] rD, rA, rB case 0x12: rD = bit_xor(rA, ~0, insn.spform.CU); break; // xor[.c] rD, rA, rB case 0x13: rD = bit_or(rA, rB, insn.spform.CU); break; // bitclr[.c] rD, rA, imm5 case 0x14: rD = bit_and(rA, ~(1 << insn.spform.rB), insn.spform.CU); break; // bitset[.c] rD, rA, imm5 case 0x15: rD = bit_or(rA, 1 << insn.spform.rB, insn.spform.CU); break; // bittst.c rA, imm5 case 0x16: bit_and(rA, 1 << insn.spform.rB, insn.spform.CU); break; // bittgl[.c] rA, imm5 case 0x17: rD = bit_xor(rA, 1 << insn.spform.rB, insn.spform.CU); break; // sll[.c] rA, imm5 case 0x18: rD = sll(rA, insn.spform.rB, insn.spform.CU); break; // srl[.c] rA, imm5 case 0x1A: rD = srl(rA, insn.spform.rB, insn.spform.CU); break; // sra[.c] rA, imm5 case 0x1B: rD = sra(rA, insn.spform.rB, insn.spform.CU); break; // mul rA, rD case 0x20: ce_op(rA, rD, std::multiplies<int64_t>()); break; // mulu rA, rD case 0x21: ce_op(rA, rD, std::multiplies<uint64_t>()); break; // div rA, rD case 0x22: ce_op(rA, rD, std::divides<int64_t>()); break; // divu rA, rD case 0x23: ce_op(rA, rD, std::divides<uint64_t>()); break; // mfce{hl} rD[, rA] case 0x24: switch(insn.spform.rB) { case 0x01: rD = CEL; break; case 0x02: rD = CEH; break; case 0x03: rD = CEH; rA = CEL; break; } break; // mtce{hl} rD[, rA] case 0x25: switch(insn.spform.rB) { case 0x01: CEL = rD; break; case 0x02: CEH = rD; break; case 0x03: CEH = rD; CEL = rA; break; } break; // mfsr rA, Srn case 0x28: rA = sr[insn.spform.rB]; // mtsr rA, Srn case 0x29: sr[insn.spform.rB] = rA; // t{cond} case 0x2A: T = conditional(insn.spform.rB); break; // mv{cond} rD, rA case 0x2B: if(conditional(insn.spform.rB)) rD = rA; break; // extsb[.c] rD, rA case 0x2C: rD = sign_extend(rA, 8); if(insn.spform.CU) basic_flags(rD); break; // extsh[.c] rD, rA case 0x2D: rD = sign_extend(rA, 16); if(insn.spform.CU) basic_flags(rD); break; // extzb[.c] rD, rA case 0x2E: rD = bit_and(rA, 0x000000FF, insn.spform.CU); break; // extzh[.c] rD, rA case 0x2F: rD = bit_and(rA, 0x0000FFFF, insn.spform.CU); break; // slli[.c] rD, rA, imm5 case 0x38: rD = sll(rA, insn.spform.rB, insn.spform.CU); break; // srli[.c] rD, rA, imm5 case 0x3A: rD = srl(rA, insn.spform.rB, insn.spform.CU); break; // srai[.c] rD, rA, imm5 case 0x3B: rD = sra(rA, insn.spform.rB, insn.spform.CU); break; default: debugDump(); } } break; case 0x01: { uint32_t &rD = r[insn.iform.rD]; switch(insn.iform.func3) { // addi[.c] rD, imm16 case 0x00: rD = add(rD, sign_extend(insn.iform.Imm16, 16), insn.iform.CU); break; // cmpi.c rD, imm16 case 0x02: cmp(rD, sign_extend(insn.iform.Imm16, 16), 3, insn.iform.CU); break; // andi.c rD, imm16 case 0x04: rD = bit_and(rD, insn.iform.Imm16, insn.iform.CU); break; // ori.c rD, imm16 case 0x05: rD = bit_or(rD, insn.iform.Imm16, insn.iform.CU); break; // ldi rD, imm16 case 0x06: rD = sign_extend(insn.iform.Imm16, 16); break; default: debugDump(); } } break; case 0x02: { // j[l] imm24 if(insn.jform.LK) link(); // Update PC pc &= 0xFC000000; pc |= (insn.jform.Disp24 << 1) - 4; } break; case 0x03: { uint32_t &rD = r[insn.rixform.rD]; uint32_t &rA = r[insn.rixform.rA]; // Pre-increment rA += sign_extend(insn.rixform.Imm12, 12); switch(insn.rixform.func3) { // lw rD, [rA, imm12]+ case 0x00: rD = miu.readU32(rA); break; // lh rD, [rA, imm12]+ case 0x01: rD = sign_extend(miu.readU16(rA), 16); break; // lhu rD, [rA, imm12]+ case 0x02: rD = miu.readU16(rA); break; // lb rD, [rA, imm12]+ case 0x03: rD = sign_extend(miu.readU8(rA), 8); break; // sw rD, [rA, imm12]+ case 0x04: miu.writeU32(rA, rD); break; // sh rD, [rA, imm12]+ case 0x05: miu.writeU16(rA, rD); break; // lbu rD, [rA, imm12]+ case 0x06: rD = miu.readU8(rA); break; // sb rD, [rA, imm12]+ case 0x07: miu.writeU8(rA, rD); break; default: debugDump(); } } break; case 0x04: { // b{cond}[l] if(conditional(insn.bcform.BC)) { if(insn.bcform.LK) link(); pc += sign_extend(((insn.bcform.Disp18_9 << 9) | insn.bcform.Disp8_0) << 1, 20) - 4; } } break; case 0x05: { uint32_t &rD = r[insn.iform.rD]; uint32_t imm16 = insn.iform.Imm16 << 16; switch(insn.iform.func3) { // addis[.c] rD, imm16 case 0x00: rD = add(rD, imm16, insn.iform.CU); break; // cmpis.c rD, imm16 case 0x02: cmp(rD, imm16, 3, insn.iform.CU); break; // andis.c rD, imm16 case 0x04: rD = bit_and(rD, imm16, insn.iform.CU); break; // oris.c rD, imm16 case 0x05: rD = bit_or(rD, imm16, insn.iform.CU); break; // ldis rD, imm16 case 0x06: rD = imm16; break; default: debugDump(); } } break; case 0x06: { uint32_t &rD = r[insn.crform.rD]; uint32_t &crA = cr[insn.crform.crA]; switch(insn.crform.CR_OP) { // mtcr rD, crA case 0x00: crA = rD; break; // mfcr rD, crA case 0x01: rD = crA; break; // rte case 0x84: branch(cr5 - 4, false); /* TODO: missing PSR */ break; default: debugDump(); } } break; case 0x07: { uint32_t &rD = r[insn.rixform.rD]; uint32_t &rA = r[insn.rixform.rA]; switch(insn.rixform.func3) { // lw rD, [rA]+, imm12 case 0x00: rD = miu.readU32(rA); break; // lh rD, [rA]+, imm12 case 0x01: rD = sign_extend(miu.readU16(rA), 16); break; // lhu rD, [rA]+, imm12 case 0x02: rD = miu.readU16(rA); break; // lb rD, [rA]+, imm12 case 0x03: rD = sign_extend(miu.readU8(rA), 8); break; // sw rD, [rA]+, imm12 case 0x04: miu.writeU32(rA, rD); break; // sh rD, [rA]+, imm12 case 0x05: miu.writeU16(rA, rD); break; // lbu rD, [rA]+, imm12 case 0x06: rD = miu.readU8(rA); break; // sb rD, [rA]+, imm12 case 0x07: miu.writeU8(rA, rD); break; default: debugDump(); } // Post-increment rA += sign_extend(insn.rixform.Imm12, 12); } break; case 0x08: { // addri[.c] rD, rA, imm14 uint32_t &rD = r[insn.riform.rD]; uint32_t &rA = r[insn.riform.rA]; uint32_t imm14 = sign_extend(insn.riform.Imm14, 14); rD = add(rA, imm14, insn.riform.CU); } break; case 0x0C: { // andri[.c] rD, rA, imm14 uint32_t &rD = r[insn.riform.rD]; uint32_t &rA = r[insn.riform.rA]; uint32_t imm14 = insn.riform.Imm14; rD = bit_and(rA, imm14, insn.riform.CU); } break; case 0x0D: { // orri[.c] rD, rA, imm14 uint32_t &rD = r[insn.riform.rD]; uint32_t &rA = r[insn.riform.rA]; uint32_t imm14 = insn.riform.Imm14; rD = bit_or(rA, imm14, insn.riform.CU); } break; case 0x10: { // lw rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); rD = miu.readU32(rA + imm15); } break; case 0x11: { // lh rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); rD = sign_extend(miu.readU16(rA + imm15), 16); } break; case 0x12: { // lhu rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); rD = miu.readU16(rA + imm15); } break; case 0x13: { // lb rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); rD = sign_extend(miu.readU8(rA + imm15), 8); } break; case 0x14: { // sw rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); miu.writeU32(rA + imm15, rD); } break; case 0x15: { // sh rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); miu.writeU16(rA + imm15, rD); } break; case 0x16: { // lbu rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); rD = miu.readU8(rA + imm15); } break; case 0x17: { // sb rD, [rA, imm15] uint32_t &rD = r[insn.mform.rD]; uint32_t &rA = r[insn.mform.rA]; uint32_t imm15 = sign_extend(insn.mform.Imm15, 15); miu.writeU8(rA + imm15, rD); } break; case 0x18: // cache op, [rA, imm15] break; default: debugDump(); } }
//Perform the operation given by the CPU void ALU::operation(int code, Register a, Register b) { //Reset all flags that aren't required m_flags[1] = 0; m_flags[2] = 0; m_flags[3] = 0; //Check if unary operation if(!(code==0||code==1||code==4||code==9||code==13||code==16||code==17||code==18||code==19||code==20)) { //Compare a and b if possible and set flags if(a.getValue()>b.getValue()) { m_flags[1] = 1; } else if(a.getValue()==b.getValue()) { m_flags[2] = 1; } } //Perform operation based on code (sets carry flag to 0 if it isn't set in the operation) if(code==0) { zero(a); m_flags[0] = 0; } else if(code==1) { one(a); m_flags[0] = 0; } else if(code==2) { add(a,b); } else if(code==3) { addc(a,b); } else if(code==4) { inc(a); } else if(code==5) { sub(a,b); } else if(code==6) { subc(a,b); } else if(code==7) { rsub(a,b); } else if(code==8) { rsubc(a,b); } else if(code==9) { dec(a); } else if(code==10) { mul(a,b); } else if(code==11) { random(a); m_flags[0] = 0; } else if(code==16) { shl(a); } else if(code==17) { shlc(a); } else if(code==18) { shr(a); } else if(code==19) { shrc(a); } else if(code==20) { not(a); m_flags[0] = 0; } else if(code==21) { and(a,b); m_flags[0] = 0; } else if(code==22) { nand(a,b); m_flags[0] = 0; } else if(code==23) { or(a,b); m_flags[0] = 0; } else if(code==24) { nor(a,b); m_flags[0] = 0; } else if(code==25) { xor(a,b); m_flags[0] = 0; } else if(code==26) { xnor(a,b); m_flags[0] = 0; } else if(code==27) { bclr(a,b); m_flags[0] = 0; } else if(code==31) { m_flags[0] = 0; } //Check if output is 0 and set flag accordingly if(a.getValue()) { m_flags[3]=1; } }