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