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