/* This file is part of SIS (SPARC instruction simulator) Copyright (C) 1995-2017 Free Software Foundation, Inc. Contributed by Jiri Gaisler, European Space Agency This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config.h" #include "sis.h" #include #include #include #include #include #include #include int ext_irl[NCPU]; #define SIGN_BIT 0x80000000 /* Add two unsigned 32-bit integers, and calculate the carry out. */ static uint32 add32 (uint32 n1, uint32 n2, int *carry) { uint32 result = n1 + n2; *carry = result < n1 || result < n2; return result; } /* Multiply two 32-bit integers. */ void mul64 (uint32 n1, uint32 n2, uint32 * result_hi, uint32 * result_lo, int msigned) { uint32 lo, mid1, mid2, hi, reg_lo, reg_hi; int carry; int sign = 0; /* If this is a signed multiply, calculate the sign of the result and make the operands positive. */ if (msigned) { sign = (n1 ^ n2) & SIGN_BIT; if (n1 & SIGN_BIT) n1 = -n1; if (n2 & SIGN_BIT) n2 = -n2; } /* We can split the 32x32 into four 16x16 operations. This ensures that we do not lose precision on 32bit only hosts: */ lo = ((n1 & 0xFFFF) * (n2 & 0xFFFF)); mid1 = ((n1 & 0xFFFF) * ((n2 >> 16) & 0xFFFF)); mid2 = (((n1 >> 16) & 0xFFFF) * (n2 & 0xFFFF)); hi = (((n1 >> 16) & 0xFFFF) * ((n2 >> 16) & 0xFFFF)); /* We now need to add all of these results together, taking care to propogate the carries from the additions: */ reg_lo = add32 (lo, (mid1 << 16), &carry); reg_hi = carry; reg_lo = add32 (reg_lo, (mid2 << 16), &carry); reg_hi += (carry + ((mid1 >> 16) & 0xFFFF) + ((mid2 >> 16) & 0xFFFF) + hi); /* Negate result if necessary. */ if (sign) { reg_hi = ~reg_hi; reg_lo = -reg_lo; if (reg_lo == 0) reg_hi++; } *result_lo = reg_lo; *result_hi = reg_hi; } /* Divide a 64-bit integer by a 32-bit integer. We cheat and assume that the host compiler supports long long operations. */ void div64 (uint32 n1_hi, uint32 n1_low, uint32 n2, uint32 * result, int msigned) { uint64 n1; n1 = ((uint64) n1_hi) << 32; n1 |= ((uint64) n1_low) & 0xffffffff; if (msigned) { int64 n1_s = (int64) n1; int32 n2_s = (int32) n2; n1_s = n1_s / n2_s; n1 = (uint64) n1_s; } else n1 = n1 / n2; *result = (uint32) (n1 & 0xffffffff); } /* How to clear the accrued FPU exceptions */ void clear_accex () { feclearexcept (FE_ALL_EXCEPT); } void init_regs (sregs) struct pstate *sregs; { int i; ebase.wphit = 0; for (i = 0; i < NCPU; i++) { sregs[i].pc = 0; sregs[i].npc = 4; sregs[i].trap = 0; sregs[i].psr &= 0x00f03fdf; if (cputype == CPU_ERC32) sregs[i].psr |= 0x11000080; /* Set supervisor bit */ else if (cputype == CPU_LEON2) sregs[i].psr |= 0x00000080; /* Set supervisor bit */ else sregs[i].psr |= 0xF3000080; /* Set supervisor bit */ sregs[i].breakpoint = 0; sregs[i].fpstate = 0; sregs[i].fpqn = 0; sregs[i].ftime = 0; sregs[i].ltime = 0; sregs[i].err_mode = 0; ext_irl[i] = 0; sregs[i].g[0] = 0; sregs[i].r[0] = 0; sregs[i].fs = (float32 *) sregs[i].fd; sregs[i].fsi = (int32 *) sregs[i].fd; sregs[i].fsr = 0; sregs[i].fpu_pres = !nfp; sregs[i].ildreg = 0; sregs[i].ildtime = 0; sregs[i].y = 0; sregs[i].asr17 = 0; sregs[i].rett_err = 0; sregs[i].jmpltime = 0; sregs[i].asr17 = 0x04000107 | (i << 28); if (!nfp) sregs[i].asr17 |= (3 << 10); /* Meiko FPU */ sregs[i].cpu = i; sregs[i].simtime = 0; sregs[i].pwdtime = 0; sregs[i].pwdstart = 0; if (i == 0) sregs[i].pwd_mode = 0; else sregs[i].pwd_mode = 1; sregs[i].mip = 0; sregs[i].mstatus = 0; sregs[i].mie = 0; sregs[i].mpp = 0; sregs[i].mode = 1; sregs[i].lrq = 0; sregs[i].bphit = 0; } } #ifdef ENABLE_L1CACHE void l1data_snoop (uint32 address, uint32 cpu) { int i; for (i = 0; i < ncpu; i++) { if (sregs[i].l1dtags[(address >> L1DLINEBITS) & L1DMASK] == (address >> L1DLINEBITS)) { if (cpu != i) { sregs[i].l1dtags[(address >> L1DLINEBITS) & L1DMASK] = 0; // printf("l1 snoop hit : 0x%08X, %d %d\n", address, cpu, i); } } } } void l1data_update (uint32 address, uint32 cpu) { if (sregs[cpu].l1dtags[address >> L1DLINEBITS & L1DMASK] != (address >> L1DLINEBITS)) { sregs[cpu].l1dtags[(address >> L1DLINEBITS) & L1DMASK] = (address >> L1DLINEBITS); sregs[cpu].hold += T_L1DMISS; sregs[cpu].l1dmiss++; } } #endif