2 * Copyright (c) 1998 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/sysproto.h>
32 #include <sys/sysent.h>
36 #include <vm/vm_kern.h>
37 #include <vm/vm_page.h>
38 #include <vm/vm_map.h>
39 #include <vm/vm_extern.h>
40 #include <vm/vm_object.h>
41 #include <vm/vm_pager.h>
43 #include <machine/inst.h>
44 #include <machine/fpu.h>
45 #include <machine/reg.h>
46 #include <alpha/alpha/ieee_float.h>
48 #define GETREG(regs, i) (*(fp_register_t*) ®s->fpr_regs[i])
49 #define PUTREG(regs, i, v) (*(fp_register_t*) ®s->fpr_regs[i] = v)
51 typedef fp_register_t fp_opcode_handler(union alpha_instruction ins,
55 struct fpreg *fpregs);
57 static fp_register_t fp_add(union alpha_instruction ins,
59 u_int64_t control, u_int64_t *status,
62 return ieee_add(GETREG(fpregs, ins.f_format.fa),
63 GETREG(fpregs, ins.f_format.fb),
64 src, rnd, control, status);
67 static fp_register_t fp_sub(union alpha_instruction ins,
69 u_int64_t control, u_int64_t *status,
72 return ieee_sub(GETREG(fpregs, ins.f_format.fa),
73 GETREG(fpregs, ins.f_format.fb),
74 src, rnd, control, status);
77 static fp_register_t fp_mul(union alpha_instruction ins,
79 u_int64_t control, u_int64_t *status,
82 return ieee_mul(GETREG(fpregs, ins.f_format.fa),
83 GETREG(fpregs, ins.f_format.fb),
84 src, rnd, control, status);
87 static fp_register_t fp_div(union alpha_instruction ins,
89 u_int64_t control, u_int64_t *status,
92 return ieee_div(GETREG(fpregs, ins.f_format.fa),
93 GETREG(fpregs, ins.f_format.fb),
94 src, rnd, control, status);
97 static fp_register_t fp_cmpun(union alpha_instruction ins,
99 u_int64_t control, u_int64_t *status,
100 struct fpreg *fpregs)
102 return ieee_cmpun(GETREG(fpregs, ins.f_format.fa),
103 GETREG(fpregs, ins.f_format.fb),
107 static fp_register_t fp_cmpeq(union alpha_instruction ins,
109 u_int64_t control, u_int64_t *status,
110 struct fpreg *fpregs)
112 return ieee_cmpeq(GETREG(fpregs, ins.f_format.fa),
113 GETREG(fpregs, ins.f_format.fb),
117 static fp_register_t fp_cmplt(union alpha_instruction ins,
119 u_int64_t control, u_int64_t *status,
120 struct fpreg *fpregs)
122 return ieee_cmplt(GETREG(fpregs, ins.f_format.fa),
123 GETREG(fpregs, ins.f_format.fb),
127 static fp_register_t fp_cmple(union alpha_instruction ins,
129 u_int64_t control, u_int64_t *status,
130 struct fpreg *fpregs)
132 return ieee_cmple(GETREG(fpregs, ins.f_format.fa),
133 GETREG(fpregs, ins.f_format.fb),
137 static fp_register_t fp_cvts(union alpha_instruction ins,
139 u_int64_t control, u_int64_t *status,
140 struct fpreg *fpregs)
144 return ieee_convert_T_S(GETREG(fpregs, ins.f_format.fb),
145 rnd, control, status);
148 return ieee_convert_Q_S(GETREG(fpregs, ins.f_format.fb),
149 rnd, control, status);
153 return GETREG(fpregs, ins.f_format.fc);
157 static fp_register_t fp_cvtt(union alpha_instruction ins,
159 u_int64_t control, u_int64_t *status,
160 struct fpreg *fpregs)
164 return ieee_convert_S_T(GETREG(fpregs, ins.f_format.fb),
165 rnd, control, status);
169 return ieee_convert_Q_T(GETREG(fpregs, ins.f_format.fb),
170 rnd, control, status);
175 return GETREG(fpregs, ins.f_format.fc);
179 static fp_register_t fp_cvtq(union alpha_instruction ins,
181 u_int64_t control, u_int64_t *status,
182 struct fpreg *fpregs)
186 return ieee_convert_S_Q(GETREG(fpregs, ins.f_format.fb),
187 rnd, control, status);
191 return ieee_convert_T_Q(GETREG(fpregs, ins.f_format.fb),
192 rnd, control, status);
197 return GETREG(fpregs, ins.f_format.fc);
201 static fp_register_t fp_reserved(union alpha_instruction ins,
203 u_int64_t control, u_int64_t *status,
204 struct fpreg *fpregs)
207 return GETREG(fpregs, ins.f_format.fc);
210 static fp_register_t fp_cvtql(union alpha_instruction ins,
212 u_int64_t control, u_int64_t *status,
213 struct fpreg *fpregs)
216 fp_register_t fb = GETREG(fpregs, ins.f_format.fb);
219 ret.q = ((fb.q & 0xc0000000) << 32 | (fb.q & 0x3fffffff) << 29);
223 static int fp_emulate(union alpha_instruction ins, struct proc *p)
225 u_int64_t control = p->p_addr->u_pcb.pcb_fp_control;
226 struct fpreg *fpregs = &p->p_addr->u_pcb.pcb_fp;
227 static fp_opcode_handler *ops[16] = {
238 fp_reserved, /* 10 */
239 fp_reserved, /* 11 */
241 fp_reserved, /* 13 */
246 fp_register_t result;
250 * Only attempt to emulate ieee instructions & integer overflow
252 if ((ins.common.opcode != op_flti) &&
253 (ins.f_format.function != fltl_cvtqlsv)){
254 printf("fp_emulate: unhandled opcode = 0x%x, fun = 0x%x\n",ins.common.opcode,ins.f_format.function);
259 * Dump the float registers into the pcb so we can get at
260 * them. We are potentially going to modify the fp state, so
261 * cancel fpcurproc too.
263 alpha_fpstate_save(p, 1);
266 * Decode and execute the instruction.
268 src = (ins.f_format.function >> 4) & 3;
269 rnd = (ins.f_format.function >> 6) & 3;
271 rnd = (fpregs->fpr_cr >> FPCR_DYN_SHIFT) & 3;
273 if (ins.common.opcode == op_fltl
274 && ins.f_format.function == fltl_cvtqlsv)
275 result = fp_cvtql(ins, src, rnd, control, &status,
278 result = ops[ins.f_format.function & 0xf](ins, src, rnd,
288 /* Record the exception in the software control word. */
289 control |= (status >> IEEE_STATUS_TO_FPCR_SHIFT);
290 p->p_addr->u_pcb.pcb_fp_control = control;
292 /* Regenerate the control register */
293 fpcr = fpregs->fpr_cr & FPCR_DYN_MASK;
294 fpcr |= ((control & IEEE_STATUS_MASK)
295 << IEEE_STATUS_TO_FPCR_SHIFT);
296 if (!(control & IEEE_TRAP_ENABLE_INV))
298 if (!(control & IEEE_TRAP_ENABLE_DZE))
300 if (!(control & IEEE_TRAP_ENABLE_OVF))
302 if (!(control & IEEE_TRAP_ENABLE_UNF))
304 if (!(control & IEEE_TRAP_ENABLE_INE))
306 if (control & IEEE_STATUS_MASK)
308 fpregs->fpr_cr = fpcr;
310 /* Check the trap enable */
311 if ((control >> IEEE_STATUS_TO_EXCSUM_SHIFT)
312 & (control & IEEE_TRAP_ENABLE_MASK))
316 PUTREG(fpregs, ins.f_format.fc, result);
321 * Attempt to complete a floating point instruction which trapped by
322 * emulating it in software. Return non-zero if the completion was
323 * successful, otherwise zero.
325 int fp_software_completion(u_int64_t regmask, struct proc *p)
327 struct trapframe *frame = p->p_md.md_tf;
328 u_int64_t pc = frame->tf_regs[FRAME_PC];
332 * First we must search back through the trap shadow to find which
333 * instruction was responsible for generating the trap.
337 union alpha_instruction ins;
340 * Read the instruction and figure out the destination
341 * register and opcode.
343 error = copyin((caddr_t) pc, &ins, sizeof(ins));
347 switch (ins.common.opcode) {
350 case op_br ... op_bgt:
352 * Condition 6: the trap shadow may not
353 * include any branch instructions. Also,
354 * the trap shadow is bounded by EXCB, TRAPB
360 switch (ins.memory_format.function) {
371 * The first 32 bits of the register mask
372 * represents integer registers which were
373 * modified in the trap shadow.
375 regmask &= ~(1LL << ins.o_format.rc);
382 * The second 32 bits of the register mask
383 * represents float registers which were
384 * modified in the trap shadow.
386 regmask &= ~(1LL << (ins.f_format.fc + 32));
392 * We have traced back through all the
393 * instructions in the trap shadow, so this
394 * must be the one which generated the trap.
396 if (fp_emulate(ins, p)) {
398 * Restore pc to the first instruction
399 * in the trap shadow.
401 frame->tf_regs[FRAME_PC] = pc + 4;