|
|
1.1 root 1: /*
2: * M68K helper routines
3: *
4: * Copyright (c) 2007 CodeSourcery
5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, write to the Free Software
1.1.1.2 ! root 18: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
1.1 root 19: */
20: #include "exec.h"
1.1.1.2 ! root 21: #include "helpers.h"
1.1 root 22:
23: #if defined(CONFIG_USER_ONLY)
24:
25: void do_interrupt(int is_hw)
26: {
27: env->exception_index = -1;
28: }
29:
30: #else
31:
32: extern int semihosting_enabled;
33:
34: #define MMUSUFFIX _mmu
35:
36: #define SHIFT 0
37: #include "softmmu_template.h"
38:
39: #define SHIFT 1
40: #include "softmmu_template.h"
41:
42: #define SHIFT 2
43: #include "softmmu_template.h"
44:
45: #define SHIFT 3
46: #include "softmmu_template.h"
47:
48: /* Try to fill the TLB and return an exception if error. If retaddr is
49: NULL, it means that the function was called in C code (i.e. not
50: from generated code or from helper.c) */
51: /* XXX: fix it to restore all registers */
52: void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
53: {
54: TranslationBlock *tb;
55: CPUState *saved_env;
56: unsigned long pc;
57: int ret;
58:
59: /* XXX: hack to restore env in all cases, even if not called from
60: generated code */
61: saved_env = env;
62: env = cpu_single_env;
63: ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1.1.1.2 ! root 64: if (unlikely(ret)) {
1.1 root 65: if (retaddr) {
66: /* now we have a real cpu fault */
67: pc = (unsigned long)retaddr;
68: tb = tb_find_pc(pc);
69: if (tb) {
70: /* the PC is inside the translated code. It means that we have
71: a virtual CPU fault */
72: cpu_restore_state(tb, env, pc, NULL);
73: }
74: }
75: cpu_loop_exit();
76: }
77: env = saved_env;
78: }
79:
80: static void do_rte(void)
81: {
82: uint32_t sp;
83: uint32_t fmt;
84:
85: sp = env->aregs[7];
86: fmt = ldl_kernel(sp);
87: env->pc = ldl_kernel(sp + 4);
88: sp |= (fmt >> 28) & 3;
89: env->sr = fmt & 0xffff;
90: m68k_switch_sp(env);
91: env->aregs[7] = sp + 8;
92: }
93:
94: void do_interrupt(int is_hw)
95: {
96: uint32_t sp;
97: uint32_t fmt;
98: uint32_t retaddr;
99: uint32_t vector;
100:
101: fmt = 0;
102: retaddr = env->pc;
103:
104: if (!is_hw) {
105: switch (env->exception_index) {
106: case EXCP_RTE:
107: /* Return from an exception. */
108: do_rte();
109: return;
110: case EXCP_HALT_INSN:
111: if (semihosting_enabled
112: && (env->sr & SR_S) != 0
113: && (env->pc & 3) == 0
114: && lduw_code(env->pc - 4) == 0x4e71
115: && ldl_code(env->pc) == 0x4e7bf000) {
116: env->pc += 4;
117: do_m68k_semihosting(env, env->dregs[0]);
118: return;
119: }
120: env->halted = 1;
121: env->exception_index = EXCP_HLT;
122: cpu_loop_exit();
123: return;
124: }
125: if (env->exception_index >= EXCP_TRAP0
126: && env->exception_index <= EXCP_TRAP15) {
127: /* Move the PC after the trap instruction. */
128: retaddr += 2;
129: }
130: }
131:
132: vector = env->exception_index << 2;
133:
134: sp = env->aregs[7];
135:
136: fmt |= 0x40000000;
137: fmt |= (sp & 3) << 28;
138: fmt |= vector << 16;
139: fmt |= env->sr;
140:
141: env->sr |= SR_S;
142: if (is_hw) {
143: env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
144: env->sr &= ~SR_M;
145: }
146: m68k_switch_sp(env);
147:
148: /* ??? This could cause MMU faults. */
149: sp &= ~3;
150: sp -= 4;
151: stl_kernel(sp, retaddr);
152: sp -= 4;
153: stl_kernel(sp, fmt);
154: env->aregs[7] = sp;
155: /* Jump to vector. */
156: env->pc = ldl_kernel(env->vbr + vector);
157: }
158:
159: #endif
1.1.1.2 ! root 160:
! 161: static void raise_exception(int tt)
! 162: {
! 163: env->exception_index = tt;
! 164: cpu_loop_exit();
! 165: }
! 166:
! 167: void HELPER(raise_exception)(uint32_t tt)
! 168: {
! 169: raise_exception(tt);
! 170: }
! 171:
! 172: void HELPER(divu)(CPUState *env, uint32_t word)
! 173: {
! 174: uint32_t num;
! 175: uint32_t den;
! 176: uint32_t quot;
! 177: uint32_t rem;
! 178: uint32_t flags;
! 179:
! 180: num = env->div1;
! 181: den = env->div2;
! 182: /* ??? This needs to make sure the throwing location is accurate. */
! 183: if (den == 0)
! 184: raise_exception(EXCP_DIV0);
! 185: quot = num / den;
! 186: rem = num % den;
! 187: flags = 0;
! 188: /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses
! 189: the address of a symbol, and gcc knows symbols can't have address
! 190: zero. */
! 191: if (word && quot > 0xffff)
! 192: flags |= CCF_V;
! 193: if (quot == 0)
! 194: flags |= CCF_Z;
! 195: else if ((int32_t)quot < 0)
! 196: flags |= CCF_N;
! 197: env->div1 = quot;
! 198: env->div2 = rem;
! 199: env->cc_dest = flags;
! 200: }
! 201:
! 202: void HELPER(divs)(CPUState *env, uint32_t word)
! 203: {
! 204: int32_t num;
! 205: int32_t den;
! 206: int32_t quot;
! 207: int32_t rem;
! 208: int32_t flags;
! 209:
! 210: num = env->div1;
! 211: den = env->div2;
! 212: if (den == 0)
! 213: raise_exception(EXCP_DIV0);
! 214: quot = num / den;
! 215: rem = num % den;
! 216: flags = 0;
! 217: if (word && quot != (int16_t)quot)
! 218: flags |= CCF_V;
! 219: if (quot == 0)
! 220: flags |= CCF_Z;
! 221: else if (quot < 0)
! 222: flags |= CCF_N;
! 223: env->div1 = quot;
! 224: env->div2 = rem;
! 225: env->cc_dest = flags;
! 226: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.