/* * r3000.c last updated 14/10/99 */ #include #include "memory.h" enum opcodetype {special, regimm, j, jal, beq, bne, blez, bgtz, addi, addiu, slti, sltiu, andi, ori, xori, lui, cop0, cop1, cop2, cop3, o20, o21, o22, o23, o24, o25, o26, o27, o28, o29, o30, o31, lb=32, lh, lwl, lw, lbu, lhu, lwr, o39, sb=40, sh, swl, sw, o44, o45, swr=46}; enum specialtype {sll, s1, srl=2, sra, sllv, s5, srlv=6, srav, jr, jalr, s10, s11, syscall=12, brk, s14, s15, mfhi=16, mthi, mflo, mtlo, s20, s21, s22, s23, mult=24, multu, dv, dvu, s28, s29, s30, s31, add=32, addu, sub, subu, and, or, xor, nor, s40, s41, slt=42, sltu}; enum regimmtype {bltz, bgez, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, bltzal=16, bgezal}; enum instructionstate {normal, delay, jump}; unsigned int reg[32]; unsigned int hi; unsigned int lo; unsigned int programBase; unsigned int pc; unsigned int jumpPc; static int dummy; enum instructionstate jumpState; void CallLibrary(unsigned int); void MainLoop(void) { enum opcodetype opcode; enum specialtype function; enum regimmtype immfunction; int rs; int rt; int rd; unsigned int sa; short int offset; unsigned int index; #ifdef UINT64TYPE INT64TYPE mulTemp; UINT64TYPE uMulTemp; #else short int u1; short int u0; short int v1; short int v0; unsigned int u1v1; unsigned int term2; unsigned int u0v0; unsigned int carry; #endif int temp; unsigned int utemp; unsigned int address; unsigned int instruction; unsigned int tempsa; /* * Initialise here */ jumpState = normal; for(;;) { /* * decode instruction */ instruction = read_memory32u(pc); opcode = (enum opcodetype)(instruction >> 26); rs = (int)((instruction & 0x03e00000u)>>21); rt = (int)((instruction & 0x001f0000u)>>16); if (opcode==special) { function = (enum specialtype)(instruction & 0x0000003fu); sa = (instruction & 0x000007c0u)>>6; rd = (int)((instruction & 0x0000f800u)>>11); switch (function) { case sll: reg[rd]=reg[rt]<>=sa; reg[rd]=(unsigned int)(-(int)utemp); break; } /* * else fall through */ case srl: reg[rd]=reg[rt]>>sa; break; case sllv: utemp=reg[rs] & 0x0000001fu; reg[rd]=reg[rt]<>tempsa)); break; } /* * else fall through */ case srlv: utemp=reg[rs] & 0x0000001fu; reg[rd]=reg[rt]>>utemp; break; case jalr: reg[rd]=pc+8; /* * fall through */ case jr: jumpPc=reg[rs]; jumpState=delay; break; case s10: dummy++; case s11: dummy++; case syscall: dummy++; case brk: dummy++; case s14: dummy++; case s15: dummy++; assert(0); break; case mfhi: reg[rd]=hi; break; case mthi: hi=reg[rs]; break; case mflo: reg[rd]=lo; break; case mtlo: lo=reg[rs]; break; case s20: dummy++; case s21: dummy++; case s22: dummy++; case s23: dummy++; assert(0); break; case mult: #ifdef UINT64TYPE mulTemp=((INT64TYPE)(int)reg[rs])*((INT64TYPE)(int)reg[rt]); lo=(unsigned int)(mulTemp&0xffffffffu); hi=(unsigned int)((UINT64TYPE)(mulTemp)>>32); #else if ((int)reg[rs]<0) { u1=(short int)((unsigned int)(-(int)reg[rs])>>16); u0=(short int)((unsigned int)(-(int)reg[rs])&0xffffu); } else { u1=(short int)(reg[rs]>>16); u0=(short int)(reg[rs]&0xffffu); } if ((int)reg[rt]<0) { v1=(short int)((unsigned int)(-(int)reg[rt])>>16); v0=(short int)((unsigned int)(-(int)reg[rt])&0xffffu); } else { v1=(short int)(reg[rt]>>16); v0=(short int)(reg[rt]&0xffffu); } u0v0=(unsigned int)u0*(unsigned int)v0; u1v1=(unsigned int)u1*(unsigned int)v1; term2=(unsigned int)(u1-u0)*(unsigned int)(v0-v1); carry=((u0v0>>16)+(term2&0x0000ffffu)+(u1v1&0x0000ffffu))>>16; lo=u0v0 + (term2<<16) + (u1v1<<16); hi=u1v1 + (u1v1>>16) + (term2>>16) + (u0v0>>16) + carry; if ((int)(reg[rs]^reg[rt])<0) { lo = (unsigned int)(-(int)lo); hi = ~hi; if (lo==0) { hi++; } } #endif break; case multu: #ifdef UINT64TYPE uMulTemp=reg[rs]*reg[rt]; lo=(unsigned int)(uMulTemp&0xffffffffu); hi=(unsigned int)(uMulTemp>>32); #else /* * This 64-bit multiply routine is from Knuth * vol 2 2/e P278 */ u1=(short int)(reg[rs]>>16); u0=(short int)(reg[rs]&0xffffu); v1=(short int)(reg[rt]>>16); v0=(short int)(reg[rt]&0xffffu); u0v0=(unsigned int)u0*(unsigned int)v0; u1v1=(unsigned int)u1*(unsigned int)v1; term2=(unsigned int)(u1-u0)*(unsigned int)(v0-v1); carry=((u0v0>>16)+(term2&0x0000ffffu)+(u1v1&0x0000ffffu))>>16; lo=u0v0 + (term2<<16) + (u1v1<<16); hi=u1v1 + (u1v1>>16) + (term2>>16) + (u0v0>>16) + carry; #endif break; case dv: lo=(unsigned int)((int)reg[rs]/(int)reg[rt]); hi=(unsigned int)((int)reg[rs]%(int)reg[rt]); break; case dvu: lo=reg[rs]/reg[rt]; hi=reg[rs]%reg[rt]; break; case s28: dummy++; case s29: dummy++; case s30: dummy++; case s31: dummy++; assert(0); break; case add: /* * fall through - is the same */ case addu: reg[rd]=reg[rs]+reg[rt]; break; case sub: /* * fall through - is the same */ case subu: reg[rd]=reg[rs]-reg[rt]; break; case and: reg[rd]=reg[rs]®[rt]; break; case or: reg[rd]=reg[rs]|reg[rt]; break; case xor: reg[rd]=reg[rs]^reg[rt]; break; case nor: reg[rd]=~(reg[rs]|reg[rt]); break; case s40: dummy++; case s41: dummy++; assert(0); break; case slt: if ((int)reg[rs]<(int)reg[rt]) { reg[rd]=1; } else { reg[rd]=0; } break; case sltu: if (reg[rs]=0) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc=pc + 4 + temp; jumpState = delay; } break; case r2: dummy++; case r3: dummy++; case r4: dummy++; case r5: dummy++; case r6: dummy++; case r7: dummy++; case r8: dummy++; case r9: dummy++; case r10: dummy++; case r11: dummy++; case r12: dummy++; case r13: dummy++; case r14: dummy++; case r15: dummy++; assert(0); break; case bltzal: reg[31]=pc+8; if ((int)reg[rs]<0) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc=pc + 4 + temp; jumpState = delay; } break; case bgezal: reg[31]=pc+8; if ((int)reg[rs]>=0) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc=pc + 4 + temp; jumpState = delay; } break; default: assert(0); } break; case jal: reg[31]=pc+8; /* * fall through */ case j: index=instruction & 0x03ffffffu; jumpPc = ((pc + 4) & 0xf0000000u) + (index<<2); jumpState = delay; break; case beq: if (reg[rs]==reg[rt]) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc = pc + 4 + temp; jumpState = delay; } break; case bne: if (reg[rs]!=reg[rt]) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc = pc + 4 + temp; jumpState = delay; } break; case blez: if ((int)reg[rs]<=0) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc = pc + 4 + temp; jumpState = delay; } break; case bgtz: if ((int)reg[rs]>0) { if (offset<0) { temp=-(int)(((unsigned int)(-offset))<<2); } else { temp=(int)(((unsigned int)offset)<<2); } jumpPc = pc + 4 + temp; jumpState = delay; } break; case addi: /* * fall through - is the same */ case addiu: reg[rt] = reg[rs]+offset; break; case slti: if ((int)reg[rs]> 8; reg[rt]+=utemp&0xff000000u >> 24; break; case 1: reg[rt] =reg[rt] & 0x000000ffu; reg[rt]+=utemp&0x0000ff00u << 16; reg[rt]+=utemp&0x00ff0000u; reg[rt]+=utemp&0xff000000u >> 16; break; case 2: reg[rt] =reg[rt] & 0x0000ffffu; reg[rt]+=utemp&0x00ff0000u << 8; reg[rt]+=utemp&0xff000000u >> 8; break; case 3: reg[rt] =reg[rt] & 0x00ffffffu; reg[rt]+=utemp&0xff000000u; break; } break; case lw: reg[rt] = read_memory32u(reg[rs]+offset); break; case lbu: reg[rt] = (unsigned int)read_memory8u(reg[rs]+offset); break; case lhu: reg[rt] = (unsigned int)read_memory16u(reg[rs]+offset); break; case lwr: address = (reg[rs]+offset); temp = (int)(address & 0x00000003u); address &= 0xfffffffcu; utemp=read_memory32u(address); switch(temp) { default: case 0: reg[rt] = utemp; break; case 1: reg[rt] = reg[rt] & 0xff000000u; reg[rt] += utemp&0x00ffffffu; break; case 2: reg[rt] = reg[rt] & 0xffff0000u; reg[rt] += utemp&0x0000ffffu; break; case 3: reg[rt] = reg[rt] & 0xffffff00u; reg[rt] += utemp&0x000000ffu; break; } break; case o39: dummy++; assert(0); break; case sb: write_memory8u(reg[rs]+offset, (unsigned char)(reg[rt]&0x000000ff)); break; case sh: write_memory16u(reg[rs]+offset, (unsigned short int)(reg[rt]&0x0000ffff)); break; case swl: address = (reg[rs]+offset); temp = (int)(address & 0x00000003u); address &= 0xfffffffcu; switch(temp) { default: case 0: utemp = reg[rt] & 0xff000000u >> 24; utemp += reg[rt] & 0x00ff0000u >> 8; utemp += reg[rt] & 0x0000ff00u << 8; utemp += reg[rt] & 0x000000ffu << 24; break; case 1: utemp = read_memory32u(address); utemp = utemp & 0x000000ffu; utemp += reg[rt] & 0xff000000u >> 16; utemp += reg[rt] & 0x00ff0000u; utemp += reg[rt] & 0x0000ff00u << 16; break; case 2: utemp = read_memory32u(address); utemp = utemp & 0x0000ffffu; utemp += reg[rt] & 0xff000000u >> 8; utemp += reg[rt] & 0x00ff0000u << 8; break; case 3: utemp = read_memory32u(address); utemp = utemp & 0x00ffffffu; utemp += reg[rt] & 0xff000000u; break; } write_memory32u(address, utemp); break; case sw: write_memory32u(reg[rs]+offset, reg[rt]); break; case o44: dummy++; case o45: dummy++; assert(0); break; case swr: address = (reg[rs]+offset); temp = (int)(address & 0x00000003u); address &= 0xfffffffc; switch(temp) { default: case 0: utemp = reg[rt]; break; case 1: utemp = read_memory32u(address); utemp = utemp & 0x000000ffu; utemp += reg[rt] & 0x00ffffffu << 8; break; case 2: utemp = read_memory32u(address); utemp = utemp & 0x0000ffffu; utemp += reg[rt] & 0x0000ffffu << 16; break; case 3: utemp = read_memory32u(address); utemp = utemp & 0x00ffffffu; utemp += reg[rt] & 0x000000ffu << 24; break; } write_memory32u(address, utemp); break; default: assert(0); } } /* * Do hardware multitask stuff here */ if (jumpState==normal) { pc+=4; } else { if (jumpState==delay) { jumpState=jump; pc+=4; } else { assert(jumpState==jump); jumpState=normal; if (jumpPc < programBase) { CallLibrary(jumpPc); pc+=4; } else { pc=jumpPc; } } } } }