|
|
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: */
1.1.1.5 root 19: #include "cpu.h"
20: #include "dyngen-exec.h"
1.1.1.2 root 21: #include "helpers.h"
1.1 root 22:
23: #if defined(CONFIG_USER_ONLY)
24:
1.1.1.6 ! root 25: void do_interrupt(CPUM68KState *env1)
1.1.1.4 root 26: {
27: env1->exception_index = -1;
28: }
29:
1.1.1.6 ! root 30: void do_interrupt_m68k_hardirq(CPUM68KState *env1)
1.1 root 31: {
32: }
33:
34: #else
35:
36: extern int semihosting_enabled;
37:
1.1.1.5 root 38: #include "softmmu_exec.h"
39:
1.1 root 40: #define MMUSUFFIX _mmu
41:
42: #define SHIFT 0
43: #include "softmmu_template.h"
44:
45: #define SHIFT 1
46: #include "softmmu_template.h"
47:
48: #define SHIFT 2
49: #include "softmmu_template.h"
50:
51: #define SHIFT 3
52: #include "softmmu_template.h"
53:
54: /* Try to fill the TLB and return an exception if error. If retaddr is
55: NULL, it means that the function was called in C code (i.e. not
56: from generated code or from helper.c) */
57: /* XXX: fix it to restore all registers */
1.1.1.6 ! root 58: void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
! 59: uintptr_t retaddr)
1.1 root 60: {
61: TranslationBlock *tb;
1.1.1.6 ! root 62: CPUM68KState *saved_env;
1.1 root 63: int ret;
64:
65: saved_env = env;
1.1.1.5 root 66: env = env1;
67: ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
1.1.1.2 root 68: if (unlikely(ret)) {
1.1 root 69: if (retaddr) {
70: /* now we have a real cpu fault */
1.1.1.6 ! root 71: tb = tb_find_pc(retaddr);
1.1 root 72: if (tb) {
73: /* the PC is inside the translated code. It means that we have
74: a virtual CPU fault */
1.1.1.6 ! root 75: cpu_restore_state(tb, env, retaddr);
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.6 ! root 162: void do_interrupt(CPUM68KState *env1)
1.1.1.4 root 163: {
1.1.1.6 ! root 164: CPUM68KState *saved_env;
1.1.1.4 root 165:
166: saved_env = env;
167: env = env1;
168: do_interrupt_all(0);
169: env = saved_env;
170: }
171:
1.1.1.6 ! root 172: void do_interrupt_m68k_hardirq(CPUM68KState *env1)
1.1.1.4 root 173: {
1.1.1.6 ! root 174: CPUM68KState *saved_env;
1.1.1.4 root 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:
1.1.1.6 ! root 194: void HELPER(divu)(CPUM68KState *env, uint32_t word)
1.1.1.2 root 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:
1.1.1.6 ! root 224: void HELPER(divs)(CPUM68KState *env, uint32_t word)
1.1.1.2 root 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.