summaryrefslogtreecommitdiffstats
path: root/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'exec.c')
-rw-r--r--exec.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/exec.c b/exec.c
new file mode 100644
index 0000000..67a16f5
--- /dev/null
+++ b/exec.c
@@ -0,0 +1,177 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "sis.h"
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+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);
+}
+
+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_LEON3)
+ sregs[i].psr |= 0xF3000080; /* Set supervisor bit */
+ else
+ if (cputype == CPU_LEON2)
+ sregs[i].psr |= 0x00000080; /* Set supervisor bit */
+ else
+ sregs[i].psr |= 0x11000080; /* 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].fs = (float32 *) sregs[i].fd;
+ sregs[i].fsi = (int32 *) sregs[i].fd;
+ sregs[i].fsr = 0;
+ sregs[i].fpu_pres = !nfp;
+ set_fsr(sregs[i].fsr);
+ 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;
+ if (cputype == CPU_LEON3) {
+ 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;
+ }
+}