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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/sysproto.h>
33 #include <sys/sysent.h>
36 #include <sys/mutex.h>
39 #include <vm/vm_kern.h>
40 #include <vm/vm_page.h>
41 #include <vm/vm_map.h>
42 #include <vm/vm_extern.h>
43 #include <vm/vm_object.h>
44 #include <vm/vm_pager.h>
46 #include <machine/fpu.h>
47 #include <machine/inst.h>
48 #include <machine/md_var.h>
49 #include <machine/pcb.h>
50 #include <machine/reg.h>
52 #include <alpha/alpha/ieee_float.h>
54 #define GETREG(regs, i) (*(fp_register_t*) ®s->fpr_regs[i])
55 #define PUTREG(regs, i, v) (*(fp_register_t*) ®s->fpr_regs[i] = v)
57 typedef fp_register_t fp_opcode_handler(union alpha_instruction ins,
61 struct fpreg *fpregs);
63 static fp_register_t fp_add(union alpha_instruction ins,
65 u_int64_t control, u_int64_t *status,
68 return ieee_add(GETREG(fpregs, ins.f_format.fa),
69 GETREG(fpregs, ins.f_format.fb),
70 src, rnd, control, status);
73 static fp_register_t fp_sub(union alpha_instruction ins,
75 u_int64_t control, u_int64_t *status,
78 return ieee_sub(GETREG(fpregs, ins.f_format.fa),
79 GETREG(fpregs, ins.f_format.fb),
80 src, rnd, control, status);
83 static fp_register_t fp_mul(union alpha_instruction ins,
85 u_int64_t control, u_int64_t *status,
88 return ieee_mul(GETREG(fpregs, ins.f_format.fa),
89 GETREG(fpregs, ins.f_format.fb),
90 src, rnd, control, status);
93 static fp_register_t fp_div(union alpha_instruction ins,
95 u_int64_t control, u_int64_t *status,
98 return ieee_div(GETREG(fpregs, ins.f_format.fa),
99 GETREG(fpregs, ins.f_format.fb),
100 src, rnd, control, status);
103 static fp_register_t fp_cmpun(union alpha_instruction ins,
105 u_int64_t control, u_int64_t *status,
106 struct fpreg *fpregs)
108 return ieee_cmpun(GETREG(fpregs, ins.f_format.fa),
109 GETREG(fpregs, ins.f_format.fb),
113 static fp_register_t fp_cmpeq(union alpha_instruction ins,
115 u_int64_t control, u_int64_t *status,
116 struct fpreg *fpregs)
118 return ieee_cmpeq(GETREG(fpregs, ins.f_format.fa),
119 GETREG(fpregs, ins.f_format.fb),
123 static fp_register_t fp_cmplt(union alpha_instruction ins,
125 u_int64_t control, u_int64_t *status,
126 struct fpreg *fpregs)
128 return ieee_cmplt(GETREG(fpregs, ins.f_format.fa),
129 GETREG(fpregs, ins.f_format.fb),
133 static fp_register_t fp_cmple(union alpha_instruction ins,
135 u_int64_t control, u_int64_t *status,
136 struct fpreg *fpregs)
138 return ieee_cmple(GETREG(fpregs, ins.f_format.fa),
139 GETREG(fpregs, ins.f_format.fb),
143 static fp_register_t fp_cvts(union alpha_instruction ins,
145 u_int64_t control, u_int64_t *status,
146 struct fpreg *fpregs)
150 return ieee_convert_T_S(GETREG(fpregs, ins.f_format.fb),
151 rnd, control, status);
154 return ieee_convert_Q_S(GETREG(fpregs, ins.f_format.fb),
155 rnd, control, status);
159 return GETREG(fpregs, ins.f_format.fc);
163 static fp_register_t fp_cvtt(union alpha_instruction ins,
165 u_int64_t control, u_int64_t *status,
166 struct fpreg *fpregs)
170 return ieee_convert_S_T(GETREG(fpregs, ins.f_format.fb),
171 rnd, control, status);
175 return ieee_convert_Q_T(GETREG(fpregs, ins.f_format.fb),
176 rnd, control, status);
181 return GETREG(fpregs, ins.f_format.fc);
185 static fp_register_t fp_cvtq(union alpha_instruction ins,
187 u_int64_t control, u_int64_t *status,
188 struct fpreg *fpregs)
192 return ieee_convert_S_Q(GETREG(fpregs, ins.f_format.fb),
193 rnd, control, status);
197 return ieee_convert_T_Q(GETREG(fpregs, ins.f_format.fb),
198 rnd, control, status);
203 return GETREG(fpregs, ins.f_format.fc);
207 static fp_register_t fp_reserved(union alpha_instruction ins,
209 u_int64_t control, u_int64_t *status,
210 struct fpreg *fpregs)
213 return GETREG(fpregs, ins.f_format.fc);
216 static fp_register_t fp_cvtql(union alpha_instruction ins,
218 u_int64_t control, u_int64_t *status,
219 struct fpreg *fpregs)
222 fp_register_t fb = GETREG(fpregs, ins.f_format.fb);
225 ret.q = ((fb.q & 0xc0000000) << 32 | (fb.q & 0x3fffffff) << 29);
229 static int fp_emulate(union alpha_instruction ins, struct thread *td)
231 u_int64_t control = td->td_pcb->pcb_fp_control;
232 struct fpreg *fpregs = &td->td_pcb->pcb_fp;
233 static fp_opcode_handler *ops[16] = {
244 fp_reserved, /* 10 */
245 fp_reserved, /* 11 */
247 fp_reserved, /* 13 */
252 fp_register_t result;
256 * Only attempt to emulate ieee instructions & integer overflow
258 if ((ins.common.opcode != op_flti) &&
259 (ins.f_format.function != fltl_cvtqlsv)){
260 printf("fp_emulate: unhandled opcode = 0x%x, fun = 0x%x\n",ins.common.opcode,ins.f_format.function);
265 * Dump the float registers into the pcb so we can get at
266 * them. We are potentially going to modify the fp state, so
267 * cancel fpcurproc too.
269 alpha_fpstate_save(td, 1);
272 * Decode and execute the instruction.
274 src = (ins.f_format.function >> 4) & 3;
275 rnd = (ins.f_format.function >> 6) & 3;
277 rnd = (fpregs->fpr_cr >> FPCR_DYN_SHIFT) & 3;
279 if (ins.common.opcode == op_fltl
280 && ins.f_format.function == fltl_cvtqlsv)
281 result = fp_cvtql(ins, src, rnd, control, &status,
284 result = ops[ins.f_format.function & 0xf](ins, src, rnd,
294 /* Record the exception in the software control word. */
295 control |= (status >> IEEE_STATUS_TO_FPCR_SHIFT);
296 td->td_pcb->pcb_fp_control = control;
298 /* Regenerate the control register */
299 fpcr = fpregs->fpr_cr & (FPCR_DYN_MASK | FPCR_STATUS_MASK);
300 fpcr |= ((control & IEEE_STATUS_MASK)
301 << IEEE_STATUS_TO_FPCR_SHIFT);
302 if (!(control & IEEE_TRAP_ENABLE_INV))
304 if (!(control & IEEE_TRAP_ENABLE_DZE))
306 if (!(control & IEEE_TRAP_ENABLE_OVF))
308 if (!(control & IEEE_TRAP_ENABLE_UNF))
310 if (!(control & IEEE_TRAP_ENABLE_INE))
312 if (control & IEEE_STATUS_MASK)
314 fpregs->fpr_cr = fpcr;
316 /* Check the trap enable */
317 if ((control >> IEEE_STATUS_TO_EXCSUM_SHIFT)
318 & (control & IEEE_TRAP_ENABLE_MASK))
322 PUTREG(fpregs, ins.f_format.fc, result);
327 * Attempt to complete a floating point instruction which trapped by
328 * emulating it in software. Return non-zero if the completion was
329 * successful, otherwise zero.
331 int fp_software_completion(u_int64_t regmask, struct thread *td)
333 struct trapframe *frame = td->td_frame;
334 u_int64_t pc = frame->tf_regs[FRAME_PC];
338 * First we must search back through the trap shadow to find which
339 * instruction was responsible for generating the trap.
343 union alpha_instruction ins;
346 * Read the instruction and figure out the destination
347 * register and opcode.
349 error = copyin((caddr_t) pc, &ins, sizeof(ins));
353 switch (ins.common.opcode) {
356 case op_br ... op_bgt:
358 * Condition 6: the trap shadow may not
359 * include any branch instructions. Also,
360 * the trap shadow is bounded by EXCB, TRAPB
366 switch (ins.memory_format.function) {
377 * The first 32 bits of the register mask
378 * represents integer registers which were
379 * modified in the trap shadow.
381 regmask &= ~(1LL << ins.o_format.rc);
388 * The second 32 bits of the register mask
389 * represents float registers which were
390 * modified in the trap shadow.
392 regmask &= ~(1LL << (ins.f_format.fc + 32));
398 * We have traced back through all the
399 * instructions in the trap shadow, so this
400 * must be the one which generated the trap.
402 if (fp_emulate(ins, td)) {
404 * Restore pc to the first instruction
405 * in the trap shadow.
407 frame->tf_regs[FRAME_PC] = pc + 4;