]> git.proxmox.com Git - qemu.git/blob - target-alpha/op_helper.c
c51b535a7934d59392635f94e8fa71861857a93b
[qemu.git] / target-alpha / op_helper.c
1 /*
2 * Alpha emulation cpu micro-operations helpers for qemu.
3 *
4 * Copyright (c) 2007 Jocelyn Mayer
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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "cpu.h"
21 #include "dyngen-exec.h"
22 #include "host-utils.h"
23 #include "softfloat.h"
24 #include "helper.h"
25 #include "sysemu.h"
26 #include "qemu-timer.h"
27
28 /*****************************************************************************/
29 /* Exceptions processing helpers */
30
31 uint64_t helper_load_pcc (void)
32 {
33 #ifndef CONFIG_USER_ONLY
34 /* In system mode we have access to a decent high-resolution clock.
35 In order to make OS-level time accounting work with the RPCC,
36 present it with a well-timed clock fixed at 250MHz. */
37 return (((uint64_t)env->pcc_ofs << 32)
38 | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
39 #else
40 /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
41 clock ticks. Also, don't bother taking PCC_OFS into account. */
42 return (uint32_t)cpu_get_real_ticks();
43 #endif
44 }
45
46 /* PALcode support special instructions */
47 #if !defined (CONFIG_USER_ONLY)
48 void helper_hw_ret (uint64_t a)
49 {
50 env->pc = a & ~3;
51 env->intr_flag = 0;
52 env->lock_addr = -1;
53 if ((a & 1) == 0) {
54 env->pal_mode = 0;
55 swap_shadow_regs(env);
56 }
57 }
58
59 void helper_tbia(void)
60 {
61 tlb_flush(env, 1);
62 }
63
64 void helper_tbis(uint64_t p)
65 {
66 tlb_flush_page(env, p);
67 }
68
69 void helper_halt(uint64_t restart)
70 {
71 if (restart) {
72 qemu_system_reset_request();
73 } else {
74 qemu_system_shutdown_request();
75 }
76 }
77
78 uint64_t helper_get_time(void)
79 {
80 return qemu_get_clock_ns(rtc_clock);
81 }
82
83 void helper_set_alarm(uint64_t expire)
84 {
85 if (expire) {
86 env->alarm_expire = expire;
87 qemu_mod_timer(env->alarm_timer, expire);
88 } else {
89 qemu_del_timer(env->alarm_timer);
90 }
91 }
92 #endif
93
94 /*****************************************************************************/
95 /* Softmmu support */
96 #if !defined (CONFIG_USER_ONLY)
97 uint64_t helper_ldl_phys(uint64_t p)
98 {
99 return (int32_t)ldl_phys(p);
100 }
101
102 uint64_t helper_ldq_phys(uint64_t p)
103 {
104 return ldq_phys(p);
105 }
106
107 uint64_t helper_ldl_l_phys(uint64_t p)
108 {
109 env->lock_addr = p;
110 return env->lock_value = (int32_t)ldl_phys(p);
111 }
112
113 uint64_t helper_ldq_l_phys(uint64_t p)
114 {
115 env->lock_addr = p;
116 return env->lock_value = ldl_phys(p);
117 }
118
119 void helper_stl_phys(uint64_t p, uint64_t v)
120 {
121 stl_phys(p, v);
122 }
123
124 void helper_stq_phys(uint64_t p, uint64_t v)
125 {
126 stq_phys(p, v);
127 }
128
129 uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
130 {
131 uint64_t ret = 0;
132
133 if (p == env->lock_addr) {
134 int32_t old = ldl_phys(p);
135 if (old == (int32_t)env->lock_value) {
136 stl_phys(p, v);
137 ret = 1;
138 }
139 }
140 env->lock_addr = -1;
141
142 return ret;
143 }
144
145 uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
146 {
147 uint64_t ret = 0;
148
149 if (p == env->lock_addr) {
150 uint64_t old = ldq_phys(p);
151 if (old == env->lock_value) {
152 stq_phys(p, v);
153 ret = 1;
154 }
155 }
156 env->lock_addr = -1;
157
158 return ret;
159 }
160
161 static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
162 int is_user, void *retaddr)
163 {
164 uint64_t pc;
165 uint32_t insn;
166
167 do_restore_state(env, retaddr);
168
169 pc = env->pc;
170 insn = ldl_code(pc);
171
172 env->trap_arg0 = addr;
173 env->trap_arg1 = insn >> 26; /* opcode */
174 env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
175 env->exception_index = EXCP_UNALIGN;
176 env->error_code = 0;
177 cpu_loop_exit(env);
178 }
179
180 void QEMU_NORETURN cpu_unassigned_access(CPUAlphaState *env1,
181 target_phys_addr_t addr, int is_write,
182 int is_exec, int unused, int size)
183 {
184 env = env1;
185 env->trap_arg0 = addr;
186 env->trap_arg1 = is_write;
187 dynamic_excp(env1, GETPC(), EXCP_MCHK, 0);
188 }
189
190 #include "softmmu_exec.h"
191
192 #define MMUSUFFIX _mmu
193 #define ALIGNED_ONLY
194
195 #define SHIFT 0
196 #include "softmmu_template.h"
197
198 #define SHIFT 1
199 #include "softmmu_template.h"
200
201 #define SHIFT 2
202 #include "softmmu_template.h"
203
204 #define SHIFT 3
205 #include "softmmu_template.h"
206
207 /* try to fill the TLB and return an exception if error. If retaddr is
208 NULL, it means that the function was called in C code (i.e. not
209 from generated code or from helper.c) */
210 /* XXX: fix it to restore all registers */
211 void tlb_fill(CPUAlphaState *env1, target_ulong addr, int is_write, int mmu_idx,
212 void *retaddr)
213 {
214 CPUAlphaState *saved_env;
215 int ret;
216
217 saved_env = env;
218 env = env1;
219 ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
220 if (unlikely(ret != 0)) {
221 do_restore_state(env, retaddr);
222 /* Exception index and error code are already set */
223 cpu_loop_exit(env);
224 }
225 env = saved_env;
226 }
227 #endif