📄 exec.c
字号:
<< 10) | (rs1 >> 1); if ((sregs->y & 1) == 0) operand2 = 0; *rdd = operand1 + operand2; sregs->y = (rs1 << 31) | (sregs->y >> 1); sregs->psr = add_cc(sregs->psr, operand1, operand2, *rdd); break; case DIVScc: { int sign; uint32 result, remainder; int c0, y31; if (!sparclite) { sregs->trap = TRAP_UNIMP; break; } sign = ((sregs->psr & PSR_V) != 0) ^ ((sregs->psr & PSR_N) != 0); remainder = (sregs->y << 1) | (rs1 >> 31); /* If true sign is positive, calculate remainder - divisor. Otherwise, calculate remainder + divisor. */ if (sign == 0) operand2 = ~operand2 + 1; result = remainder + operand2; /* The SPARClite User's Manual is not clear on how the "carry out" of the above ALU operation is to be calculated. From trial and error tests on the the chip itself, it appears that it is a normal addition carry, and not a subtraction borrow, even in cases where the divisor is subtracted from the remainder. FIXME: get the true story from Fujitsu. */ c0 = result < (uint32) remainder || result < (uint32) operand2; if (result & 0x80000000) sregs->psr |= PSR_N; else sregs->psr &= ~PSR_N; y31 = (sregs->y & 0x80000000) == 0x80000000; if (result == 0 && sign == y31) sregs->psr |= PSR_Z; else sregs->psr &= ~PSR_Z; sign = (sign && !y31) || (!c0 && (sign || !y31)); if (sign ^ (result >> 31)) sregs->psr |= PSR_V; else sregs->psr &= ~PSR_V; if (!sign) sregs->psr |= PSR_C; else sregs->psr &= ~PSR_C; sregs->y = result; if (rd != 0) *rdd = (rs1 << 1) | !sign; } break; case SMUL: { mul64 (rs1, operand2, &sregs->y, rdd, 1); } break; case SMULCC: { uint32 result; mul64 (rs1, operand2, &sregs->y, &result, 1); if (result & 0x80000000) sregs->psr |= PSR_N; else sregs->psr &= ~PSR_N; if (result == 0) sregs->psr |= PSR_Z; else sregs->psr &= ~PSR_Z; *rdd = result; } break; case UMUL: { mul64 (rs1, operand2, &sregs->y, rdd, 0); } break; case UMULCC: { uint32 result; mul64 (rs1, operand2, &sregs->y, &result, 0); if (result & 0x80000000) sregs->psr |= PSR_N; else sregs->psr &= ~PSR_N; if (result == 0) sregs->psr |= PSR_Z; else sregs->psr &= ~PSR_Z; *rdd = result; } break; case SDIV: { if (sparclite) { sregs->trap = TRAP_UNIMP; break; } if (operand2 == 0) { sregs->trap = TRAP_DIV0; break; } div64 (sregs->y, rs1, operand2, rdd, 1); } break; case SDIVCC: { uint32 result; if (sparclite) { sregs->trap = TRAP_UNIMP; break; } if (operand2 == 0) { sregs->trap = TRAP_DIV0; break; } div64 (sregs->y, rs1, operand2, &result, 1); if (result & 0x80000000) sregs->psr |= PSR_N; else sregs->psr &= ~PSR_N; if (result == 0) sregs->psr |= PSR_Z; else sregs->psr &= ~PSR_Z; /* FIXME: should set overflow flag correctly. */ sregs->psr &= ~(PSR_C | PSR_V); *rdd = result; } break; case UDIV: { if (sparclite) { sregs->trap = TRAP_UNIMP; break; } if (operand2 == 0) { sregs->trap = TRAP_DIV0; break; } div64 (sregs->y, rs1, operand2, rdd, 0); } break; case UDIVCC: { uint32 result; if (sparclite) { sregs->trap = TRAP_UNIMP; break; } if (operand2 == 0) { sregs->trap = TRAP_DIV0; break; } div64 (sregs->y, rs1, operand2, &result, 0); if (result & 0x80000000) sregs->psr |= PSR_N; else sregs->psr &= ~PSR_N; if (result == 0) sregs->psr |= PSR_Z; else sregs->psr &= ~PSR_Z; /* FIXME: should set overflow flag correctly. */ sregs->psr &= ~(PSR_C | PSR_V); *rdd = result; } break; case IXNOR: *rdd = rs1 ^ ~operand2; break; case IXNORCC: *rdd = rs1 ^ ~operand2; log_cc(*rdd, sregs); break; case IXOR: *rdd = rs1 ^ operand2; break; case IXORCC: *rdd = rs1 ^ operand2; log_cc(*rdd, sregs); break; case IOR: *rdd = rs1 | operand2; break; case IORCC: *rdd = rs1 | operand2; log_cc(*rdd, sregs); break; case IORN: *rdd = rs1 | ~operand2; break; case IORNCC: *rdd = rs1 | ~operand2; log_cc(*rdd, sregs); break; case IANDNCC: *rdd = rs1 & ~operand2; log_cc(*rdd, sregs); break; case IANDN: *rdd = rs1 & ~operand2; break; case IAND: *rdd = rs1 & operand2; break; case IANDCC: *rdd = rs1 & operand2; log_cc(*rdd, sregs); break; case SUB: *rdd = rs1 - operand2; break; case SUBCC: *rdd = rs1 - operand2; sregs->psr = sub_cc(sregs->psr, rs1, operand2, *rdd); break; case SUBX: *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1); break; case SUBXCC: *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1); sregs->psr = sub_cc(sregs->psr, rs1, operand2, *rdd); break; case ADD: *rdd = rs1 + operand2; break; case ADDCC: *rdd = rs1 + operand2; sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd); break; case ADDX: *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1); break; case ADDXCC: *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1); sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd); break; case TADDCC: *rdd = rs1 + operand2; sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd); if ((rs1 | operand2) & 0x3) sregs->psr |= PSR_V; break; case TSUBCC: *rdd = rs1 - operand2; sregs->psr = sub_cc (sregs->psr, rs1, operand2, *rdd); if ((rs1 | operand2) & 0x3) sregs->psr |= PSR_V; break; case TADDCCTV: *rdd = rs1 + operand2; result = add_cc(0, rs1, operand2, *rdd); if ((rs1 | operand2) & 0x3) result |= PSR_V; if (result & PSR_V) { sregs->trap = TRAP_TAG; } else { sregs->psr = (sregs->psr & ~PSR_CC) | result; } break; case TSUBCCTV: *rdd = rs1 - operand2; result = add_cc (0, rs1, operand2, *rdd); if ((rs1 | operand2) & 0x3) result |= PSR_V; if (result & PSR_V) { sregs->trap = TRAP_TAG; } else { sregs->psr = (sregs->psr & ~PSR_CC) | result; } break; case SLL: *rdd = rs1 << (operand2 & 0x1f); break; case SRL: *rdd = rs1 >> (operand2 & 0x1f); break; case SRA: *rdd = ((int) rs1) >> (operand2 & 0x1f); break; case FLUSH: if (ift) sregs->trap = TRAP_UNIMP; break; case SAVE: new_cwp = ((sregs->psr & PSR_CWP) - 1) & PSR_CWP; if (sregs->wim & (1 << new_cwp)) { sregs->trap = TRAP_WOFL; break; } if (rd > 7) rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]); *rdd = rs1 + operand2; sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp; break; case RESTORE: new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP; if (sregs->wim & (1 << new_cwp)) { sregs->trap = TRAP_WUFL; break; } if (rd > 7) rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]); *rdd = rs1 + operand2; sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp; break; case RDPSR: if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } *rdd = sregs->psr; break; case RDY: if (!sparclite) *rdd = sregs->y; else { int rs1_is_asr = (sregs->inst >> 14) & 0x1f; if ( 0 == rs1_is_asr ) *rdd = sregs->y; else if ( 17 == rs1_is_asr ) *rdd = sregs->asr17; else { sregs->trap = TRAP_UNIMP; break; } } break; case RDWIM: if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } *rdd = sregs->wim; break; case RDTBR: if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } *rdd = sregs->tbr; break; case WRPSR: if ((sregs->psr & 0x1f) > 7) { sregs->trap = TRAP_UNIMP; break; } if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } sregs->psr = (rs1 ^ operand2) & 0x00f03fff; break; case WRWIM: if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } sregs->wim = (rs1 ^ operand2) & 0x0ff; break; case WRTBR: if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } sregs->tbr = (sregs->tbr & 0x00000ff0) | ((rs1 ^ operand2) & 0xfffff000); break; case WRY: if (!sparclite) sregs->y = (rs1 ^ operand2); else { if ( 0 == rd ) sregs->y = (rs1 ^ operand2); else if ( 17 == rd ) sregs->asr17 = (rs1 ^ operand2); else { sregs->trap = TRAP_UNIMP; break; } } break; case JMPL:#ifdef STAT sregs->nbranch++;#endif sregs->icnt = T_JMPL; /* JMPL takes two cycles */ if (rs1 & 0x3) { sregs->trap = TRAP_UNALI; break; } *rdd = sregs->pc; npc = rs1 + operand2; break; case RETT: address = rs1 + operand2; new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP; sregs->icnt = T_RETT; /* RETT takes two cycles */ if (sregs->psr & PSR_ET) { sregs->trap = TRAP_UNIMP; break; } if (!(sregs->psr & PSR_S)) { sregs->trap = TRAP_PRIVI; break; } if (sregs->wim & (1 << new_cwp)) { sregs->trap = TRAP_WUFL; break; } if (address & 0x3) { sregs->trap = TRAP_UNALI; break; } sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp | PSR_ET; sregs->psr = (sregs->psr & ~PSR_S) | ((sregs->psr & PSR_PS) << 1); npc = address; break; case SCAN: { uint32 result, mask; int i; if (!sparclite) { sregs->trap = TRAP_UNIMP; break; } mask = (operand2 & 0x80000000) | (operand2 >> 1); result = rs1 ^ mask; for (i = 0; i < 32; i++) { if (result & 0x80000000) break; result <<= 1; } *rdd = i == 32 ? 63 : i; } break; default: sregs->trap = TRAP_UNIMP; break; } } break; case 3: /* Load/store instructions */ address = rs1 + operand2; if (sregs->psr & PSR_S) asi = 11; else asi = 10; if (op3 & 4) { sregs->icnt = T_ST; /* Set store instruction count */#ifdef STAT sregs->nstore++;#endif } else { sregs->icnt = T_LD; /* Set load instruction count */#ifdef STAT sregs->nload++;#endif } /* Decode load/store instructions */ switch (op3) { case LDDA: if (!chk_asi(sregs, &asi, op3)) break; case LDD: if (address & 0x7) { sregs->trap = TRAP_UNALI; break; } if (rd & 1) { rd &= 0x1e; if (rd > 7) rdd = &(sregs->r[(cwp + rd) & 0x7f]); else rdd = &(sregs->g[rd]); } mexc = memory_read(asi, address, ddata, 3, &ws); sregs->hold += ws * 2; sregs->icnt = T_LDD; if (mexc) { sregs->trap = TRAP_DEXC; } else { rdd[0] = ddata[0]; rdd[1] = ddata[1];#ifdef STAT sregs->nload++; /* Double load counts twice */#endif } break; case LDA: if (!chk_asi(sregs, &asi, op3)) break; case LD: if (address & 0x3) { sregs->trap = TRAP_UNALI; break; } mexc = memory_read(asi, address, &data, 2, &ws); sregs->hold += ws; if (mexc) { sregs->trap = TRAP_DEXC; } else { *rdd = data; } break; case LDSTUBA: if (!chk_asi(sregs, &asi, op3)) break; case LDSTUB: mexc = memory_read(asi, address, &data, 0, &ws); sregs->hold += ws; sregs->icnt = T_LDST; if (mexc) { sregs->trap = TRAP_DEXC; break; } *rdd = data; data = 0x0ff; mexc = memory_write(asi, address, &data, 0, &ws); sregs->hold += ws; if (mexc) { sregs->trap = TRAP_DEXC; }#ifdef STAT sregs->nload++;#endif break; case LDSBA: case LDUBA: if (!chk_asi(sregs, &asi, op3)) break; case LDSB: case LDUB: mexc = memory_read(asi, address, &data, 0, &ws); sregs->hold += ws; if (mexc) { sregs->trap = TRAP_DEXC; break; } if ((op3 == LDSB) && (data & 0x80)) data |= 0xffffff00; *rdd = data; break; case LDSHA: case LDUHA: if (!chk_asi(sregs, &asi, op3)) break; case LDSH: case LDUH: if (address & 0x1) { sregs->trap = TRAP_UNALI; break; } mexc = memory_read(asi, address, &data, 1, &ws); sregs->hold += ws; if (mexc) { sregs->trap = TRAP_DEXC; break; } if ((op3 == LDSH) && (data & 0x8000)) data |= 0xffff0000; *rdd = data; break; case LDF: if (!((sregs->psr & PSR_EF) && FP_PRES)) { sregs->trap = TRAP_FPDIS; break; } if (address & 0x3) { sregs->trap = TRAP_UNALI; break; } if (ebase.simtime < sregs->ftime) { if ((sregs->frd == rd) || (sregs->frs1 == rd) || (sregs->frs2 == rd)) sregs->fhold += (sregs->ftime - ebase.simtime); } mexc = memory_read(asi, address, &data, 2, &ws); sregs->hold += ws; sregs->flrd = rd; sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD + sregs->hold + sregs->fhold; if (mexc) { sregs->trap = TRAP_DEXC; } else { sregs->fs[rd] = *((float32 *) & data); } break; case LDDF: if (!((sregs->psr & PSR_EF) && FP_PRES)) { sregs->trap = TRAP_FPDIS; break; } if (address & 0x7) { sregs->trap = TRAP_UNALI; break; } if (ebase.simtime < sregs->ftime) { if (((sregs->frd >> 1) == (rd >> 1)) || ((sregs->frs1 >> 1) == (rd >> 1)) || ((sregs->frs2 >> 1) == (rd >> 1))) sregs->fhold += (sregs->ftime - ebase.simtime); } mexc = memory_read(asi, address, ddata, 3, &ws); sregs->hold += ws * 2; sregs->icnt = T_LDD; if (mexc) { sregs->trap = TRAP_DEXC; } else { rd &= 0x1E; sregs->flrd = rd; sregs->fs[rd] = *((float32 *) & ddata[0]);#ifdef STAT sregs->nload++; /* Double load counts twice */#endif sregs->fs[rd + 1] = *((float32 *) & ddata[1]); sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD + sregs->hold + sregs->fhold; } break; case LDFSR: if (ebase.simtime < sregs->ftime) { sregs->fhold += (sregs->ftime - ebase.simtime); } if (!((sregs->psr & PSR_EF) && FP_PRES)) { sregs->trap = TRAP_FPDIS; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -