pfpsp.s revision 1.4 1 1.1 is #
2 1.4 christos # $NetBSD: pfpsp.s,v 1.4 2005/12/11 12:17:52 christos Exp $
3 1.1 is #
4 1.1 is
5 1.1 is #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 1.1 is # MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
7 1.1 is # M68000 Hi-Performance Microprocessor Division
8 1.1 is # M68060 Software Package Production Release
9 1.1 is #
10 1.1 is # M68060 Software Package Copyright (C) 1993, 1994, 1995, 1996 Motorola Inc.
11 1.1 is # All rights reserved.
12 1.1 is #
13 1.1 is # THE SOFTWARE is provided on an "AS IS" basis and without warranty.
14 1.1 is # To the maximum extent permitted by applicable law,
15 1.1 is # MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
16 1.1 is # INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS
17 1.1 is # FOR A PARTICULAR PURPOSE and any warranty against infringement with
18 1.1 is # regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
19 1.1 is # and any accompanying written materials.
20 1.1 is #
21 1.1 is # To the maximum extent permitted by applicable law,
22 1.1 is # IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
23 1.1 is # (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
24 1.1 is # BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
25 1.1 is # ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
26 1.1 is #
27 1.1 is # Motorola assumes no responsibility for the maintenance and support
28 1.1 is # of the SOFTWARE.
29 1.1 is #
30 1.1 is # You are hereby granted a copyright license to use, modify, and distribute the
31 1.1 is # SOFTWARE so long as this entire notice is retained without alteration
32 1.1 is # in any modified and/or redistributed versions, and that such modified
33 1.1 is # versions are clearly identified as such.
34 1.1 is # No licenses are granted by implication, estoppel or otherwise under any
35 1.1 is # patents or trademarks of Motorola, Inc.
36 1.1 is #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37 1.1 is
38 1.1 is #
39 1.1 is # freal.s:
40 1.1 is # This file is appended to the top of the 060FPSP package
41 1.1 is # and contains the entry points into the package. The user, in
42 1.1 is # effect, branches to one of the branch table entries located
43 1.1 is # after _060FPSP_TABLE.
44 1.1 is # Also, subroutine stubs exist in this file (_fpsp_done for
45 1.1 is # example) that are referenced by the FPSP package itself in order
46 1.1 is # to call a given routine. The stub routine actually performs the
47 1.1 is # callout. The FPSP code does a "bsr" to the stub routine. This
48 1.1 is # extra layer of hierarchy adds a slight performance penalty but
49 1.1 is # it makes the FPSP code easier to read and more mainatinable.
50 1.1 is #
51 1.1 is
52 1.1 is set _off_bsun, 0x00
53 1.1 is set _off_snan, 0x04
54 1.1 is set _off_operr, 0x08
55 1.1 is set _off_ovfl, 0x0c
56 1.1 is set _off_unfl, 0x10
57 1.1 is set _off_dz, 0x14
58 1.1 is set _off_inex, 0x18
59 1.1 is set _off_fline, 0x1c
60 1.1 is set _off_fpu_dis, 0x20
61 1.1 is set _off_trap, 0x24
62 1.1 is set _off_trace, 0x28
63 1.1 is set _off_access, 0x2c
64 1.1 is set _off_done, 0x30
65 1.1 is
66 1.1 is set _off_imr, 0x40
67 1.1 is set _off_dmr, 0x44
68 1.1 is set _off_dmw, 0x48
69 1.1 is set _off_irw, 0x4c
70 1.1 is set _off_irl, 0x50
71 1.1 is set _off_drb, 0x54
72 1.1 is set _off_drw, 0x58
73 1.1 is set _off_drl, 0x5c
74 1.1 is set _off_dwb, 0x60
75 1.1 is set _off_dww, 0x64
76 1.1 is set _off_dwl, 0x68
77 1.1 is
78 1.1 is _060FPSP_TABLE:
79 1.1 is
80 1.1 is ###############################################################
81 1.1 is
82 1.1 is # Here's the table of ENTRY POINTS for those linking the package.
83 1.1 is bra.l _fpsp_snan
84 1.1 is short 0x0000
85 1.1 is bra.l _fpsp_operr
86 1.1 is short 0x0000
87 1.1 is bra.l _fpsp_ovfl
88 1.1 is short 0x0000
89 1.1 is bra.l _fpsp_unfl
90 1.1 is short 0x0000
91 1.1 is bra.l _fpsp_dz
92 1.1 is short 0x0000
93 1.1 is bra.l _fpsp_inex
94 1.1 is short 0x0000
95 1.1 is bra.l _fpsp_fline
96 1.1 is short 0x0000
97 1.1 is bra.l _fpsp_unsupp
98 1.1 is short 0x0000
99 1.1 is bra.l _fpsp_effadd
100 1.1 is short 0x0000
101 1.1 is
102 1.1 is space 56
103 1.1 is
104 1.1 is ###############################################################
105 1.1 is global _fpsp_done
106 1.1 is _fpsp_done:
107 1.1 is mov.l %d0,-(%sp)
108 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
109 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
110 1.1 is mov.l 0x4(%sp),%d0
111 1.1 is rtd &0x4
112 1.1 is
113 1.1 is global _real_ovfl
114 1.1 is _real_ovfl:
115 1.1 is mov.l %d0,-(%sp)
116 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
117 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
118 1.1 is mov.l 0x4(%sp),%d0
119 1.1 is rtd &0x4
120 1.1 is
121 1.1 is global _real_unfl
122 1.1 is _real_unfl:
123 1.1 is mov.l %d0,-(%sp)
124 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
125 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
126 1.1 is mov.l 0x4(%sp),%d0
127 1.1 is rtd &0x4
128 1.1 is
129 1.1 is global _real_inex
130 1.1 is _real_inex:
131 1.1 is mov.l %d0,-(%sp)
132 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
133 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
134 1.1 is mov.l 0x4(%sp),%d0
135 1.1 is rtd &0x4
136 1.1 is
137 1.1 is global _real_bsun
138 1.1 is _real_bsun:
139 1.1 is mov.l %d0,-(%sp)
140 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
141 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
142 1.1 is mov.l 0x4(%sp),%d0
143 1.1 is rtd &0x4
144 1.1 is
145 1.1 is global _real_operr
146 1.1 is _real_operr:
147 1.1 is mov.l %d0,-(%sp)
148 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
149 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
150 1.1 is mov.l 0x4(%sp),%d0
151 1.1 is rtd &0x4
152 1.1 is
153 1.1 is global _real_snan
154 1.1 is _real_snan:
155 1.1 is mov.l %d0,-(%sp)
156 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
157 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
158 1.1 is mov.l 0x4(%sp),%d0
159 1.1 is rtd &0x4
160 1.1 is
161 1.1 is global _real_dz
162 1.1 is _real_dz:
163 1.1 is mov.l %d0,-(%sp)
164 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
165 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
166 1.1 is mov.l 0x4(%sp),%d0
167 1.1 is rtd &0x4
168 1.1 is
169 1.1 is global _real_fline
170 1.1 is _real_fline:
171 1.1 is mov.l %d0,-(%sp)
172 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
173 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
174 1.1 is mov.l 0x4(%sp),%d0
175 1.1 is rtd &0x4
176 1.1 is
177 1.1 is global _real_fpu_disabled
178 1.1 is _real_fpu_disabled:
179 1.1 is mov.l %d0,-(%sp)
180 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
181 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
182 1.1 is mov.l 0x4(%sp),%d0
183 1.1 is rtd &0x4
184 1.1 is
185 1.1 is global _real_trap
186 1.1 is _real_trap:
187 1.1 is mov.l %d0,-(%sp)
188 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
189 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
190 1.1 is mov.l 0x4(%sp),%d0
191 1.1 is rtd &0x4
192 1.1 is
193 1.1 is global _real_trace
194 1.1 is _real_trace:
195 1.1 is mov.l %d0,-(%sp)
196 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
197 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
198 1.1 is mov.l 0x4(%sp),%d0
199 1.1 is rtd &0x4
200 1.1 is
201 1.1 is global _real_access
202 1.1 is _real_access:
203 1.1 is mov.l %d0,-(%sp)
204 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
205 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
206 1.1 is mov.l 0x4(%sp),%d0
207 1.1 is rtd &0x4
208 1.1 is
209 1.1 is #######################################
210 1.1 is
211 1.1 is global _imem_read
212 1.1 is _imem_read:
213 1.1 is mov.l %d0,-(%sp)
214 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
215 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
216 1.1 is mov.l 0x4(%sp),%d0
217 1.1 is rtd &0x4
218 1.1 is
219 1.1 is global _dmem_read
220 1.1 is _dmem_read:
221 1.1 is mov.l %d0,-(%sp)
222 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
223 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
224 1.1 is mov.l 0x4(%sp),%d0
225 1.1 is rtd &0x4
226 1.1 is
227 1.1 is global _dmem_write
228 1.1 is _dmem_write:
229 1.1 is mov.l %d0,-(%sp)
230 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
231 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
232 1.1 is mov.l 0x4(%sp),%d0
233 1.1 is rtd &0x4
234 1.1 is
235 1.1 is global _imem_read_word
236 1.1 is _imem_read_word:
237 1.1 is mov.l %d0,-(%sp)
238 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
239 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
240 1.1 is mov.l 0x4(%sp),%d0
241 1.1 is rtd &0x4
242 1.1 is
243 1.1 is global _imem_read_long
244 1.1 is _imem_read_long:
245 1.1 is mov.l %d0,-(%sp)
246 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
247 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
248 1.1 is mov.l 0x4(%sp),%d0
249 1.1 is rtd &0x4
250 1.1 is
251 1.1 is global _dmem_read_byte
252 1.1 is _dmem_read_byte:
253 1.1 is mov.l %d0,-(%sp)
254 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
255 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
256 1.1 is mov.l 0x4(%sp),%d0
257 1.1 is rtd &0x4
258 1.1 is
259 1.1 is global _dmem_read_word
260 1.1 is _dmem_read_word:
261 1.1 is mov.l %d0,-(%sp)
262 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
263 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
264 1.1 is mov.l 0x4(%sp),%d0
265 1.1 is rtd &0x4
266 1.1 is
267 1.1 is global _dmem_read_long
268 1.1 is _dmem_read_long:
269 1.1 is mov.l %d0,-(%sp)
270 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
271 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
272 1.1 is mov.l 0x4(%sp),%d0
273 1.1 is rtd &0x4
274 1.1 is
275 1.1 is global _dmem_write_byte
276 1.1 is _dmem_write_byte:
277 1.1 is mov.l %d0,-(%sp)
278 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
279 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
280 1.1 is mov.l 0x4(%sp),%d0
281 1.1 is rtd &0x4
282 1.1 is
283 1.1 is global _dmem_write_word
284 1.1 is _dmem_write_word:
285 1.1 is mov.l %d0,-(%sp)
286 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
287 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
288 1.1 is mov.l 0x4(%sp),%d0
289 1.1 is rtd &0x4
290 1.1 is
291 1.1 is global _dmem_write_long
292 1.1 is _dmem_write_long:
293 1.1 is mov.l %d0,-(%sp)
294 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
295 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
296 1.1 is mov.l 0x4(%sp),%d0
297 1.1 is rtd &0x4
298 1.1 is
299 1.1 is #
300 1.1 is # This file contains a set of define statements for constants
301 1.1 is # in order to promote readability within the corecode itself.
302 1.1 is #
303 1.1 is
304 1.1 is set LOCAL_SIZE, 192 # stack frame size(bytes)
305 1.1 is set LV, -LOCAL_SIZE # stack offset
306 1.1 is
307 1.1 is set EXC_SR, 0x4 # stack status register
308 1.1 is set EXC_PC, 0x6 # stack pc
309 1.1 is set EXC_VOFF, 0xa # stacked vector offset
310 1.1 is set EXC_EA, 0xc # stacked <ea>
311 1.1 is
312 1.1 is set EXC_FP, 0x0 # frame pointer
313 1.1 is
314 1.1 is set EXC_AREGS, -68 # offset of all address regs
315 1.1 is set EXC_DREGS, -100 # offset of all data regs
316 1.1 is set EXC_FPREGS, -36 # offset of all fp regs
317 1.1 is
318 1.1 is set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7
319 1.1 is set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7
320 1.1 is set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6
321 1.1 is set EXC_A5, EXC_AREGS+(5*4)
322 1.1 is set EXC_A4, EXC_AREGS+(4*4)
323 1.1 is set EXC_A3, EXC_AREGS+(3*4)
324 1.1 is set EXC_A2, EXC_AREGS+(2*4)
325 1.1 is set EXC_A1, EXC_AREGS+(1*4)
326 1.1 is set EXC_A0, EXC_AREGS+(0*4)
327 1.1 is set EXC_D7, EXC_DREGS+(7*4)
328 1.1 is set EXC_D6, EXC_DREGS+(6*4)
329 1.1 is set EXC_D5, EXC_DREGS+(5*4)
330 1.1 is set EXC_D4, EXC_DREGS+(4*4)
331 1.1 is set EXC_D3, EXC_DREGS+(3*4)
332 1.1 is set EXC_D2, EXC_DREGS+(2*4)
333 1.1 is set EXC_D1, EXC_DREGS+(1*4)
334 1.1 is set EXC_D0, EXC_DREGS+(0*4)
335 1.1 is
336 1.1 is set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0
337 1.1 is set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1
338 1.1 is set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used)
339 1.1 is
340 1.1 is set FP_SCR1, LV+80 # fp scratch 1
341 1.1 is set FP_SCR1_EX, FP_SCR1+0
342 1.1 is set FP_SCR1_SGN, FP_SCR1+2
343 1.1 is set FP_SCR1_HI, FP_SCR1+4
344 1.1 is set FP_SCR1_LO, FP_SCR1+8
345 1.1 is
346 1.1 is set FP_SCR0, LV+68 # fp scratch 0
347 1.1 is set FP_SCR0_EX, FP_SCR0+0
348 1.1 is set FP_SCR0_SGN, FP_SCR0+2
349 1.1 is set FP_SCR0_HI, FP_SCR0+4
350 1.1 is set FP_SCR0_LO, FP_SCR0+8
351 1.1 is
352 1.1 is set FP_DST, LV+56 # fp destination operand
353 1.1 is set FP_DST_EX, FP_DST+0
354 1.1 is set FP_DST_SGN, FP_DST+2
355 1.1 is set FP_DST_HI, FP_DST+4
356 1.1 is set FP_DST_LO, FP_DST+8
357 1.1 is
358 1.1 is set FP_SRC, LV+44 # fp source operand
359 1.1 is set FP_SRC_EX, FP_SRC+0
360 1.1 is set FP_SRC_SGN, FP_SRC+2
361 1.1 is set FP_SRC_HI, FP_SRC+4
362 1.1 is set FP_SRC_LO, FP_SRC+8
363 1.1 is
364 1.1 is set USER_FPIAR, LV+40 # FP instr address register
365 1.1 is
366 1.1 is set USER_FPSR, LV+36 # FP status register
367 1.1 is set FPSR_CC, USER_FPSR+0 # FPSR condition codes
368 1.1 is set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte
369 1.1 is set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte
370 1.1 is set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte
371 1.1 is
372 1.1 is set USER_FPCR, LV+32 # FP control register
373 1.1 is set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable
374 1.1 is set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control
375 1.1 is
376 1.1 is set L_SCR3, LV+28 # integer scratch 3
377 1.1 is set L_SCR2, LV+24 # integer scratch 2
378 1.1 is set L_SCR1, LV+20 # integer scratch 1
379 1.1 is
380 1.1 is set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst)
381 1.1 is
382 1.1 is set EXC_TEMP2, LV+24 # temporary space
383 1.1 is set EXC_TEMP, LV+16 # temporary space
384 1.1 is
385 1.1 is set DTAG, LV+15 # destination operand type
386 1.1 is set STAG, LV+14 # source operand type
387 1.1 is
388 1.1 is set SPCOND_FLG, LV+10 # flag: special case (see below)
389 1.1 is
390 1.1 is set EXC_CC, LV+8 # saved condition codes
391 1.1 is set EXC_EXTWPTR, LV+4 # saved current PC (active)
392 1.1 is set EXC_EXTWORD, LV+2 # saved extension word
393 1.1 is set EXC_CMDREG, LV+2 # saved extension word
394 1.1 is set EXC_OPWORD, LV+0 # saved operation word
395 1.1 is
396 1.1 is ################################
397 1.1 is
398 1.1 is # Helpful macros
399 1.1 is
400 1.1 is set FTEMP, 0 # offsets within an
401 1.1 is set FTEMP_EX, 0 # extended precision
402 1.1 is set FTEMP_SGN, 2 # value saved in memory.
403 1.1 is set FTEMP_HI, 4
404 1.1 is set FTEMP_LO, 8
405 1.1 is set FTEMP_GRS, 12
406 1.1 is
407 1.1 is set LOCAL, 0 # offsets within an
408 1.1 is set LOCAL_EX, 0 # extended precision
409 1.1 is set LOCAL_SGN, 2 # value saved in memory.
410 1.1 is set LOCAL_HI, 4
411 1.1 is set LOCAL_LO, 8
412 1.1 is set LOCAL_GRS, 12
413 1.1 is
414 1.1 is set DST, 0 # offsets within an
415 1.1 is set DST_EX, 0 # extended precision
416 1.1 is set DST_HI, 4 # value saved in memory.
417 1.1 is set DST_LO, 8
418 1.1 is
419 1.1 is set SRC, 0 # offsets within an
420 1.1 is set SRC_EX, 0 # extended precision
421 1.1 is set SRC_HI, 4 # value saved in memory.
422 1.1 is set SRC_LO, 8
423 1.1 is
424 1.1 is set SGL_LO, 0x3f81 # min sgl prec exponent
425 1.1 is set SGL_HI, 0x407e # max sgl prec exponent
426 1.1 is set DBL_LO, 0x3c01 # min dbl prec exponent
427 1.1 is set DBL_HI, 0x43fe # max dbl prec exponent
428 1.1 is set EXT_LO, 0x0 # min ext prec exponent
429 1.1 is set EXT_HI, 0x7ffe # max ext prec exponent
430 1.1 is
431 1.1 is set EXT_BIAS, 0x3fff # extended precision bias
432 1.1 is set SGL_BIAS, 0x007f # single precision bias
433 1.1 is set DBL_BIAS, 0x03ff # double precision bias
434 1.1 is
435 1.1 is set NORM, 0x00 # operand type for STAG/DTAG
436 1.1 is set ZERO, 0x01 # operand type for STAG/DTAG
437 1.1 is set INF, 0x02 # operand type for STAG/DTAG
438 1.1 is set QNAN, 0x03 # operand type for STAG/DTAG
439 1.1 is set DENORM, 0x04 # operand type for STAG/DTAG
440 1.1 is set SNAN, 0x05 # operand type for STAG/DTAG
441 1.1 is set UNNORM, 0x06 # operand type for STAG/DTAG
442 1.1 is
443 1.1 is ##################
444 1.1 is # FPSR/FPCR bits #
445 1.1 is ##################
446 1.1 is set neg_bit, 0x3 # negative result
447 1.1 is set z_bit, 0x2 # zero result
448 1.1 is set inf_bit, 0x1 # infinite result
449 1.1 is set nan_bit, 0x0 # NAN result
450 1.1 is
451 1.1 is set q_sn_bit, 0x7 # sign bit of quotient byte
452 1.1 is
453 1.1 is set bsun_bit, 7 # branch on unordered
454 1.1 is set snan_bit, 6 # signalling NAN
455 1.1 is set operr_bit, 5 # operand error
456 1.1 is set ovfl_bit, 4 # overflow
457 1.1 is set unfl_bit, 3 # underflow
458 1.1 is set dz_bit, 2 # divide by zero
459 1.1 is set inex2_bit, 1 # inexact result 2
460 1.1 is set inex1_bit, 0 # inexact result 1
461 1.1 is
462 1.1 is set aiop_bit, 7 # accrued inexact operation bit
463 1.1 is set aovfl_bit, 6 # accrued overflow bit
464 1.1 is set aunfl_bit, 5 # accrued underflow bit
465 1.1 is set adz_bit, 4 # accrued dz bit
466 1.1 is set ainex_bit, 3 # accrued inexact bit
467 1.1 is
468 1.1 is #############################
469 1.1 is # FPSR individual bit masks #
470 1.1 is #############################
471 1.1 is set neg_mask, 0x08000000 # negative bit mask (lw)
472 1.1 is set inf_mask, 0x02000000 # infinity bit mask (lw)
473 1.1 is set z_mask, 0x04000000 # zero bit mask (lw)
474 1.1 is set nan_mask, 0x01000000 # nan bit mask (lw)
475 1.1 is
476 1.1 is set neg_bmask, 0x08 # negative bit mask (byte)
477 1.1 is set inf_bmask, 0x02 # infinity bit mask (byte)
478 1.1 is set z_bmask, 0x04 # zero bit mask (byte)
479 1.1 is set nan_bmask, 0x01 # nan bit mask (byte)
480 1.1 is
481 1.1 is set bsun_mask, 0x00008000 # bsun exception mask
482 1.1 is set snan_mask, 0x00004000 # snan exception mask
483 1.1 is set operr_mask, 0x00002000 # operr exception mask
484 1.1 is set ovfl_mask, 0x00001000 # overflow exception mask
485 1.1 is set unfl_mask, 0x00000800 # underflow exception mask
486 1.1 is set dz_mask, 0x00000400 # dz exception mask
487 1.1 is set inex2_mask, 0x00000200 # inex2 exception mask
488 1.1 is set inex1_mask, 0x00000100 # inex1 exception mask
489 1.1 is
490 1.1 is set aiop_mask, 0x00000080 # accrued illegal operation
491 1.1 is set aovfl_mask, 0x00000040 # accrued overflow
492 1.1 is set aunfl_mask, 0x00000020 # accrued underflow
493 1.1 is set adz_mask, 0x00000010 # accrued divide by zero
494 1.1 is set ainex_mask, 0x00000008 # accrued inexact
495 1.1 is
496 1.1 is ######################################
497 1.1 is # FPSR combinations used in the FPSP #
498 1.1 is ######################################
499 1.1 is set dzinf_mask, inf_mask+dz_mask+adz_mask
500 1.1 is set opnan_mask, nan_mask+operr_mask+aiop_mask
501 1.1 is set nzi_mask, 0x01ffffff #clears N, Z, and I
502 1.1 is set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask
503 1.1 is set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask
504 1.1 is set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
505 1.1 is set inx1a_mask, inex1_mask+ainex_mask
506 1.1 is set inx2a_mask, inex2_mask+ainex_mask
507 1.1 is set snaniop_mask, nan_mask+snan_mask+aiop_mask
508 1.1 is set snaniop2_mask, snan_mask+aiop_mask
509 1.1 is set naniop_mask, nan_mask+aiop_mask
510 1.1 is set neginf_mask, neg_mask+inf_mask
511 1.1 is set infaiop_mask, inf_mask+aiop_mask
512 1.1 is set negz_mask, neg_mask+z_mask
513 1.1 is set opaop_mask, operr_mask+aiop_mask
514 1.1 is set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask
515 1.1 is set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask
516 1.1 is
517 1.1 is #########
518 1.1 is # misc. #
519 1.1 is #########
520 1.1 is set rnd_stky_bit, 29 # stky bit pos in longword
521 1.1 is
522 1.1 is set sign_bit, 0x7 # sign bit
523 1.1 is set signan_bit, 0x6 # signalling nan bit
524 1.1 is
525 1.1 is set sgl_thresh, 0x3f81 # minimum sgl exponent
526 1.1 is set dbl_thresh, 0x3c01 # minimum dbl exponent
527 1.1 is
528 1.1 is set x_mode, 0x0 # extended precision
529 1.1 is set s_mode, 0x4 # single precision
530 1.1 is set d_mode, 0x8 # double precision
531 1.1 is
532 1.1 is set rn_mode, 0x0 # round-to-nearest
533 1.1 is set rz_mode, 0x1 # round-to-zero
534 1.1 is set rm_mode, 0x2 # round-tp-minus-infinity
535 1.1 is set rp_mode, 0x3 # round-to-plus-infinity
536 1.1 is
537 1.1 is set mantissalen, 64 # length of mantissa in bits
538 1.1 is
539 1.1 is set BYTE, 1 # len(byte) == 1 byte
540 1.1 is set WORD, 2 # len(word) == 2 bytes
541 1.1 is set LONG, 4 # len(longword) == 2 bytes
542 1.1 is
543 1.1 is set BSUN_VEC, 0xc0 # bsun vector offset
544 1.1 is set INEX_VEC, 0xc4 # inexact vector offset
545 1.1 is set DZ_VEC, 0xc8 # dz vector offset
546 1.1 is set UNFL_VEC, 0xcc # unfl vector offset
547 1.1 is set OPERR_VEC, 0xd0 # operr vector offset
548 1.1 is set OVFL_VEC, 0xd4 # ovfl vector offset
549 1.1 is set SNAN_VEC, 0xd8 # snan vector offset
550 1.1 is
551 1.1 is ###########################
552 1.1 is # SPecial CONDition FLaGs #
553 1.1 is ###########################
554 1.1 is set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception
555 1.1 is set fbsun_flg, 0x02 # flag bit: bsun exception
556 1.1 is set mia7_flg, 0x04 # flag bit: (a7)+ <ea>
557 1.1 is set mda7_flg, 0x08 # flag bit: -(a7) <ea>
558 1.1 is set fmovm_flg, 0x40 # flag bit: fmovm instruction
559 1.1 is set immed_flg, 0x80 # flag bit: &<data> <ea>
560 1.1 is
561 1.1 is set ftrapcc_bit, 0x0
562 1.1 is set fbsun_bit, 0x1
563 1.1 is set mia7_bit, 0x2
564 1.1 is set mda7_bit, 0x3
565 1.1 is set immed_bit, 0x7
566 1.1 is
567 1.1 is ##################################
568 1.1 is # TRANSCENDENTAL "LAST-OP" FLAGS #
569 1.1 is ##################################
570 1.1 is set FMUL_OP, 0x0 # fmul instr performed last
571 1.1 is set FDIV_OP, 0x1 # fdiv performed last
572 1.1 is set FADD_OP, 0x2 # fadd performed last
573 1.1 is set FMOV_OP, 0x3 # fmov performed last
574 1.1 is
575 1.1 is #############
576 1.1 is # CONSTANTS #
577 1.1 is #############
578 1.1 is T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD
579 1.1 is T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL
580 1.1 is
581 1.1 is PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000
582 1.1 is PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
583 1.1 is
584 1.1 is TWOBYPI:
585 1.1 is long 0x3FE45F30,0x6DC9C883
586 1.1 is
587 1.1 is #########################################################################
588 1.1 is # XDEF **************************************************************** #
589 1.1 is # _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. #
590 1.1 is # #
591 1.1 is # This handler should be the first code executed upon taking the #
592 1.1 is # FP Overflow exception in an operating system. #
593 1.1 is # #
594 1.1 is # XREF **************************************************************** #
595 1.1 is # _imem_read_long() - read instruction longword #
596 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
597 1.1 is # set_tag_x() - determine optype of src/dst operands #
598 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile #
599 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO #
600 1.1 is # load_fpn2() - load dst operand from FP regfile #
601 1.1 is # fout() - emulate an opclass 3 instruction #
602 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 #
603 1.1 is # _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
604 1.1 is # _real_ovfl() - "callout" for Overflow exception enabled code #
605 1.1 is # _real_inex() - "callout" for Inexact exception enabled code #
606 1.1 is # _real_trace() - "callout" for Trace exception code #
607 1.1 is # #
608 1.1 is # INPUT *************************************************************** #
609 1.1 is # - The system stack contains the FP Ovfl exception stack frame #
610 1.1 is # - The fsave frame contains the source operand #
611 1.1 is # #
612 1.1 is # OUTPUT ************************************************************** #
613 1.1 is # Overflow Exception enabled: #
614 1.1 is # - The system stack is unchanged #
615 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 #
616 1.1 is # Overflow Exception disabled: #
617 1.1 is # - The system stack is unchanged #
618 1.1 is # - The "exception present" flag in the fsave frame is cleared #
619 1.1 is # #
620 1.1 is # ALGORITHM *********************************************************** #
621 1.1 is # On the 060, if an FP overflow is present as the result of any #
622 1.1 is # instruction, the 060 will take an overflow exception whether the #
623 1.1 is # exception is enabled or disabled in the FPCR. For the disabled case, #
624 1.1 is # This handler emulates the instruction to determine what the correct #
625 1.1 is # default result should be for the operation. This default result is #
626 1.1 is # then stored in either the FP regfile, data regfile, or memory. #
627 1.1 is # Finally, the handler exits through the "callout" _fpsp_done() #
628 1.1 is # denoting that no exceptional conditions exist within the machine. #
629 1.1 is # If the exception is enabled, then this handler must create the #
630 1.1 is # exceptional operand and plave it in the fsave state frame, and store #
631 1.1 is # the default result (only if the instruction is opclass 3). For #
632 1.1 is # exceptions enabled, this handler must exit through the "callout" #
633 1.1 is # _real_ovfl() so that the operating system enabled overflow handler #
634 1.1 is # can handle this case. #
635 1.1 is # Two other conditions exist. First, if overflow was disabled #
636 1.1 is # but the inexact exception was enabled, this handler must exit #
637 1.1 is # through the "callout" _real_inex() regardless of whether the result #
638 1.1 is # was inexact. #
639 1.1 is # Also, in the case of an opclass three instruction where #
640 1.1 is # overflow was disabled and the trace exception was enabled, this #
641 1.1 is # handler must exit through the "callout" _real_trace(). #
642 1.1 is # #
643 1.1 is #########################################################################
644 1.1 is
645 1.1 is global _fpsp_ovfl
646 1.1 is _fpsp_ovfl:
647 1.1 is
648 1.1 is #$# sub.l &24,%sp # make room for src/dst
649 1.1 is
650 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
651 1.1 is
652 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
653 1.1 is
654 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
655 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
656 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
657 1.1 is
658 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
659 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
660 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
661 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
662 1.1 is bsr.l _imem_read_long # fetch the instruction words
663 1.1 is mov.l %d0,EXC_OPWORD(%a6)
664 1.1 is
665 1.1 is ##############################################################################
666 1.1 is
667 1.1 is btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
668 1.1 is bne.w fovfl_out
669 1.1 is
670 1.1 is
671 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
672 1.1 is bsr.l fix_skewed_ops # fix src op
673 1.1 is
674 1.1 is # since, I believe, only NORMs and DENORMs can come through here,
675 1.1 is # maybe we can avoid the subroutine call.
676 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
677 1.1 is bsr.l set_tag_x # tag the operand type
678 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM
679 1.1 is
680 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations
681 1.1 is # that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
682 1.1 is # will never take this exception.
683 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
684 1.1 is beq.b fovfl_extract # monadic
685 1.1 is
686 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
687 1.1 is bsr.l load_fpn2 # load dst into FP_DST
688 1.1 is
689 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
690 1.1 is bsr.l set_tag_x # tag the operand type
691 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
692 1.1 is bne.b fovfl_op2_done # no
693 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
694 1.1 is fovfl_op2_done:
695 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag
696 1.1 is
697 1.1 is fovfl_extract:
698 1.1 is
699 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
700 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
701 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
702 1.1 is #$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
703 1.1 is #$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
704 1.1 is #$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
705 1.1 is
706 1.1 is clr.l %d0
707 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
708 1.1 is
709 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1
710 1.1 is andi.w &0x007f,%d1 # extract extension
711 1.1 is
712 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
713 1.1 is
714 1.1 is fmov.l &0x0,%fpcr # zero current control regs
715 1.1 is fmov.l &0x0,%fpsr
716 1.1 is
717 1.1 is lea FP_SRC(%a6),%a0
718 1.1 is lea FP_DST(%a6),%a1
719 1.1 is
720 1.1 is # maybe we can make these entry points ONLY the OVFL entry points of each routine.
721 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
722 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
723 1.1 is
724 1.1 is # the operation has been emulated. the result is in fp0.
725 1.1 is # the EXOP, if an exception occurred, is in fp1.
726 1.1 is # we must save the default result regardless of whether
727 1.1 is # traps are enabled or disabled.
728 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0
729 1.1 is bsr.l store_fpreg
730 1.1 is
731 1.1 is # the exceptional possibilities we have left ourselves with are ONLY overflow
732 1.1 is # and inexact. and, the inexact is such that overflow occurred and was disabled
733 1.1 is # but inexact was enabled.
734 1.1 is btst &ovfl_bit,FPCR_ENABLE(%a6)
735 1.1 is bne.b fovfl_ovfl_on
736 1.1 is
737 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6)
738 1.1 is bne.b fovfl_inex_on
739 1.1 is
740 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
741 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
742 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
743 1.1 is
744 1.1 is unlk %a6
745 1.1 is #$# add.l &24,%sp
746 1.1 is bra.l _fpsp_done
747 1.1 is
748 1.1 is # overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
749 1.1 is # in fp1. now, simply jump to _real_ovfl()!
750 1.1 is fovfl_ovfl_on:
751 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
752 1.1 is
753 1.1 is mov.w &0xe005,2+FP_SRC(%a6) # save exc status
754 1.1 is
755 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
756 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
757 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
758 1.1 is
759 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
760 1.1 is
761 1.1 is unlk %a6
762 1.1 is
763 1.1 is bra.l _real_ovfl
764 1.1 is
765 1.1 is # overflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
766 1.1 is # we must jump to real_inex().
767 1.1 is fovfl_inex_on:
768 1.1 is
769 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
770 1.1 is
771 1.1 is mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
772 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # save exc status
773 1.1 is
774 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
775 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
776 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
777 1.1 is
778 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
779 1.1 is
780 1.1 is unlk %a6
781 1.1 is
782 1.1 is bra.l _real_inex
783 1.1 is
784 1.1 is ########################################################################
785 1.1 is fovfl_out:
786 1.1 is
787 1.1 is
788 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
789 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
790 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
791 1.1 is
792 1.1 is # the src operand is definitely a NORM(!), so tag it as such
793 1.1 is mov.b &NORM,STAG(%a6) # set src optype tag
794 1.1 is
795 1.1 is clr.l %d0
796 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
797 1.1 is
798 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
799 1.1 is
800 1.1 is fmov.l &0x0,%fpcr # zero current control regs
801 1.1 is fmov.l &0x0,%fpsr
802 1.1 is
803 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand
804 1.1 is
805 1.1 is bsr.l fout
806 1.1 is
807 1.1 is btst &ovfl_bit,FPCR_ENABLE(%a6)
808 1.1 is bne.w fovfl_ovfl_on
809 1.1 is
810 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6)
811 1.1 is bne.w fovfl_inex_on
812 1.1 is
813 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
814 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
815 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
816 1.1 is
817 1.1 is unlk %a6
818 1.1 is #$# add.l &24,%sp
819 1.1 is
820 1.1 is btst &0x7,(%sp) # is trace on?
821 1.1 is beq.l _fpsp_done # no
822 1.1 is
823 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
824 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
825 1.1 is bra.l _real_trace
826 1.1 is
827 1.1 is #########################################################################
828 1.1 is # XDEF **************************************************************** #
829 1.1 is # _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. #
830 1.1 is # #
831 1.1 is # This handler should be the first code executed upon taking the #
832 1.1 is # FP Underflow exception in an operating system. #
833 1.1 is # #
834 1.1 is # XREF **************************************************************** #
835 1.1 is # _imem_read_long() - read instruction longword #
836 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
837 1.1 is # set_tag_x() - determine optype of src/dst operands #
838 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile #
839 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO #
840 1.1 is # load_fpn2() - load dst operand from FP regfile #
841 1.1 is # fout() - emulate an opclass 3 instruction #
842 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 #
843 1.1 is # _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
844 1.1 is # _real_ovfl() - "callout" for Overflow exception enabled code #
845 1.1 is # _real_inex() - "callout" for Inexact exception enabled code #
846 1.1 is # _real_trace() - "callout" for Trace exception code #
847 1.1 is # #
848 1.1 is # INPUT *************************************************************** #
849 1.1 is # - The system stack contains the FP Unfl exception stack frame #
850 1.1 is # - The fsave frame contains the source operand #
851 1.1 is # #
852 1.1 is # OUTPUT ************************************************************** #
853 1.1 is # Underflow Exception enabled: #
854 1.1 is # - The system stack is unchanged #
855 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 #
856 1.1 is # Underflow Exception disabled: #
857 1.1 is # - The system stack is unchanged #
858 1.1 is # - The "exception present" flag in the fsave frame is cleared #
859 1.1 is # #
860 1.1 is # ALGORITHM *********************************************************** #
861 1.1 is # On the 060, if an FP underflow is present as the result of any #
862 1.1 is # instruction, the 060 will take an underflow exception whether the #
863 1.1 is # exception is enabled or disabled in the FPCR. For the disabled case, #
864 1.1 is # This handler emulates the instruction to determine what the correct #
865 1.1 is # default result should be for the operation. This default result is #
866 1.1 is # then stored in either the FP regfile, data regfile, or memory. #
867 1.1 is # Finally, the handler exits through the "callout" _fpsp_done() #
868 1.1 is # denoting that no exceptional conditions exist within the machine. #
869 1.1 is # If the exception is enabled, then this handler must create the #
870 1.1 is # exceptional operand and plave it in the fsave state frame, and store #
871 1.1 is # the default result (only if the instruction is opclass 3). For #
872 1.1 is # exceptions enabled, this handler must exit through the "callout" #
873 1.1 is # _real_unfl() so that the operating system enabled overflow handler #
874 1.1 is # can handle this case. #
875 1.1 is # Two other conditions exist. First, if underflow was disabled #
876 1.1 is # but the inexact exception was enabled and the result was inexact, #
877 1.1 is # this handler must exit through the "callout" _real_inex(). #
878 1.1 is # was inexact. #
879 1.1 is # Also, in the case of an opclass three instruction where #
880 1.1 is # underflow was disabled and the trace exception was enabled, this #
881 1.1 is # handler must exit through the "callout" _real_trace(). #
882 1.1 is # #
883 1.1 is #########################################################################
884 1.1 is
885 1.1 is global _fpsp_unfl
886 1.1 is _fpsp_unfl:
887 1.1 is
888 1.1 is #$# sub.l &24,%sp # make room for src/dst
889 1.1 is
890 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
891 1.1 is
892 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
893 1.1 is
894 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
895 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
896 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
897 1.1 is
898 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
899 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
900 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
901 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
902 1.1 is bsr.l _imem_read_long # fetch the instruction words
903 1.1 is mov.l %d0,EXC_OPWORD(%a6)
904 1.1 is
905 1.1 is ##############################################################################
906 1.1 is
907 1.1 is btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
908 1.1 is bne.w funfl_out
909 1.1 is
910 1.1 is
911 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
912 1.1 is bsr.l fix_skewed_ops # fix src op
913 1.1 is
914 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
915 1.1 is bsr.l set_tag_x # tag the operand type
916 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM
917 1.1 is
918 1.1 is # bit five of the fp ext word separates the monadic and dyadic operations
919 1.1 is # that can pass through fpsp_unfl(). remember that fcmp, and ftst
920 1.1 is # will never take this exception.
921 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic?
922 1.1 is beq.b funfl_extract # monadic
923 1.1 is
924 1.1 is # now, what's left that's not dyadic is fsincos. we can distinguish it
925 1.1 is # from all dyadics by the '0110xxx pattern
926 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is op an fsincos?
927 1.1 is bne.b funfl_extract # yes
928 1.1 is
929 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
930 1.1 is bsr.l load_fpn2 # load dst into FP_DST
931 1.1 is
932 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
933 1.1 is bsr.l set_tag_x # tag the operand type
934 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
935 1.1 is bne.b funfl_op2_done # no
936 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
937 1.1 is funfl_op2_done:
938 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag
939 1.1 is
940 1.1 is funfl_extract:
941 1.1 is
942 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
943 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
944 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
945 1.1 is #$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
946 1.1 is #$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
947 1.1 is #$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
948 1.1 is
949 1.1 is clr.l %d0
950 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
951 1.1 is
952 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1
953 1.1 is andi.w &0x007f,%d1 # extract extension
954 1.1 is
955 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6)
956 1.1 is
957 1.1 is fmov.l &0x0,%fpcr # zero current control regs
958 1.1 is fmov.l &0x0,%fpsr
959 1.1 is
960 1.1 is lea FP_SRC(%a6),%a0
961 1.1 is lea FP_DST(%a6),%a1
962 1.1 is
963 1.1 is # maybe we can make these entry points ONLY the OVFL entry points of each routine.
964 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
965 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
966 1.1 is
967 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0
968 1.1 is bsr.l store_fpreg
969 1.1 is
970 1.1 is # The `060 FPU multiplier hardware is such that if the result of a
971 1.1 is # multiply operation is the smallest possible normalized number
972 1.1 is # (0x00000000_80000000_00000000), then the machine will take an
973 1.1 is # underflow exception. Since this is incorrect, we need to check
974 1.1 is # if our emulation, after re-doing the operation, decided that
975 1.1 is # no underflow was called for. We do these checks only in
976 1.1 is # funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
977 1.1 is # special case will simply exit gracefully with the correct result.
978 1.1 is
979 1.1 is # the exceptional possibilities we have left ourselves with are ONLY overflow
980 1.1 is # and inexact. and, the inexact is such that overflow occurred and was disabled
981 1.1 is # but inexact was enabled.
982 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6)
983 1.1 is bne.b funfl_unfl_on
984 1.1 is
985 1.1 is funfl_chkinex:
986 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6)
987 1.1 is bne.b funfl_inex_on
988 1.1 is
989 1.1 is funfl_exit:
990 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
991 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
992 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
993 1.1 is
994 1.1 is unlk %a6
995 1.1 is #$# add.l &24,%sp
996 1.1 is bra.l _fpsp_done
997 1.1 is
998 1.1 is # overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
999 1.1 is # in fp1 (don't forget to save fp0). what to do now?
1000 1.1 is # well, we simply have to get to go to _real_unfl()!
1001 1.1 is funfl_unfl_on:
1002 1.1 is
1003 1.1 is # The `060 FPU multiplier hardware is such that if the result of a
1004 1.1 is # multiply operation is the smallest possible normalized number
1005 1.1 is # (0x00000000_80000000_00000000), then the machine will take an
1006 1.1 is # underflow exception. Since this is incorrect, we check here to see
1007 1.1 is # if our emulation, after re-doing the operation, decided that
1008 1.1 is # no underflow was called for.
1009 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6)
1010 1.1 is beq.w funfl_chkinex
1011 1.1 is
1012 1.1 is funfl_unfl_on2:
1013 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
1014 1.1 is
1015 1.1 is mov.w &0xe003,2+FP_SRC(%a6) # save exc status
1016 1.1 is
1017 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1018 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1019 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1020 1.1 is
1021 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
1022 1.1 is
1023 1.1 is unlk %a6
1024 1.1 is
1025 1.1 is bra.l _real_unfl
1026 1.1 is
1027 1.1 is # undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
1028 1.1 is # we must jump to real_inex().
1029 1.1 is funfl_inex_on:
1030 1.1 is
1031 1.1 is # The `060 FPU multiplier hardware is such that if the result of a
1032 1.1 is # multiply operation is the smallest possible normalized number
1033 1.1 is # (0x00000000_80000000_00000000), then the machine will take an
1034 1.1 is # underflow exception.
1035 1.1 is # But, whether bogus or not, if inexact is enabled AND it occurred,
1036 1.1 is # then we have to branch to real_inex.
1037 1.1 is
1038 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6)
1039 1.1 is beq.w funfl_exit
1040 1.1 is
1041 1.1 is funfl_inex_on2:
1042 1.1 is
1043 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to stack
1044 1.1 is
1045 1.1 is mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
1046 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # save exc status
1047 1.1 is
1048 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1049 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1050 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1051 1.1 is
1052 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
1053 1.1 is
1054 1.1 is unlk %a6
1055 1.1 is
1056 1.1 is bra.l _real_inex
1057 1.1 is
1058 1.1 is #######################################################################
1059 1.1 is funfl_out:
1060 1.1 is
1061 1.1 is
1062 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
1063 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
1064 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
1065 1.1 is
1066 1.1 is # the src operand is definitely a NORM(!), so tag it as such
1067 1.1 is mov.b &NORM,STAG(%a6) # set src optype tag
1068 1.1 is
1069 1.1 is clr.l %d0
1070 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
1071 1.1 is
1072 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
1073 1.1 is
1074 1.1 is fmov.l &0x0,%fpcr # zero current control regs
1075 1.1 is fmov.l &0x0,%fpsr
1076 1.1 is
1077 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand
1078 1.1 is
1079 1.1 is bsr.l fout
1080 1.1 is
1081 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6)
1082 1.1 is bne.w funfl_unfl_on2
1083 1.1 is
1084 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6)
1085 1.1 is bne.w funfl_inex_on2
1086 1.1 is
1087 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1088 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1089 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1090 1.1 is
1091 1.1 is unlk %a6
1092 1.1 is #$# add.l &24,%sp
1093 1.1 is
1094 1.1 is btst &0x7,(%sp) # is trace on?
1095 1.1 is beq.l _fpsp_done # no
1096 1.1 is
1097 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
1098 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
1099 1.1 is bra.l _real_trace
1100 1.1 is
1101 1.1 is #########################################################################
1102 1.1 is # XDEF **************************************************************** #
1103 1.1 is # _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented #
1104 1.1 is # Data Type" exception. #
1105 1.1 is # #
1106 1.1 is # This handler should be the first code executed upon taking the #
1107 1.1 is # FP Unimplemented Data Type exception in an operating system. #
1108 1.1 is # #
1109 1.1 is # XREF **************************************************************** #
1110 1.1 is # _imem_read_{word,long}() - read instruction word/longword #
1111 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
1112 1.1 is # set_tag_x() - determine optype of src/dst operands #
1113 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile #
1114 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO #
1115 1.1 is # load_fpn2() - load dst operand from FP regfile #
1116 1.1 is # load_fpn1() - load src operand from FP regfile #
1117 1.1 is # fout() - emulate an opclass 3 instruction #
1118 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 #
1119 1.1 is # _real_inex() - "callout" to operating system inexact handler #
1120 1.1 is # _fpsp_done() - "callout" for exit; work all done #
1121 1.1 is # _real_trace() - "callout" for Trace enabled exception #
1122 1.1 is # funimp_skew() - adjust fsave src ops to "incorrect" value #
1123 1.1 is # _real_snan() - "callout" for SNAN exception #
1124 1.1 is # _real_operr() - "callout" for OPERR exception #
1125 1.1 is # _real_ovfl() - "callout" for OVFL exception #
1126 1.1 is # _real_unfl() - "callout" for UNFL exception #
1127 1.1 is # get_packed() - fetch packed operand from memory #
1128 1.1 is # #
1129 1.1 is # INPUT *************************************************************** #
1130 1.1 is # - The system stack contains the "Unimp Data Type" stk frame #
1131 1.1 is # - The fsave frame contains the ssrc op (for UNNORM/DENORM) #
1132 1.1 is # #
1133 1.1 is # OUTPUT ************************************************************** #
1134 1.1 is # If Inexact exception (opclass 3): #
1135 1.1 is # - The system stack is changed to an Inexact exception stk frame #
1136 1.1 is # If SNAN exception (opclass 3): #
1137 1.1 is # - The system stack is changed to an SNAN exception stk frame #
1138 1.1 is # If OPERR exception (opclass 3): #
1139 1.1 is # - The system stack is changed to an OPERR exception stk frame #
1140 1.1 is # If OVFL exception (opclass 3): #
1141 1.1 is # - The system stack is changed to an OVFL exception stk frame #
1142 1.1 is # If UNFL exception (opclass 3): #
1143 1.1 is # - The system stack is changed to an UNFL exception stack frame #
1144 1.1 is # If Trace exception enabled: #
1145 1.1 is # - The system stack is changed to a Trace exception stack frame #
1146 1.1 is # Else: (normal case) #
1147 1.1 is # - Correct result has been stored as appropriate #
1148 1.1 is # #
1149 1.1 is # ALGORITHM *********************************************************** #
1150 1.1 is # Two main instruction types can enter here: (1) DENORM or UNNORM #
1151 1.1 is # unimplemented data types. These can be either opclass 0,2 or 3 #
1152 1.1 is # instructions, and (2) PACKED unimplemented data format instructions #
1153 1.1 is # also of opclasses 0,2, or 3. #
1154 1.1 is # For UNNORM/DENORM opclass 0 and 2, the handler fetches the src #
1155 1.1 is # operand from the fsave state frame and the dst operand (if dyadic) #
1156 1.1 is # from the FP register file. The instruction is then emulated by #
1157 1.1 is # choosing an emulation routine from a table of routines indexed by #
1158 1.1 is # instruction type. Once the instruction has been emulated and result #
1159 1.1 is # saved, then we check to see if any enabled exceptions resulted from #
1160 1.1 is # instruction emulation. If none, then we exit through the "callout" #
1161 1.1 is # _fpsp_done(). If there is an enabled FP exception, then we insert #
1162 1.1 is # this exception into the FPU in the fsave state frame and then exit #
1163 1.1 is # through _fpsp_done(). #
1164 1.1 is # PACKED opclass 0 and 2 is similar in how the instruction is #
1165 1.1 is # emulated and exceptions handled. The differences occur in how the #
1166 1.1 is # handler loads the packed op (by calling get_packed() routine) and #
1167 1.1 is # by the fact that a Trace exception could be pending for PACKED ops. #
1168 1.1 is # If a Trace exception is pending, then the current exception stack #
1169 1.1 is # frame is changed to a Trace exception stack frame and an exit is #
1170 1.1 is # made through _real_trace(). #
1171 1.1 is # For UNNORM/DENORM opclass 3, the actual move out to memory is #
1172 1.1 is # performed by calling the routine fout(). If no exception should occur #
1173 1.1 is # as the result of emulation, then an exit either occurs through #
1174 1.1 is # _fpsp_done() or through _real_trace() if a Trace exception is pending #
1175 1.1 is # (a Trace stack frame must be created here, too). If an FP exception #
1176 1.1 is # should occur, then we must create an exception stack frame of that #
1177 1.1 is # type and jump to either _real_snan(), _real_operr(), _real_inex(), #
1178 1.1 is # _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 #
1179 1.1 is # emulation is performed in a similar manner. #
1180 1.1 is # #
1181 1.1 is #########################################################################
1182 1.1 is
1183 1.1 is #
1184 1.1 is # (1) DENORM and UNNORM (unimplemented) data types:
1185 1.1 is #
1186 1.1 is # post-instruction
1187 1.1 is # *****************
1188 1.1 is # * EA *
1189 1.1 is # pre-instruction * *
1190 1.1 is # ***************** *****************
1191 1.1 is # * 0x0 * 0x0dc * * 0x3 * 0x0dc *
1192 1.1 is # ***************** *****************
1193 1.1 is # * Next * * Next *
1194 1.1 is # * PC * * PC *
1195 1.1 is # ***************** *****************
1196 1.1 is # * SR * * SR *
1197 1.1 is # ***************** *****************
1198 1.1 is #
1199 1.1 is # (2) PACKED format (unsupported) opclasses two and three:
1200 1.1 is # *****************
1201 1.1 is # * EA *
1202 1.1 is # * *
1203 1.1 is # *****************
1204 1.1 is # * 0x2 * 0x0dc *
1205 1.1 is # *****************
1206 1.1 is # * Next *
1207 1.1 is # * PC *
1208 1.1 is # *****************
1209 1.1 is # * SR *
1210 1.1 is # *****************
1211 1.1 is #
1212 1.1 is global _fpsp_unsupp
1213 1.1 is _fpsp_unsupp:
1214 1.1 is
1215 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
1216 1.1 is
1217 1.1 is fsave FP_SRC(%a6) # save fp state
1218 1.1 is
1219 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
1220 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
1221 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
1222 1.1 is
1223 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode?
1224 1.1 is bne.b fu_s
1225 1.1 is fu_u:
1226 1.1 is mov.l %usp,%a0 # fetch user stack pointer
1227 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack
1228 1.1 is bra.b fu_cont
1229 1.1 is # if the exception is an opclass zero or two unimplemented data type
1230 1.1 is # exception, then the a7' calculated here is wrong since it doesn't
1231 1.1 is # stack an ea. however, we don't need an a7' for this case anyways.
1232 1.1 is fu_s:
1233 1.1 is lea 0x4+EXC_EA(%a6),%a0 # load old a7'
1234 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack
1235 1.1 is
1236 1.1 is fu_cont:
1237 1.1 is
1238 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
1239 1.1 is # the FPIAR should be set correctly for ALL exceptions passing through
1240 1.1 is # this point.
1241 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
1242 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
1243 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
1244 1.1 is bsr.l _imem_read_long # fetch the instruction words
1245 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
1246 1.1 is
1247 1.1 is ############################
1248 1.1 is
1249 1.1 is clr.b SPCOND_FLG(%a6) # clear special condition flag
1250 1.1 is
1251 1.1 is # Separate opclass three (fpn-to-mem) ops since they have a different
1252 1.1 is # stack frame and protocol.
1253 1.1 is btst &0x5,EXC_CMDREG(%a6) # is it an fmove out?
1254 1.1 is bne.w fu_out # yes
1255 1.1 is
1256 1.1 is # Separate packed opclass two instructions.
1257 1.1 is bfextu EXC_CMDREG(%a6){&0:&6},%d0
1258 1.1 is cmpi.b %d0,&0x13
1259 1.1 is beq.w fu_in_pack
1260 1.1 is
1261 1.1 is
1262 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction.
1263 1.1 is # so, since the emulation routines re-create them anyways, zero exception field
1264 1.1 is andi.l &0x00ff00ff,USER_FPSR(%a6) # zero exception field
1265 1.1 is
1266 1.1 is fmov.l &0x0,%fpcr # zero current control regs
1267 1.1 is fmov.l &0x0,%fpsr
1268 1.1 is
1269 1.1 is # Opclass two w/ memory-to-fpn operation will have an incorrect extended
1270 1.1 is # precision format if the src format was single or double and the
1271 1.1 is # source data type was an INF, NAN, DENORM, or UNNORM
1272 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to input
1273 1.1 is bsr.l fix_skewed_ops
1274 1.1 is
1275 1.1 is # we don't know whether the src operand or the dst operand (or both) is the
1276 1.1 is # UNNORM or DENORM. call the function that tags the operand type. if the
1277 1.1 is # input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
1278 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
1279 1.1 is bsr.l set_tag_x # tag the operand type
1280 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
1281 1.1 is bne.b fu_op2 # no
1282 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1283 1.1 is
1284 1.1 is fu_op2:
1285 1.1 is mov.b %d0,STAG(%a6) # save src optype tag
1286 1.1 is
1287 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1288 1.1 is
1289 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations
1290 1.1 is # at this point
1291 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
1292 1.1 is beq.b fu_extract # monadic
1293 1.1 is cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1294 1.1 is beq.b fu_extract # yes, so it's monadic, too
1295 1.1 is
1296 1.1 is bsr.l load_fpn2 # load dst into FP_DST
1297 1.1 is
1298 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
1299 1.1 is bsr.l set_tag_x # tag the operand type
1300 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
1301 1.1 is bne.b fu_op2_done # no
1302 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1303 1.1 is fu_op2_done:
1304 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag
1305 1.1 is
1306 1.1 is fu_extract:
1307 1.1 is clr.l %d0
1308 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1309 1.1 is
1310 1.1 is bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1311 1.1 is
1312 1.1 is lea FP_SRC(%a6),%a0
1313 1.1 is lea FP_DST(%a6),%a1
1314 1.1 is
1315 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1316 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
1317 1.1 is
1318 1.1 is #
1319 1.1 is # Exceptions in order of precedence:
1320 1.1 is # BSUN : none
1321 1.1 is # SNAN : all dyadic ops
1322 1.1 is # OPERR : fsqrt(-NORM)
1323 1.1 is # OVFL : all except ftst,fcmp
1324 1.1 is # UNFL : all except ftst,fcmp
1325 1.1 is # DZ : fdiv
1326 1.1 is # INEX2 : all except ftst,fcmp
1327 1.1 is # INEX1 : none (packed doesn't go through here)
1328 1.1 is #
1329 1.1 is
1330 1.1 is # we determine the highest priority exception(if any) set by the
1331 1.1 is # emulation routine that has also been enabled by the user.
1332 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions set
1333 1.1 is bne.b fu_in_ena # some are enabled
1334 1.1 is
1335 1.1 is fu_in_cont:
1336 1.1 is # fcmp and ftst do not store any result.
1337 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension
1338 1.1 is andi.b &0x38,%d0 # extract bits 3-5
1339 1.1 is cmpi.b %d0,&0x38 # is instr fcmp or ftst?
1340 1.1 is beq.b fu_in_exit # yes
1341 1.1 is
1342 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1343 1.1 is bsr.l store_fpreg # store the result
1344 1.1 is
1345 1.1 is fu_in_exit:
1346 1.1 is
1347 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1348 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1349 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1350 1.1 is
1351 1.1 is unlk %a6
1352 1.1 is
1353 1.1 is bra.l _fpsp_done
1354 1.1 is
1355 1.1 is fu_in_ena:
1356 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
1357 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception
1358 1.1 is bne.b fu_in_exc # there is at least one set
1359 1.1 is
1360 1.1 is #
1361 1.1 is # No exceptions occurred that were also enabled. Now:
1362 1.1 is #
1363 1.1 is # if (OVFL && ovfl_disabled && inexact_enabled) {
1364 1.1 is # branch to _real_inex() (even if the result was exact!);
1365 1.1 is # } else {
1366 1.1 is # save the result in the proper fp reg (unless the op is fcmp or ftst);
1367 1.1 is # return;
1368 1.1 is # }
1369 1.1 is #
1370 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1371 1.1 is beq.b fu_in_cont # no
1372 1.1 is
1373 1.1 is fu_in_ovflchk:
1374 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1375 1.1 is beq.b fu_in_cont # no
1376 1.1 is bra.w fu_in_exc_ovfl # go insert overflow frame
1377 1.1 is
1378 1.1 is #
1379 1.1 is # An exception occurred and that exception was enabled:
1380 1.1 is #
1381 1.1 is # shift enabled exception field into lo byte of d0;
1382 1.1 is # if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1383 1.1 is # ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1384 1.1 is # /*
1385 1.1 is # * this is the case where we must call _real_inex() now or else
1386 1.1 is # * there will be no other way to pass it the exceptional operand
1387 1.1 is # */
1388 1.1 is # call _real_inex();
1389 1.1 is # } else {
1390 1.1 is # restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1391 1.1 is # }
1392 1.1 is #
1393 1.1 is fu_in_exc:
1394 1.1 is subi.l &24,%d0 # fix offset to be 0-8
1395 1.1 is cmpi.b %d0,&0x6 # is exception INEX? (6)
1396 1.1 is bne.b fu_in_exc_exit # no
1397 1.1 is
1398 1.1 is # the enabled exception was inexact
1399 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1400 1.1 is bne.w fu_in_exc_unfl # yes
1401 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1402 1.1 is bne.w fu_in_exc_ovfl # yes
1403 1.1 is
1404 1.1 is # here, we insert the correct fsave status value into the fsave frame for the
1405 1.1 is # corresponding exception. the operand in the fsave frame should be the original
1406 1.1 is # src operand.
1407 1.1 is fu_in_exc_exit:
1408 1.1 is mov.l %d0,-(%sp) # save d0
1409 1.1 is bsr.l funimp_skew # skew sgl or dbl inputs
1410 1.1 is mov.l (%sp)+,%d0 # restore d0
1411 1.1 is
1412 1.1 is mov.w (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
1413 1.1 is
1414 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1415 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1416 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1417 1.1 is
1418 1.1 is frestore FP_SRC(%a6) # restore src op
1419 1.1 is
1420 1.1 is unlk %a6
1421 1.1 is
1422 1.1 is bra.l _fpsp_done
1423 1.1 is
1424 1.1 is tbl_except:
1425 1.1 is short 0xe000,0xe006,0xe004,0xe005
1426 1.1 is short 0xe003,0xe002,0xe001,0xe001
1427 1.1 is
1428 1.1 is fu_in_exc_unfl:
1429 1.1 is mov.w &0x4,%d0
1430 1.1 is bra.b fu_in_exc_exit
1431 1.1 is fu_in_exc_ovfl:
1432 1.1 is mov.w &0x03,%d0
1433 1.1 is bra.b fu_in_exc_exit
1434 1.1 is
1435 1.1 is # If the input operand to this operation was opclass two and a single
1436 1.1 is # or double precision denorm, inf, or nan, the operand needs to be
1437 1.1 is # "corrected" in order to have the proper equivalent extended precision
1438 1.1 is # number.
1439 1.1 is global fix_skewed_ops
1440 1.1 is fix_skewed_ops:
1441 1.1 is bfextu EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
1442 1.1 is cmpi.b %d0,&0x11 # is class = 2 & fmt = sgl?
1443 1.1 is beq.b fso_sgl # yes
1444 1.1 is cmpi.b %d0,&0x15 # is class = 2 & fmt = dbl?
1445 1.1 is beq.b fso_dbl # yes
1446 1.1 is rts # no
1447 1.1 is
1448 1.1 is fso_sgl:
1449 1.1 is mov.w LOCAL_EX(%a0),%d0 # fetch src exponent
1450 1.1 is andi.w &0x7fff,%d0 # strip sign
1451 1.1 is cmpi.w %d0,&0x3f80 # is |exp| == $3f80?
1452 1.1 is beq.b fso_sgl_dnrm_zero # yes
1453 1.1 is cmpi.w %d0,&0x407f # no; is |exp| == $407f?
1454 1.1 is beq.b fso_infnan # yes
1455 1.1 is rts # no
1456 1.1 is
1457 1.1 is fso_sgl_dnrm_zero:
1458 1.1 is andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1459 1.1 is beq.b fso_zero # it's a skewed zero
1460 1.1 is fso_sgl_dnrm:
1461 1.1 is # here, we count on norm not to alter a0...
1462 1.1 is bsr.l norm # normalize mantissa
1463 1.1 is neg.w %d0 # -shft amt
1464 1.1 is addi.w &0x3f81,%d0 # adjust new exponent
1465 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent
1466 1.1 is or.w %d0,LOCAL_EX(%a0) # insert new exponent
1467 1.1 is rts
1468 1.1 is
1469 1.1 is fso_zero:
1470 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent
1471 1.1 is rts
1472 1.1 is
1473 1.1 is fso_infnan:
1474 1.1 is andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit
1475 1.1 is ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff
1476 1.1 is rts
1477 1.1 is
1478 1.1 is fso_dbl:
1479 1.1 is mov.w LOCAL_EX(%a0),%d0 # fetch src exponent
1480 1.1 is andi.w &0x7fff,%d0 # strip sign
1481 1.1 is cmpi.w %d0,&0x3c00 # is |exp| == $3c00?
1482 1.1 is beq.b fso_dbl_dnrm_zero # yes
1483 1.1 is cmpi.w %d0,&0x43ff # no; is |exp| == $43ff?
1484 1.1 is beq.b fso_infnan # yes
1485 1.1 is rts # no
1486 1.1 is
1487 1.1 is fso_dbl_dnrm_zero:
1488 1.1 is andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1489 1.1 is bne.b fso_dbl_dnrm # it's a skewed denorm
1490 1.1 is tst.l LOCAL_LO(%a0) # is it a zero?
1491 1.1 is beq.b fso_zero # yes
1492 1.1 is fso_dbl_dnrm:
1493 1.1 is # here, we count on norm not to alter a0...
1494 1.1 is bsr.l norm # normalize mantissa
1495 1.1 is neg.w %d0 # -shft amt
1496 1.1 is addi.w &0x3c01,%d0 # adjust new exponent
1497 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent
1498 1.1 is or.w %d0,LOCAL_EX(%a0) # insert new exponent
1499 1.1 is rts
1500 1.1 is
1501 1.1 is #################################################################
1502 1.1 is
1503 1.1 is # fmove out took an unimplemented data type exception.
1504 1.1 is # the src operand is in FP_SRC. Call _fout() to write out the result and
1505 1.1 is # to determine which exceptions, if any, to take.
1506 1.1 is fu_out:
1507 1.1 is
1508 1.1 is # Separate packed move outs from the UNNORM and DENORM move outs.
1509 1.1 is bfextu EXC_CMDREG(%a6){&3:&3},%d0
1510 1.1 is cmpi.b %d0,&0x3
1511 1.1 is beq.w fu_out_pack
1512 1.1 is cmpi.b %d0,&0x7
1513 1.1 is beq.w fu_out_pack
1514 1.1 is
1515 1.1 is
1516 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction.
1517 1.1 is # so, since the emulation routines re-create them anyways, zero exception field.
1518 1.1 is # fmove out doesn't affect ccodes.
1519 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
1520 1.1 is
1521 1.1 is fmov.l &0x0,%fpcr # zero current control regs
1522 1.1 is fmov.l &0x0,%fpsr
1523 1.1 is
1524 1.1 is # the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
1525 1.1 is # call here. just figure out what it is...
1526 1.1 is mov.w FP_SRC_EX(%a6),%d0 # get exponent
1527 1.1 is andi.w &0x7fff,%d0 # strip sign
1528 1.1 is beq.b fu_out_denorm # it's a DENORM
1529 1.1 is
1530 1.1 is lea FP_SRC(%a6),%a0
1531 1.1 is bsr.l unnorm_fix # yes; fix it
1532 1.1 is
1533 1.1 is mov.b %d0,STAG(%a6)
1534 1.1 is
1535 1.1 is bra.b fu_out_cont
1536 1.1 is fu_out_denorm:
1537 1.1 is mov.b &DENORM,STAG(%a6)
1538 1.1 is fu_out_cont:
1539 1.1 is
1540 1.1 is clr.l %d0
1541 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1542 1.1 is
1543 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand
1544 1.1 is
1545 1.1 is mov.l (%a6),EXC_A6(%a6) # in case a6 changes
1546 1.1 is bsr.l fout # call fmove out routine
1547 1.1 is
1548 1.1 is # Exceptions in order of precedence:
1549 1.1 is # BSUN : none
1550 1.1 is # SNAN : none
1551 1.1 is # OPERR : fmove.{b,w,l} out of large UNNORM
1552 1.1 is # OVFL : fmove.{s,d}
1553 1.1 is # UNFL : fmove.{s,d,x}
1554 1.1 is # DZ : none
1555 1.1 is # INEX2 : all
1556 1.1 is # INEX1 : none (packed doesn't travel through here)
1557 1.1 is
1558 1.1 is # determine the highest priority exception(if any) set by the
1559 1.1 is # emulation routine that has also been enabled by the user.
1560 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
1561 1.1 is bne.w fu_out_ena # some are enabled
1562 1.1 is
1563 1.1 is fu_out_done:
1564 1.1 is
1565 1.1 is mov.l EXC_A6(%a6),(%a6) # in case a6 changed
1566 1.1 is
1567 1.1 is # on extended precision opclass three instructions using pre-decrement or
1568 1.1 is # post-increment addressing mode, the address register is not updated. is the
1569 1.1 is # address register was the stack pointer used from user mode, then let's update
1570 1.1 is # it here. if it was used from supervisor mode, then we have to handle this
1571 1.1 is # as a special case.
1572 1.1 is btst &0x5,EXC_SR(%a6)
1573 1.1 is bne.b fu_out_done_s
1574 1.1 is
1575 1.1 is mov.l EXC_A7(%a6),%a0 # restore a7
1576 1.1 is mov.l %a0,%usp
1577 1.1 is
1578 1.1 is fu_out_done_cont:
1579 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1580 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1581 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1582 1.1 is
1583 1.1 is unlk %a6
1584 1.1 is
1585 1.1 is btst &0x7,(%sp) # is trace on?
1586 1.1 is bne.b fu_out_trace # yes
1587 1.1 is
1588 1.1 is bra.l _fpsp_done
1589 1.1 is
1590 1.1 is # is the ea mode pre-decrement of the stack pointer from supervisor mode?
1591 1.1 is # ("fmov.x fpm,-(a7)") if so,
1592 1.1 is fu_out_done_s:
1593 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
1594 1.1 is bne.b fu_out_done_cont
1595 1.1 is
1596 1.1 is # the extended precision result is still in fp0. but, we need to save it
1597 1.1 is # somewhere on the stack until we can copy it to its final resting place.
1598 1.1 is # here, we're counting on the top of the stack to be the old place-holders
1599 1.1 is # for fp0/fp1 which have already been restored. that way, we can write
1600 1.1 is # over those destinations with the shifted stack frame.
1601 1.1 is fmovm.x &0x80,FP_SRC(%a6) # put answer on stack
1602 1.1 is
1603 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1604 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1605 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1606 1.1 is
1607 1.1 is mov.l (%a6),%a6 # restore frame pointer
1608 1.1 is
1609 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1610 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1611 1.1 is
1612 1.1 is # now, copy the result to the proper place on the stack
1613 1.1 is mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1614 1.1 is mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1615 1.1 is mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1616 1.1 is
1617 1.1 is add.l &LOCAL_SIZE-0x8,%sp
1618 1.1 is
1619 1.1 is btst &0x7,(%sp)
1620 1.1 is bne.b fu_out_trace
1621 1.1 is
1622 1.1 is bra.l _fpsp_done
1623 1.1 is
1624 1.1 is fu_out_ena:
1625 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
1626 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception
1627 1.1 is bne.b fu_out_exc # there is at least one set
1628 1.1 is
1629 1.1 is # no exceptions were set.
1630 1.1 is # if a disabled overflow occurred and inexact was enabled but the result
1631 1.1 is # was exact, then a branch to _real_inex() is made.
1632 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1633 1.1 is beq.w fu_out_done # no
1634 1.1 is
1635 1.1 is fu_out_ovflchk:
1636 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1637 1.1 is beq.w fu_out_done # no
1638 1.1 is bra.w fu_inex # yes
1639 1.1 is
1640 1.1 is #
1641 1.1 is # The fp move out that took the "Unimplemented Data Type" exception was
1642 1.1 is # being traced. Since the stack frames are similar, get the "current" PC
1643 1.1 is # from FPIAR and put it in the trace stack frame then jump to _real_trace().
1644 1.1 is #
1645 1.1 is # UNSUPP FRAME TRACE FRAME
1646 1.1 is # ***************** *****************
1647 1.1 is # * EA * * Current *
1648 1.1 is # * * * PC *
1649 1.1 is # ***************** *****************
1650 1.1 is # * 0x3 * 0x0dc * * 0x2 * 0x024 *
1651 1.1 is # ***************** *****************
1652 1.1 is # * Next * * Next *
1653 1.1 is # * PC * * PC *
1654 1.1 is # ***************** *****************
1655 1.1 is # * SR * * SR *
1656 1.1 is # ***************** *****************
1657 1.1 is #
1658 1.1 is fu_out_trace:
1659 1.1 is mov.w &0x2024,0x6(%sp)
1660 1.1 is fmov.l %fpiar,0x8(%sp)
1661 1.1 is bra.l _real_trace
1662 1.1 is
1663 1.1 is # an exception occurred and that exception was enabled.
1664 1.1 is fu_out_exc:
1665 1.1 is subi.l &24,%d0 # fix offset to be 0-8
1666 1.1 is
1667 1.1 is # we don't mess with the existing fsave frame. just re-insert it and
1668 1.1 is # jump to the "_real_{}()" handler...
1669 1.1 is mov.w (tbl_fu_out.b,%pc,%d0.w*2),%d0
1670 1.1 is jmp (tbl_fu_out.b,%pc,%d0.w*1)
1671 1.1 is
1672 1.1 is swbeg &0x8
1673 1.1 is tbl_fu_out:
1674 1.1 is short tbl_fu_out - tbl_fu_out # BSUN can't happen
1675 1.1 is short tbl_fu_out - tbl_fu_out # SNAN can't happen
1676 1.1 is short fu_operr - tbl_fu_out # OPERR
1677 1.1 is short fu_ovfl - tbl_fu_out # OVFL
1678 1.1 is short fu_unfl - tbl_fu_out # UNFL
1679 1.1 is short tbl_fu_out - tbl_fu_out # DZ can't happen
1680 1.1 is short fu_inex - tbl_fu_out # INEX2
1681 1.1 is short tbl_fu_out - tbl_fu_out # INEX1 won't make it here
1682 1.1 is
1683 1.1 is # for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
1684 1.1 is # frestore it.
1685 1.1 is fu_snan:
1686 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1687 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1688 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1689 1.1 is
1690 1.1 is mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8
1691 1.1 is mov.w &0xe006,2+FP_SRC(%a6)
1692 1.1 is
1693 1.1 is frestore FP_SRC(%a6)
1694 1.1 is
1695 1.1 is unlk %a6
1696 1.1 is
1697 1.1 is
1698 1.1 is bra.l _real_snan
1699 1.1 is
1700 1.1 is fu_operr:
1701 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1702 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1703 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1704 1.1 is
1705 1.1 is mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0
1706 1.1 is mov.w &0xe004,2+FP_SRC(%a6)
1707 1.1 is
1708 1.1 is frestore FP_SRC(%a6)
1709 1.1 is
1710 1.1 is unlk %a6
1711 1.1 is
1712 1.1 is
1713 1.1 is bra.l _real_operr
1714 1.1 is
1715 1.1 is fu_ovfl:
1716 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1717 1.1 is
1718 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1719 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1720 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1721 1.1 is
1722 1.1 is mov.w &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4
1723 1.1 is mov.w &0xe005,2+FP_SRC(%a6)
1724 1.1 is
1725 1.1 is frestore FP_SRC(%a6) # restore EXOP
1726 1.1 is
1727 1.1 is unlk %a6
1728 1.1 is
1729 1.1 is bra.l _real_ovfl
1730 1.1 is
1731 1.1 is # underflow can happen for extended precision. extended precision opclass
1732 1.1 is # three instruction exceptions don't update the stack pointer. so, if the
1733 1.1 is # exception occurred from user mode, then simply update a7 and exit normally.
1734 1.1 is # if the exception occurred from supervisor mode, check if
1735 1.1 is fu_unfl:
1736 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6
1737 1.1 is
1738 1.1 is btst &0x5,EXC_SR(%a6)
1739 1.1 is bne.w fu_unfl_s
1740 1.1 is
1741 1.1 is mov.l EXC_A7(%a6),%a0 # restore a7 whether we need
1742 1.1 is mov.l %a0,%usp # to or not...
1743 1.1 is
1744 1.1 is fu_unfl_cont:
1745 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1746 1.1 is
1747 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1748 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1749 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1750 1.1 is
1751 1.1 is mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
1752 1.1 is mov.w &0xe003,2+FP_SRC(%a6)
1753 1.1 is
1754 1.1 is frestore FP_SRC(%a6) # restore EXOP
1755 1.1 is
1756 1.1 is unlk %a6
1757 1.1 is
1758 1.1 is bra.l _real_unfl
1759 1.1 is
1760 1.1 is fu_unfl_s:
1761 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
1762 1.1 is bne.b fu_unfl_cont
1763 1.1 is
1764 1.1 is # the extended precision result is still in fp0. but, we need to save it
1765 1.1 is # somewhere on the stack until we can copy it to its final resting place
1766 1.1 is # (where the exc frame is currently). make sure it's not at the top of the
1767 1.1 is # frame or it will get overwritten when the exc stack frame is shifted "down".
1768 1.1 is fmovm.x &0x80,FP_SRC(%a6) # put answer on stack
1769 1.1 is fmovm.x &0x40,FP_DST(%a6) # put EXOP on stack
1770 1.1 is
1771 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1772 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1773 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1774 1.1 is
1775 1.1 is mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
1776 1.1 is mov.w &0xe003,2+FP_DST(%a6)
1777 1.1 is
1778 1.1 is frestore FP_DST(%a6) # restore EXOP
1779 1.1 is
1780 1.1 is mov.l (%a6),%a6 # restore frame pointer
1781 1.1 is
1782 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1783 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1784 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
1785 1.1 is
1786 1.1 is # now, copy the result to the proper place on the stack
1787 1.1 is mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1788 1.1 is mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1789 1.1 is mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1790 1.1 is
1791 1.1 is add.l &LOCAL_SIZE-0x8,%sp
1792 1.1 is
1793 1.1 is bra.l _real_unfl
1794 1.1 is
1795 1.1 is # fmove in and out enter here.
1796 1.1 is fu_inex:
1797 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1798 1.1 is
1799 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1800 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1801 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1802 1.1 is
1803 1.1 is mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4
1804 1.1 is mov.w &0xe001,2+FP_SRC(%a6)
1805 1.1 is
1806 1.1 is frestore FP_SRC(%a6) # restore EXOP
1807 1.1 is
1808 1.1 is unlk %a6
1809 1.1 is
1810 1.1 is
1811 1.1 is bra.l _real_inex
1812 1.1 is
1813 1.1 is #########################################################################
1814 1.1 is #########################################################################
1815 1.1 is fu_in_pack:
1816 1.1 is
1817 1.1 is
1818 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction.
1819 1.1 is # so, since the emulation routines re-create them anyways, zero exception field
1820 1.1 is andi.l &0x0ff00ff,USER_FPSR(%a6) # zero exception field
1821 1.1 is
1822 1.1 is fmov.l &0x0,%fpcr # zero current control regs
1823 1.1 is fmov.l &0x0,%fpsr
1824 1.1 is
1825 1.1 is bsr.l get_packed # fetch packed src operand
1826 1.1 is
1827 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src
1828 1.1 is bsr.l set_tag_x # set src optype tag
1829 1.1 is
1830 1.1 is mov.b %d0,STAG(%a6) # save src optype tag
1831 1.1 is
1832 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1833 1.1 is
1834 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations
1835 1.1 is # at this point
1836 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
1837 1.1 is beq.b fu_extract_p # monadic
1838 1.1 is cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1839 1.1 is beq.b fu_extract_p # yes, so it's monadic, too
1840 1.1 is
1841 1.1 is bsr.l load_fpn2 # load dst into FP_DST
1842 1.1 is
1843 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
1844 1.1 is bsr.l set_tag_x # tag the operand type
1845 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
1846 1.1 is bne.b fu_op2_done_p # no
1847 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1848 1.1 is fu_op2_done_p:
1849 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag
1850 1.1 is
1851 1.1 is fu_extract_p:
1852 1.1 is clr.l %d0
1853 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1854 1.1 is
1855 1.1 is bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1856 1.1 is
1857 1.1 is lea FP_SRC(%a6),%a0
1858 1.1 is lea FP_DST(%a6),%a1
1859 1.1 is
1860 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1861 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
1862 1.1 is
1863 1.1 is #
1864 1.1 is # Exceptions in order of precedence:
1865 1.1 is # BSUN : none
1866 1.1 is # SNAN : all dyadic ops
1867 1.1 is # OPERR : fsqrt(-NORM)
1868 1.1 is # OVFL : all except ftst,fcmp
1869 1.1 is # UNFL : all except ftst,fcmp
1870 1.1 is # DZ : fdiv
1871 1.1 is # INEX2 : all except ftst,fcmp
1872 1.1 is # INEX1 : all
1873 1.1 is #
1874 1.1 is
1875 1.1 is # we determine the highest priority exception(if any) set by the
1876 1.1 is # emulation routine that has also been enabled by the user.
1877 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
1878 1.1 is bne.w fu_in_ena_p # some are enabled
1879 1.1 is
1880 1.1 is fu_in_cont_p:
1881 1.1 is # fcmp and ftst do not store any result.
1882 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension
1883 1.1 is andi.b &0x38,%d0 # extract bits 3-5
1884 1.1 is cmpi.b %d0,&0x38 # is instr fcmp or ftst?
1885 1.1 is beq.b fu_in_exit_p # yes
1886 1.1 is
1887 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1888 1.1 is bsr.l store_fpreg # store the result
1889 1.1 is
1890 1.1 is fu_in_exit_p:
1891 1.1 is
1892 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor?
1893 1.1 is bne.w fu_in_exit_s_p # supervisor
1894 1.1 is
1895 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7
1896 1.1 is mov.l %a0,%usp
1897 1.1 is
1898 1.1 is fu_in_exit_cont_p:
1899 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1900 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1901 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1902 1.1 is
1903 1.1 is unlk %a6 # unravel stack frame
1904 1.1 is
1905 1.1 is btst &0x7,(%sp) # is trace on?
1906 1.1 is bne.w fu_trace_p # yes
1907 1.1 is
1908 1.1 is bra.l _fpsp_done # exit to os
1909 1.1 is
1910 1.1 is # the exception occurred in supervisor mode. check to see if the
1911 1.1 is # addressing mode was (a7)+. if so, we'll need to shift the
1912 1.1 is # stack frame "up".
1913 1.1 is fu_in_exit_s_p:
1914 1.1 is btst &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
1915 1.1 is beq.b fu_in_exit_cont_p # no
1916 1.1 is
1917 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1918 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1919 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1920 1.1 is
1921 1.1 is unlk %a6 # unravel stack frame
1922 1.1 is
1923 1.1 is # shift the stack frame "up". we don't really care about the <ea> field.
1924 1.1 is mov.l 0x4(%sp),0x10(%sp)
1925 1.1 is mov.l 0x0(%sp),0xc(%sp)
1926 1.1 is add.l &0xc,%sp
1927 1.1 is
1928 1.1 is btst &0x7,(%sp) # is trace on?
1929 1.1 is bne.w fu_trace_p # yes
1930 1.1 is
1931 1.1 is bra.l _fpsp_done # exit to os
1932 1.1 is
1933 1.1 is fu_in_ena_p:
1934 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set
1935 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception
1936 1.1 is bne.b fu_in_exc_p # at least one was set
1937 1.1 is
1938 1.1 is #
1939 1.1 is # No exceptions occurred that were also enabled. Now:
1940 1.1 is #
1941 1.1 is # if (OVFL && ovfl_disabled && inexact_enabled) {
1942 1.1 is # branch to _real_inex() (even if the result was exact!);
1943 1.1 is # } else {
1944 1.1 is # save the result in the proper fp reg (unless the op is fcmp or ftst);
1945 1.1 is # return;
1946 1.1 is # }
1947 1.1 is #
1948 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1949 1.1 is beq.w fu_in_cont_p # no
1950 1.1 is
1951 1.1 is fu_in_ovflchk_p:
1952 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1953 1.1 is beq.w fu_in_cont_p # no
1954 1.1 is bra.w fu_in_exc_ovfl_p # do _real_inex() now
1955 1.1 is
1956 1.1 is #
1957 1.1 is # An exception occurred and that exception was enabled:
1958 1.1 is #
1959 1.1 is # shift enabled exception field into lo byte of d0;
1960 1.1 is # if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1961 1.1 is # ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1962 1.1 is # /*
1963 1.1 is # * this is the case where we must call _real_inex() now or else
1964 1.1 is # * there will be no other way to pass it the exceptional operand
1965 1.1 is # */
1966 1.1 is # call _real_inex();
1967 1.1 is # } else {
1968 1.1 is # restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1969 1.1 is # }
1970 1.1 is #
1971 1.1 is fu_in_exc_p:
1972 1.1 is subi.l &24,%d0 # fix offset to be 0-8
1973 1.1 is cmpi.b %d0,&0x6 # is exception INEX? (6 or 7)
1974 1.1 is blt.b fu_in_exc_exit_p # no
1975 1.1 is
1976 1.1 is # the enabled exception was inexact
1977 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1978 1.1 is bne.w fu_in_exc_unfl_p # yes
1979 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1980 1.1 is bne.w fu_in_exc_ovfl_p # yes
1981 1.1 is
1982 1.1 is # here, we insert the correct fsave status value into the fsave frame for the
1983 1.1 is # corresponding exception. the operand in the fsave frame should be the original
1984 1.1 is # src operand.
1985 1.1 is # as a reminder for future predicted pain and agony, we are passing in fsave the
1986 1.1 is # "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
1987 1.1 is # this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
1988 1.1 is fu_in_exc_exit_p:
1989 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor?
1990 1.1 is bne.w fu_in_exc_exit_s_p # supervisor
1991 1.1 is
1992 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7
1993 1.1 is mov.l %a0,%usp
1994 1.1 is
1995 1.1 is fu_in_exc_exit_cont_p:
1996 1.1 is mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
1997 1.1 is
1998 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1999 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2000 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2001 1.1 is
2002 1.1 is frestore FP_SRC(%a6) # restore src op
2003 1.1 is
2004 1.1 is unlk %a6
2005 1.1 is
2006 1.1 is btst &0x7,(%sp) # is trace enabled?
2007 1.1 is bne.w fu_trace_p # yes
2008 1.1 is
2009 1.1 is bra.l _fpsp_done
2010 1.1 is
2011 1.1 is tbl_except_p:
2012 1.1 is short 0xe000,0xe006,0xe004,0xe005
2013 1.1 is short 0xe003,0xe002,0xe001,0xe001
2014 1.1 is
2015 1.1 is fu_in_exc_ovfl_p:
2016 1.1 is mov.w &0x3,%d0
2017 1.1 is bra.w fu_in_exc_exit_p
2018 1.1 is
2019 1.1 is fu_in_exc_unfl_p:
2020 1.1 is mov.w &0x4,%d0
2021 1.1 is bra.w fu_in_exc_exit_p
2022 1.1 is
2023 1.1 is fu_in_exc_exit_s_p:
2024 1.1 is btst &mia7_bit,SPCOND_FLG(%a6)
2025 1.1 is beq.b fu_in_exc_exit_cont_p
2026 1.1 is
2027 1.1 is mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2028 1.1 is
2029 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2030 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2031 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2032 1.1 is
2033 1.1 is frestore FP_SRC(%a6) # restore src op
2034 1.1 is
2035 1.1 is unlk %a6 # unravel stack frame
2036 1.1 is
2037 1.1 is # shift stack frame "up". who cares about <ea> field.
2038 1.1 is mov.l 0x4(%sp),0x10(%sp)
2039 1.1 is mov.l 0x0(%sp),0xc(%sp)
2040 1.1 is add.l &0xc,%sp
2041 1.1 is
2042 1.1 is btst &0x7,(%sp) # is trace on?
2043 1.1 is bne.b fu_trace_p # yes
2044 1.1 is
2045 1.1 is bra.l _fpsp_done # exit to os
2046 1.1 is
2047 1.1 is #
2048 1.1 is # The opclass two PACKED instruction that took an "Unimplemented Data Type"
2049 1.1 is # exception was being traced. Make the "current" PC the FPIAR and put it in the
2050 1.1 is # trace stack frame then jump to _real_trace().
2051 1.1 is #
2052 1.1 is # UNSUPP FRAME TRACE FRAME
2053 1.1 is # ***************** *****************
2054 1.1 is # * EA * * Current *
2055 1.1 is # * * * PC *
2056 1.1 is # ***************** *****************
2057 1.1 is # * 0x2 * 0x0dc * * 0x2 * 0x024 *
2058 1.1 is # ***************** *****************
2059 1.1 is # * Next * * Next *
2060 1.1 is # * PC * * PC *
2061 1.1 is # ***************** *****************
2062 1.1 is # * SR * * SR *
2063 1.1 is # ***************** *****************
2064 1.1 is fu_trace_p:
2065 1.1 is mov.w &0x2024,0x6(%sp)
2066 1.1 is fmov.l %fpiar,0x8(%sp)
2067 1.1 is
2068 1.1 is bra.l _real_trace
2069 1.1 is
2070 1.1 is #########################################################
2071 1.1 is #########################################################
2072 1.1 is fu_out_pack:
2073 1.1 is
2074 1.1 is
2075 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction.
2076 1.1 is # so, since the emulation routines re-create them anyways, zero exception field.
2077 1.1 is # fmove out doesn't affect ccodes.
2078 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
2079 1.1 is
2080 1.1 is fmov.l &0x0,%fpcr # zero current control regs
2081 1.1 is fmov.l &0x0,%fpsr
2082 1.1 is
2083 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0
2084 1.1 is bsr.l load_fpn1
2085 1.1 is
2086 1.1 is # unlike other opclass 3, unimplemented data type exceptions, packed must be
2087 1.1 is # able to detect all operand types.
2088 1.1 is lea FP_SRC(%a6),%a0
2089 1.1 is bsr.l set_tag_x # tag the operand type
2090 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
2091 1.1 is bne.b fu_op2_p # no
2092 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
2093 1.1 is
2094 1.1 is fu_op2_p:
2095 1.1 is mov.b %d0,STAG(%a6) # save src optype tag
2096 1.1 is
2097 1.1 is clr.l %d0
2098 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
2099 1.1 is
2100 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand
2101 1.1 is
2102 1.1 is mov.l (%a6),EXC_A6(%a6) # in case a6 changes
2103 1.1 is bsr.l fout # call fmove out routine
2104 1.1 is
2105 1.1 is # Exceptions in order of precedence:
2106 1.1 is # BSUN : no
2107 1.1 is # SNAN : yes
2108 1.1 is # OPERR : if ((k_factor > +17) || (dec. exp exceeds 3 digits))
2109 1.1 is # OVFL : no
2110 1.1 is # UNFL : no
2111 1.1 is # DZ : no
2112 1.1 is # INEX2 : yes
2113 1.1 is # INEX1 : no
2114 1.1 is
2115 1.1 is # determine the highest priority exception(if any) set by the
2116 1.1 is # emulation routine that has also been enabled by the user.
2117 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
2118 1.1 is bne.w fu_out_ena_p # some are enabled
2119 1.1 is
2120 1.1 is fu_out_exit_p:
2121 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6
2122 1.1 is
2123 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor?
2124 1.1 is bne.b fu_out_exit_s_p # supervisor
2125 1.1 is
2126 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7
2127 1.1 is mov.l %a0,%usp
2128 1.1 is
2129 1.1 is fu_out_exit_cont_p:
2130 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2131 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2132 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2133 1.1 is
2134 1.1 is unlk %a6 # unravel stack frame
2135 1.1 is
2136 1.1 is btst &0x7,(%sp) # is trace on?
2137 1.1 is bne.w fu_trace_p # yes
2138 1.1 is
2139 1.1 is bra.l _fpsp_done # exit to os
2140 1.1 is
2141 1.1 is # the exception occurred in supervisor mode. check to see if the
2142 1.1 is # addressing mode was -(a7). if so, we'll need to shift the
2143 1.1 is # stack frame "down".
2144 1.1 is fu_out_exit_s_p:
2145 1.1 is btst &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
2146 1.1 is beq.b fu_out_exit_cont_p # no
2147 1.1 is
2148 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2149 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2150 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2151 1.1 is
2152 1.1 is mov.l (%a6),%a6 # restore frame pointer
2153 1.1 is
2154 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2155 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2156 1.1 is
2157 1.1 is # now, copy the result to the proper place on the stack
2158 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
2159 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
2160 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
2161 1.1 is
2162 1.1 is add.l &LOCAL_SIZE-0x8,%sp
2163 1.1 is
2164 1.1 is btst &0x7,(%sp)
2165 1.1 is bne.w fu_trace_p
2166 1.1 is
2167 1.1 is bra.l _fpsp_done
2168 1.1 is
2169 1.1 is fu_out_ena_p:
2170 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
2171 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception
2172 1.1 is beq.w fu_out_exit_p
2173 1.1 is
2174 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6
2175 1.1 is
2176 1.1 is # an exception occurred and that exception was enabled.
2177 1.1 is # the only exception possible on packed move out are INEX, OPERR, and SNAN.
2178 1.1 is fu_out_exc_p:
2179 1.1 is cmpi.b %d0,&0x1a
2180 1.1 is bgt.w fu_inex_p2
2181 1.1 is beq.w fu_operr_p
2182 1.1 is
2183 1.1 is fu_snan_p:
2184 1.1 is btst &0x5,EXC_SR(%a6)
2185 1.1 is bne.b fu_snan_s_p
2186 1.1 is
2187 1.1 is mov.l EXC_A7(%a6),%a0
2188 1.1 is mov.l %a0,%usp
2189 1.1 is bra.w fu_snan
2190 1.1 is
2191 1.1 is fu_snan_s_p:
2192 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
2193 1.1 is bne.w fu_snan
2194 1.1 is
2195 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2196 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we
2197 1.1 is # can store the default result where the exception frame was.
2198 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2199 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2200 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2201 1.1 is
2202 1.1 is mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd0
2203 1.1 is mov.w &0xe006,2+FP_SRC(%a6) # set fsave status
2204 1.1 is
2205 1.1 is frestore FP_SRC(%a6) # restore src operand
2206 1.1 is
2207 1.1 is mov.l (%a6),%a6 # restore frame pointer
2208 1.1 is
2209 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2210 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2211 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2212 1.1 is
2213 1.1 is # now, we copy the default result to it's proper location
2214 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2215 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2216 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2217 1.1 is
2218 1.1 is add.l &LOCAL_SIZE-0x8,%sp
2219 1.1 is
2220 1.1 is
2221 1.1 is bra.l _real_snan
2222 1.1 is
2223 1.1 is fu_operr_p:
2224 1.1 is btst &0x5,EXC_SR(%a6)
2225 1.1 is bne.w fu_operr_p_s
2226 1.1 is
2227 1.1 is mov.l EXC_A7(%a6),%a0
2228 1.1 is mov.l %a0,%usp
2229 1.1 is bra.w fu_operr
2230 1.1 is
2231 1.1 is fu_operr_p_s:
2232 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
2233 1.1 is bne.w fu_operr
2234 1.1 is
2235 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2236 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we
2237 1.1 is # can store the default result where the exception frame was.
2238 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2239 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2240 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2241 1.1 is
2242 1.1 is mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0
2243 1.1 is mov.w &0xe004,2+FP_SRC(%a6) # set fsave status
2244 1.1 is
2245 1.1 is frestore FP_SRC(%a6) # restore src operand
2246 1.1 is
2247 1.1 is mov.l (%a6),%a6 # restore frame pointer
2248 1.1 is
2249 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2250 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2251 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2252 1.1 is
2253 1.1 is # now, we copy the default result to it's proper location
2254 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2255 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2256 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2257 1.1 is
2258 1.1 is add.l &LOCAL_SIZE-0x8,%sp
2259 1.1 is
2260 1.1 is
2261 1.1 is bra.l _real_operr
2262 1.1 is
2263 1.1 is fu_inex_p2:
2264 1.1 is btst &0x5,EXC_SR(%a6)
2265 1.1 is bne.w fu_inex_s_p2
2266 1.1 is
2267 1.1 is mov.l EXC_A7(%a6),%a0
2268 1.1 is mov.l %a0,%usp
2269 1.1 is bra.w fu_inex
2270 1.1 is
2271 1.1 is fu_inex_s_p2:
2272 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
2273 1.1 is bne.w fu_inex
2274 1.1 is
2275 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2276 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we
2277 1.1 is # can store the default result where the exception frame was.
2278 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2279 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2280 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2281 1.1 is
2282 1.1 is mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4
2283 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # set fsave status
2284 1.1 is
2285 1.1 is frestore FP_SRC(%a6) # restore src operand
2286 1.1 is
2287 1.1 is mov.l (%a6),%a6 # restore frame pointer
2288 1.1 is
2289 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2290 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2291 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2292 1.1 is
2293 1.1 is # now, we copy the default result to it's proper location
2294 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2295 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2296 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2297 1.1 is
2298 1.1 is add.l &LOCAL_SIZE-0x8,%sp
2299 1.1 is
2300 1.1 is
2301 1.1 is bra.l _real_inex
2302 1.1 is
2303 1.1 is #########################################################################
2304 1.1 is
2305 1.1 is #
2306 1.1 is # if we're stuffing a source operand back into an fsave frame then we
2307 1.1 is # have to make sure that for single or double source operands that the
2308 1.1 is # format stuffed is as weird as the hardware usually makes it.
2309 1.1 is #
2310 1.1 is global funimp_skew
2311 1.1 is funimp_skew:
2312 1.1 is bfextu EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
2313 1.1 is cmpi.b %d0,&0x1 # was src sgl?
2314 1.1 is beq.b funimp_skew_sgl # yes
2315 1.1 is cmpi.b %d0,&0x5 # was src dbl?
2316 1.1 is beq.b funimp_skew_dbl # yes
2317 1.1 is rts
2318 1.1 is
2319 1.1 is funimp_skew_sgl:
2320 1.1 is mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent
2321 1.1 is andi.w &0x7fff,%d0 # strip sign
2322 1.1 is beq.b funimp_skew_sgl_not
2323 1.1 is cmpi.w %d0,&0x3f80
2324 1.1 is bgt.b funimp_skew_sgl_not
2325 1.1 is neg.w %d0 # make exponent negative
2326 1.1 is addi.w &0x3f81,%d0 # find amt to shift
2327 1.1 is mov.l FP_SRC_HI(%a6),%d1 # fetch DENORM hi(man)
2328 1.1 is lsr.l %d0,%d1 # shift it
2329 1.1 is bset &31,%d1 # set j-bit
2330 1.1 is mov.l %d1,FP_SRC_HI(%a6) # insert new hi(man)
2331 1.1 is andi.w &0x8000,FP_SRC_EX(%a6) # clear old exponent
2332 1.1 is ori.w &0x3f80,FP_SRC_EX(%a6) # insert new "skewed" exponent
2333 1.1 is funimp_skew_sgl_not:
2334 1.1 is rts
2335 1.1 is
2336 1.1 is funimp_skew_dbl:
2337 1.1 is mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent
2338 1.1 is andi.w &0x7fff,%d0 # strip sign
2339 1.1 is beq.b funimp_skew_dbl_not
2340 1.1 is cmpi.w %d0,&0x3c00
2341 1.1 is bgt.b funimp_skew_dbl_not
2342 1.1 is
2343 1.1 is tst.b FP_SRC_EX(%a6) # make "internal format"
2344 1.1 is smi.b 0x2+FP_SRC(%a6)
2345 1.1 is mov.w %d0,FP_SRC_EX(%a6) # insert exponent with cleared sign
2346 1.1 is clr.l %d0 # clear g,r,s
2347 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src op
2348 1.1 is mov.w &0x3c01,%d1 # pass denorm threshold
2349 1.1 is bsr.l dnrm_lp # denorm it
2350 1.1 is mov.w &0x3c00,%d0 # new exponent
2351 1.1 is tst.b 0x2+FP_SRC(%a6) # is sign set?
2352 1.1 is beq.b fss_dbl_denorm_done # no
2353 1.1 is bset &15,%d0 # set sign
2354 1.1 is fss_dbl_denorm_done:
2355 1.1 is bset &0x7,FP_SRC_HI(%a6) # set j-bit
2356 1.1 is mov.w %d0,FP_SRC_EX(%a6) # insert new exponent
2357 1.1 is funimp_skew_dbl_not:
2358 1.1 is rts
2359 1.1 is
2360 1.1 is #########################################################################
2361 1.1 is global _mem_write2
2362 1.1 is _mem_write2:
2363 1.1 is btst &0x5,EXC_SR(%a6)
2364 1.1 is beq.l _dmem_write
2365 1.1 is mov.l 0x0(%a0),FP_DST_EX(%a6)
2366 1.1 is mov.l 0x4(%a0),FP_DST_HI(%a6)
2367 1.1 is mov.l 0x8(%a0),FP_DST_LO(%a6)
2368 1.1 is clr.l %d1
2369 1.1 is rts
2370 1.1 is
2371 1.1 is #########################################################################
2372 1.1 is # XDEF **************************************************************** #
2373 1.1 is # _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented #
2374 1.1 is # effective address" exception. #
2375 1.1 is # #
2376 1.1 is # This handler should be the first code executed upon taking the #
2377 1.1 is # FP Unimplemented Effective Address exception in an operating #
2378 1.1 is # system. #
2379 1.1 is # #
2380 1.1 is # XREF **************************************************************** #
2381 1.1 is # _imem_read_long() - read instruction longword #
2382 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
2383 1.1 is # set_tag_x() - determine optype of src/dst operands #
2384 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile #
2385 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO #
2386 1.1 is # load_fpn2() - load dst operand from FP regfile #
2387 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 #
2388 1.1 is # decbin() - convert packed data to FP binary data #
2389 1.1 is # _real_fpu_disabled() - "callout" for "FPU disabled" exception #
2390 1.1 is # _real_access() - "callout" for access error exception #
2391 1.1 is # _mem_read() - read extended immediate operand from memory #
2392 1.1 is # _fpsp_done() - "callout" for exit; work all done #
2393 1.1 is # _real_trace() - "callout" for Trace enabled exception #
2394 1.1 is # fmovm_dynamic() - emulate dynamic fmovm instruction #
2395 1.1 is # fmovm_ctrl() - emulate fmovm control instruction #
2396 1.1 is # #
2397 1.1 is # INPUT *************************************************************** #
2398 1.1 is # - The system stack contains the "Unimplemented <ea>" stk frame #
2399 1.1 is # #
2400 1.1 is # OUTPUT ************************************************************** #
2401 1.1 is # If access error: #
2402 1.1 is # - The system stack is changed to an access error stack frame #
2403 1.1 is # If FPU disabled: #
2404 1.1 is # - The system stack is changed to an FPU disabled stack frame #
2405 1.1 is # If Trace exception enabled: #
2406 1.1 is # - The system stack is changed to a Trace exception stack frame #
2407 1.1 is # Else: (normal case) #
2408 1.1 is # - None (correct result has been stored as appropriate) #
2409 1.1 is # #
2410 1.1 is # ALGORITHM *********************************************************** #
2411 1.1 is # This exception handles 3 types of operations: #
2412 1.1 is # (1) FP Instructions using extended precision or packed immediate #
2413 1.1 is # addressing mode. #
2414 1.1 is # (2) The "fmovm.x" instruction w/ dynamic register specification. #
2415 1.1 is # (3) The "fmovm.l" instruction w/ 2 or 3 control registers. #
2416 1.1 is # #
2417 1.1 is # For immediate data operations, the data is read in w/ a #
2418 1.1 is # _mem_read() "callout", converted to FP binary (if packed), and used #
2419 1.1 is # as the source operand to the instruction specified by the instruction #
2420 1.1 is # word. If no FP exception should be reported ads a result of the #
2421 1.1 is # emulation, then the result is stored to the destination register and #
2422 1.1 is # the handler exits through _fpsp_done(). If an enabled exc has been #
2423 1.1 is # signalled as a result of emulation, then an fsave state frame #
2424 1.1 is # corresponding to the FP exception type must be entered into the 060 #
2425 1.1 is # FPU before exiting. In either the enabled or disabled cases, we #
2426 1.1 is # must also check if a Trace exception is pending, in which case, we #
2427 1.1 is # must create a Trace exception stack frame from the current exception #
2428 1.1 is # stack frame. If no Trace is pending, we simply exit through #
2429 1.1 is # _fpsp_done(). #
2430 1.1 is # For "fmovm.x", call the routine fmovm_dynamic() which will #
2431 1.1 is # decode and emulate the instruction. No FP exceptions can be pending #
2432 1.1 is # as a result of this operation emulation. A Trace exception can be #
2433 1.1 is # pending, though, which means the current stack frame must be changed #
2434 1.1 is # to a Trace stack frame and an exit made through _real_trace(). #
2435 1.1 is # For the case of "fmovm.x Dn,-(a7)", where the offending instruction #
2436 1.1 is # was executed from supervisor mode, this handler must store the FP #
2437 1.1 is # register file values to the system stack by itself since #
2438 1.1 is # fmovm_dynamic() can't handle this. A normal exit is made through #
2439 1.1 is # fpsp_done(). #
2440 1.1 is # For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. #
2441 1.1 is # Again, a Trace exception may be pending and an exit made through #
2442 1.1 is # _real_trace(). Else, a normal exit is made through _fpsp_done(). #
2443 1.1 is # #
2444 1.1 is # Before any of the above is attempted, it must be checked to #
2445 1.1 is # see if the FPU is disabled. Since the "Unimp <ea>" exception is taken #
2446 1.1 is # before the "FPU disabled" exception, but the "FPU disabled" exception #
2447 1.1 is # has higher priority, we check the disabled bit in the PCR. If set, #
2448 1.1 is # then we must create an 8 word "FPU disabled" exception stack frame #
2449 1.1 is # from the current 4 word exception stack frame. This includes #
2450 1.1 is # reproducing the effective address of the instruction to put on the #
2451 1.1 is # new stack frame. #
2452 1.1 is # #
2453 1.1 is # In the process of all emulation work, if a _mem_read() #
2454 1.1 is # "callout" returns a failing result indicating an access error, then #
2455 1.1 is # we must create an access error stack frame from the current stack #
2456 1.1 is # frame. This information includes a faulting address and a fault- #
2457 1.1 is # status-longword. These are created within this handler. #
2458 1.1 is # #
2459 1.1 is #########################################################################
2460 1.1 is
2461 1.1 is global _fpsp_effadd
2462 1.1 is _fpsp_effadd:
2463 1.1 is
2464 1.1 is # This exception type takes priority over the "Line F Emulator"
2465 1.1 is # exception. Therefore, the FPU could be disabled when entering here.
2466 1.1 is # So, we must check to see if it's disabled and handle that case separately.
2467 1.1 is mov.l %d0,-(%sp) # save d0
2468 1.1 is movc %pcr,%d0 # load proc cr
2469 1.1 is btst &0x1,%d0 # is FPU disabled?
2470 1.1 is bne.w iea_disabled # yes
2471 1.1 is mov.l (%sp)+,%d0 # restore d0
2472 1.1 is
2473 1.1 is link %a6,&-LOCAL_SIZE # init stack frame
2474 1.1 is
2475 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
2476 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
2477 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
2478 1.1 is
2479 1.1 is # PC of instruction that took the exception is the PC in the frame
2480 1.1 is mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6)
2481 1.1 is
2482 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
2483 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
2484 1.1 is bsr.l _imem_read_long # fetch the instruction words
2485 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
2486 1.1 is
2487 1.1 is #########################################################################
2488 1.1 is
2489 1.1 is tst.w %d0 # is operation fmovem?
2490 1.1 is bmi.w iea_fmovm # yes
2491 1.1 is
2492 1.1 is #
2493 1.1 is # here, we will have:
2494 1.1 is # fabs fdabs fsabs facos fmod
2495 1.1 is # fadd fdadd fsadd fasin frem
2496 1.1 is # fcmp fatan fscale
2497 1.1 is # fdiv fddiv fsdiv fatanh fsin
2498 1.1 is # fint fcos fsincos
2499 1.1 is # fintrz fcosh fsinh
2500 1.1 is # fmove fdmove fsmove fetox ftan
2501 1.1 is # fmul fdmul fsmul fetoxm1 ftanh
2502 1.1 is # fneg fdneg fsneg fgetexp ftentox
2503 1.1 is # fsgldiv fgetman ftwotox
2504 1.1 is # fsglmul flog10
2505 1.1 is # fsqrt flog2
2506 1.1 is # fsub fdsub fssub flogn
2507 1.1 is # ftst flognp1
2508 1.1 is # which can all use f<op>.{x,p}
2509 1.1 is # so, now it's immediate data extended precision AND PACKED FORMAT!
2510 1.1 is #
2511 1.1 is iea_op:
2512 1.1 is andi.l &0x00ff00ff,USER_FPSR(%a6)
2513 1.1 is
2514 1.1 is btst &0xa,%d0 # is src fmt x or p?
2515 1.1 is bne.b iea_op_pack # packed
2516 1.1 is
2517 1.1 is
2518 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data>
2519 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super addr
2520 1.1 is mov.l &0xc,%d0 # pass: 12 bytes
2521 1.1 is bsr.l _imem_read # read extended immediate
2522 1.1 is
2523 1.1 is tst.l %d1 # did ifetch fail?
2524 1.1 is bne.w iea_iacc # yes
2525 1.1 is
2526 1.1 is bra.b iea_op_setsrc
2527 1.1 is
2528 1.1 is iea_op_pack:
2529 1.1 is
2530 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data>
2531 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super dst
2532 1.1 is mov.l &0xc,%d0 # pass: 12 bytes
2533 1.1 is bsr.l _imem_read # read packed operand
2534 1.1 is
2535 1.1 is tst.l %d1 # did ifetch fail?
2536 1.1 is bne.w iea_iacc # yes
2537 1.1 is
2538 1.1 is # The packed operand is an INF or a NAN if the exponent field is all ones.
2539 1.1 is bfextu FP_SRC(%a6){&1:&15},%d0 # get exp
2540 1.1 is cmpi.w %d0,&0x7fff # INF or NAN?
2541 1.1 is beq.b iea_op_setsrc # operand is an INF or NAN
2542 1.1 is
2543 1.1 is # The packed operand is a zero if the mantissa is all zero, else it's
2544 1.1 is # a normal packed op.
2545 1.1 is mov.b 3+FP_SRC(%a6),%d0 # get byte 4
2546 1.1 is andi.b &0x0f,%d0 # clear all but last nybble
2547 1.1 is bne.b iea_op_gp_not_spec # not a zero
2548 1.1 is tst.l FP_SRC_HI(%a6) # is lw 2 zero?
2549 1.1 is bne.b iea_op_gp_not_spec # not a zero
2550 1.1 is tst.l FP_SRC_LO(%a6) # is lw 3 zero?
2551 1.1 is beq.b iea_op_setsrc # operand is a ZERO
2552 1.1 is iea_op_gp_not_spec:
2553 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to packed op
2554 1.1 is bsr.l decbin # convert to extended
2555 1.1 is fmovm.x &0x80,FP_SRC(%a6) # make this the srcop
2556 1.1 is
2557 1.1 is iea_op_setsrc:
2558 1.1 is addi.l &0xc,EXC_EXTWPTR(%a6) # update extension word pointer
2559 1.1 is
2560 1.1 is # FP_SRC now holds the src operand.
2561 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
2562 1.1 is bsr.l set_tag_x # tag the operand type
2563 1.1 is mov.b %d0,STAG(%a6) # could be ANYTHING!!!
2564 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
2565 1.1 is bne.b iea_op_getdst # no
2566 1.1 is bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO
2567 1.1 is mov.b %d0,STAG(%a6) # set new optype tag
2568 1.1 is iea_op_getdst:
2569 1.1 is clr.b STORE_FLG(%a6) # clear "store result" boolean
2570 1.1 is
2571 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
2572 1.1 is beq.b iea_op_extract # monadic
2573 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is operation fsincos,ftst,fcmp?
2574 1.1 is bne.b iea_op_spec # yes
2575 1.1 is
2576 1.1 is iea_op_loaddst:
2577 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2578 1.1 is bsr.l load_fpn2 # load dst operand
2579 1.1 is
2580 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
2581 1.1 is bsr.l set_tag_x # tag the operand type
2582 1.1 is mov.b %d0,DTAG(%a6) # could be ANYTHING!!!
2583 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
2584 1.1 is bne.b iea_op_extract # no
2585 1.1 is bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO
2586 1.1 is mov.b %d0,DTAG(%a6) # set new optype tag
2587 1.1 is bra.b iea_op_extract
2588 1.1 is
2589 1.1 is # the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
2590 1.1 is iea_op_spec:
2591 1.1 is btst &0x3,1+EXC_CMDREG(%a6) # is operation fsincos?
2592 1.1 is beq.b iea_op_extract # yes
2593 1.1 is # now, we're left with ftst and fcmp. so, first let's tag them so that they don't
2594 1.1 is # store a result. then, only fcmp will branch back and pick up a dst operand.
2595 1.1 is st STORE_FLG(%a6) # don't store a final result
2596 1.1 is btst &0x1,1+EXC_CMDREG(%a6) # is operation fcmp?
2597 1.1 is beq.b iea_op_loaddst # yes
2598 1.1 is
2599 1.1 is iea_op_extract:
2600 1.1 is clr.l %d0
2601 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass: rnd mode,prec
2602 1.1 is
2603 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1
2604 1.1 is andi.w &0x007f,%d1 # extract extension
2605 1.1 is
2606 1.1 is fmov.l &0x0,%fpcr
2607 1.1 is fmov.l &0x0,%fpsr
2608 1.1 is
2609 1.1 is lea FP_SRC(%a6),%a0
2610 1.1 is lea FP_DST(%a6),%a1
2611 1.1 is
2612 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
2613 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
2614 1.1 is
2615 1.1 is #
2616 1.1 is # Exceptions in order of precedence:
2617 1.1 is # BSUN : none
2618 1.1 is # SNAN : all operations
2619 1.1 is # OPERR : all reg-reg or mem-reg operations that can normally operr
2620 1.1 is # OVFL : same as OPERR
2621 1.1 is # UNFL : same as OPERR
2622 1.1 is # DZ : same as OPERR
2623 1.1 is # INEX2 : same as OPERR
2624 1.1 is # INEX1 : all packed immediate operations
2625 1.1 is #
2626 1.1 is
2627 1.1 is # we determine the highest priority exception(if any) set by the
2628 1.1 is # emulation routine that has also been enabled by the user.
2629 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
2630 1.1 is bne.b iea_op_ena # some are enabled
2631 1.1 is
2632 1.1 is # now, we save the result, unless, of course, the operation was ftst or fcmp.
2633 1.1 is # these don't save results.
2634 1.1 is iea_op_save:
2635 1.1 is tst.b STORE_FLG(%a6) # does this op store a result?
2636 1.1 is bne.b iea_op_exit1 # exit with no frestore
2637 1.1 is
2638 1.1 is iea_op_store:
2639 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2640 1.1 is bsr.l store_fpreg # store the result
2641 1.1 is
2642 1.1 is iea_op_exit1:
2643 1.1 is mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2644 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2645 1.1 is
2646 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2647 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2648 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2649 1.1 is
2650 1.1 is unlk %a6 # unravel the frame
2651 1.1 is
2652 1.1 is btst &0x7,(%sp) # is trace on?
2653 1.1 is bne.w iea_op_trace # yes
2654 1.1 is
2655 1.1 is bra.l _fpsp_done # exit to os
2656 1.1 is
2657 1.1 is iea_op_ena:
2658 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enable and set
2659 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception
2660 1.1 is bne.b iea_op_exc # at least one was set
2661 1.1 is
2662 1.1 is # no exception occurred. now, did a disabled, exact overflow occur with inexact
2663 1.1 is # enabled? if so, then we have to stuff an overflow frame into the FPU.
2664 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2665 1.1 is beq.b iea_op_save
2666 1.1 is
2667 1.1 is iea_op_ovfl:
2668 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
2669 1.1 is beq.b iea_op_store # no
2670 1.1 is bra.b iea_op_exc_ovfl # yes
2671 1.1 is
2672 1.1 is # an enabled exception occurred. we have to insert the exception type back into
2673 1.1 is # the machine.
2674 1.1 is iea_op_exc:
2675 1.1 is subi.l &24,%d0 # fix offset to be 0-8
2676 1.1 is cmpi.b %d0,&0x6 # is exception INEX?
2677 1.1 is bne.b iea_op_exc_force # no
2678 1.1 is
2679 1.1 is # the enabled exception was inexact. so, if it occurs with an overflow
2680 1.1 is # or underflow that was disabled, then we have to force an overflow or
2681 1.1 is # underflow frame.
2682 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2683 1.1 is bne.b iea_op_exc_ovfl # yes
2684 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
2685 1.1 is bne.b iea_op_exc_unfl # yes
2686 1.1 is
2687 1.1 is iea_op_exc_force:
2688 1.1 is mov.w (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2689 1.1 is bra.b iea_op_exit2 # exit with frestore
2690 1.1 is
2691 1.1 is tbl_iea_except:
2692 1.1 is short 0xe002, 0xe006, 0xe004, 0xe005
2693 1.1 is short 0xe003, 0xe002, 0xe001, 0xe001
2694 1.1 is
2695 1.1 is iea_op_exc_ovfl:
2696 1.1 is mov.w &0xe005,2+FP_SRC(%a6)
2697 1.1 is bra.b iea_op_exit2
2698 1.1 is
2699 1.1 is iea_op_exc_unfl:
2700 1.1 is mov.w &0xe003,2+FP_SRC(%a6)
2701 1.1 is
2702 1.1 is iea_op_exit2:
2703 1.1 is mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2704 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2705 1.1 is
2706 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2707 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2708 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2709 1.1 is
2710 1.1 is frestore FP_SRC(%a6) # restore exceptional state
2711 1.1 is
2712 1.1 is unlk %a6 # unravel the frame
2713 1.1 is
2714 1.1 is btst &0x7,(%sp) # is trace on?
2715 1.1 is bne.b iea_op_trace # yes
2716 1.1 is
2717 1.1 is bra.l _fpsp_done # exit to os
2718 1.1 is
2719 1.1 is #
2720 1.1 is # The opclass two instruction that took an "Unimplemented Effective Address"
2721 1.1 is # exception was being traced. Make the "current" PC the FPIAR and put it in
2722 1.1 is # the trace stack frame then jump to _real_trace().
2723 1.1 is #
2724 1.1 is # UNIMP EA FRAME TRACE FRAME
2725 1.1 is # ***************** *****************
2726 1.1 is # * 0x0 * 0x0f0 * * Current *
2727 1.1 is # ***************** * PC *
2728 1.1 is # * Current * *****************
2729 1.1 is # * PC * * 0x2 * 0x024 *
2730 1.1 is # ***************** *****************
2731 1.1 is # * SR * * Next *
2732 1.1 is # ***************** * PC *
2733 1.1 is # *****************
2734 1.1 is # * SR *
2735 1.1 is # *****************
2736 1.1 is iea_op_trace:
2737 1.1 is mov.l (%sp),-(%sp) # shift stack frame "down"
2738 1.1 is mov.w 0x8(%sp),0x4(%sp)
2739 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
2740 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
2741 1.1 is
2742 1.1 is bra.l _real_trace
2743 1.1 is
2744 1.1 is #########################################################################
2745 1.1 is iea_fmovm:
2746 1.1 is btst &14,%d0 # ctrl or data reg
2747 1.1 is beq.w iea_fmovm_ctrl
2748 1.1 is
2749 1.1 is iea_fmovm_data:
2750 1.1 is
2751 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode
2752 1.1 is bne.b iea_fmovm_data_s
2753 1.1 is
2754 1.1 is iea_fmovm_data_u:
2755 1.1 is mov.l %usp,%a0
2756 1.1 is mov.l %a0,EXC_A7(%a6) # store current a7
2757 1.1 is bsr.l fmovm_dynamic # do dynamic fmovm
2758 1.1 is mov.l EXC_A7(%a6),%a0 # load possibly new a7
2759 1.1 is mov.l %a0,%usp # update usp
2760 1.1 is bra.w iea_fmovm_exit
2761 1.1 is
2762 1.1 is iea_fmovm_data_s:
2763 1.1 is clr.b SPCOND_FLG(%a6)
2764 1.1 is lea 0x2+EXC_VOFF(%a6),%a0
2765 1.1 is mov.l %a0,EXC_A7(%a6)
2766 1.1 is bsr.l fmovm_dynamic # do dynamic fmovm
2767 1.1 is
2768 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
2769 1.1 is beq.w iea_fmovm_data_predec
2770 1.1 is cmpi.b SPCOND_FLG(%a6),&mia7_flg
2771 1.1 is bne.w iea_fmovm_exit
2772 1.1 is
2773 1.1 is # right now, d0 = the size.
2774 1.1 is # the data has been fetched from the supervisor stack, but we have not
2775 1.1 is # incremented the stack pointer by the appropriate number of bytes.
2776 1.1 is # do it here.
2777 1.1 is iea_fmovm_data_postinc:
2778 1.1 is btst &0x7,EXC_SR(%a6)
2779 1.1 is bne.b iea_fmovm_data_pi_trace
2780 1.1 is
2781 1.1 is mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0)
2782 1.1 is mov.l EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
2783 1.1 is mov.w &0x00f0,(EXC_VOFF,%a6,%d0)
2784 1.1 is
2785 1.1 is lea (EXC_SR,%a6,%d0),%a0
2786 1.1 is mov.l %a0,EXC_SR(%a6)
2787 1.1 is
2788 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2789 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2790 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2791 1.1 is
2792 1.1 is unlk %a6
2793 1.1 is mov.l (%sp)+,%sp
2794 1.1 is bra.l _fpsp_done
2795 1.1 is
2796 1.1 is iea_fmovm_data_pi_trace:
2797 1.1 is mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2798 1.1 is mov.l EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
2799 1.1 is mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2800 1.1 is mov.l EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
2801 1.1 is
2802 1.1 is lea (EXC_SR-0x4,%a6,%d0),%a0
2803 1.1 is mov.l %a0,EXC_SR(%a6)
2804 1.1 is
2805 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2806 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2807 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2808 1.1 is
2809 1.1 is unlk %a6
2810 1.1 is mov.l (%sp)+,%sp
2811 1.1 is bra.l _real_trace
2812 1.1 is
2813 1.1 is # right now, d1 = size and d0 = the strg.
2814 1.1 is iea_fmovm_data_predec:
2815 1.1 is mov.b %d1,EXC_VOFF(%a6) # store strg
2816 1.1 is mov.b %d0,0x1+EXC_VOFF(%a6) # store size
2817 1.1 is
2818 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2819 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2820 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2821 1.1 is
2822 1.1 is mov.l (%a6),-(%sp) # make a copy of a6
2823 1.1 is mov.l %d0,-(%sp) # save d0
2824 1.1 is mov.l %d1,-(%sp) # save d1
2825 1.1 is mov.l EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC
2826 1.1 is
2827 1.1 is clr.l %d0
2828 1.1 is mov.b 0x1+EXC_VOFF(%a6),%d0 # fetch size
2829 1.1 is neg.l %d0 # get negative of size
2830 1.1 is
2831 1.1 is btst &0x7,EXC_SR(%a6) # is trace enabled?
2832 1.1 is beq.b iea_fmovm_data_p2
2833 1.1 is
2834 1.1 is mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2835 1.1 is mov.l EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
2836 1.1 is mov.l (%sp)+,(EXC_PC-0x4,%a6,%d0)
2837 1.1 is mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2838 1.1 is
2839 1.1 is pea (%a6,%d0) # create final sp
2840 1.1 is bra.b iea_fmovm_data_p3
2841 1.1 is
2842 1.1 is iea_fmovm_data_p2:
2843 1.1 is mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0)
2844 1.1 is mov.l (%sp)+,(EXC_PC,%a6,%d0)
2845 1.1 is mov.w &0x00f0,(EXC_VOFF,%a6,%d0)
2846 1.1 is
2847 1.1 is pea (0x4,%a6,%d0) # create final sp
2848 1.1 is
2849 1.1 is iea_fmovm_data_p3:
2850 1.1 is clr.l %d1
2851 1.1 is mov.b EXC_VOFF(%a6),%d1 # fetch strg
2852 1.1 is
2853 1.1 is tst.b %d1
2854 1.1 is bpl.b fm_1
2855 1.1 is fmovm.x &0x80,(0x4+0x8,%a6,%d0)
2856 1.1 is addi.l &0xc,%d0
2857 1.1 is fm_1:
2858 1.1 is lsl.b &0x1,%d1
2859 1.1 is bpl.b fm_2
2860 1.1 is fmovm.x &0x40,(0x4+0x8,%a6,%d0)
2861 1.1 is addi.l &0xc,%d0
2862 1.1 is fm_2:
2863 1.1 is lsl.b &0x1,%d1
2864 1.1 is bpl.b fm_3
2865 1.1 is fmovm.x &0x20,(0x4+0x8,%a6,%d0)
2866 1.1 is addi.l &0xc,%d0
2867 1.1 is fm_3:
2868 1.1 is lsl.b &0x1,%d1
2869 1.1 is bpl.b fm_4
2870 1.1 is fmovm.x &0x10,(0x4+0x8,%a6,%d0)
2871 1.1 is addi.l &0xc,%d0
2872 1.1 is fm_4:
2873 1.1 is lsl.b &0x1,%d1
2874 1.1 is bpl.b fm_5
2875 1.1 is fmovm.x &0x08,(0x4+0x8,%a6,%d0)
2876 1.1 is addi.l &0xc,%d0
2877 1.1 is fm_5:
2878 1.1 is lsl.b &0x1,%d1
2879 1.1 is bpl.b fm_6
2880 1.1 is fmovm.x &0x04,(0x4+0x8,%a6,%d0)
2881 1.1 is addi.l &0xc,%d0
2882 1.1 is fm_6:
2883 1.1 is lsl.b &0x1,%d1
2884 1.1 is bpl.b fm_7
2885 1.1 is fmovm.x &0x02,(0x4+0x8,%a6,%d0)
2886 1.1 is addi.l &0xc,%d0
2887 1.1 is fm_7:
2888 1.1 is lsl.b &0x1,%d1
2889 1.1 is bpl.b fm_end
2890 1.1 is fmovm.x &0x01,(0x4+0x8,%a6,%d0)
2891 1.1 is fm_end:
2892 1.1 is mov.l 0x4(%sp),%d1
2893 1.1 is mov.l 0x8(%sp),%d0
2894 1.1 is mov.l 0xc(%sp),%a6
2895 1.1 is mov.l (%sp)+,%sp
2896 1.1 is
2897 1.1 is btst &0x7,(%sp) # is trace enabled?
2898 1.1 is beq.l _fpsp_done
2899 1.1 is bra.l _real_trace
2900 1.1 is
2901 1.1 is #########################################################################
2902 1.1 is iea_fmovm_ctrl:
2903 1.1 is
2904 1.1 is bsr.l fmovm_ctrl # load ctrl regs
2905 1.1 is
2906 1.1 is iea_fmovm_exit:
2907 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2908 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2909 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2910 1.1 is
2911 1.1 is btst &0x7,EXC_SR(%a6) # is trace on?
2912 1.1 is bne.b iea_fmovm_trace # yes
2913 1.1 is
2914 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
2915 1.1 is
2916 1.1 is unlk %a6 # unravel the frame
2917 1.1 is
2918 1.1 is bra.l _fpsp_done # exit to os
2919 1.1 is
2920 1.1 is #
2921 1.1 is # The control reg instruction that took an "Unimplemented Effective Address"
2922 1.1 is # exception was being traced. The "Current PC" for the trace frame is the
2923 1.1 is # PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
2924 1.1 is # After fixing the stack frame, jump to _real_trace().
2925 1.1 is #
2926 1.1 is # UNIMP EA FRAME TRACE FRAME
2927 1.1 is # ***************** *****************
2928 1.1 is # * 0x0 * 0x0f0 * * Current *
2929 1.1 is # ***************** * PC *
2930 1.1 is # * Current * *****************
2931 1.1 is # * PC * * 0x2 * 0x024 *
2932 1.1 is # ***************** *****************
2933 1.1 is # * SR * * Next *
2934 1.1 is # ***************** * PC *
2935 1.1 is # *****************
2936 1.1 is # * SR *
2937 1.1 is # *****************
2938 1.1 is # this ain't a pretty solution, but it works:
2939 1.1 is # -restore a6 (not with unlk)
2940 1.1 is # -shift stack frame down over where old a6 used to be
2941 1.1 is # -add LOCAL_SIZE to stack pointer
2942 1.1 is iea_fmovm_trace:
2943 1.1 is mov.l (%a6),%a6 # restore frame pointer
2944 1.1 is mov.w EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
2945 1.1 is mov.l EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
2946 1.1 is mov.l EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
2947 1.1 is mov.w &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
2948 1.1 is add.l &LOCAL_SIZE,%sp # clear stack frame
2949 1.1 is
2950 1.1 is bra.l _real_trace
2951 1.1 is
2952 1.1 is #########################################################################
2953 1.1 is # The FPU is disabled and so we should really have taken the "Line
2954 1.1 is # F Emulator" exception. So, here we create an 8-word stack frame
2955 1.1 is # from our 4-word stack frame. This means we must calculate the length
2956 1.1 is # of the faulting instruction to get the "next PC". This is trivial for
2957 1.1 is # immediate operands but requires some extra work for fmovm dynamic
2958 1.1 is # which can use most addressing modes.
2959 1.1 is iea_disabled:
2960 1.1 is mov.l (%sp)+,%d0 # restore d0
2961 1.1 is
2962 1.1 is link %a6,&-LOCAL_SIZE # init stack frame
2963 1.1 is
2964 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
2965 1.1 is
2966 1.1 is # PC of instruction that took the exception is the PC in the frame
2967 1.1 is mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6)
2968 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
2969 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
2970 1.1 is bsr.l _imem_read_long # fetch the instruction words
2971 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
2972 1.1 is
2973 1.1 is tst.w %d0 # is instr fmovm?
2974 1.1 is bmi.b iea_dis_fmovm # yes
2975 1.1 is # instruction is using an extended precision immediate operand. therefore,
2976 1.1 is # the total instruction length is 16 bytes.
2977 1.1 is iea_dis_immed:
2978 1.1 is mov.l &0x10,%d0 # 16 bytes of instruction
2979 1.1 is bra.b iea_dis_cont
2980 1.1 is iea_dis_fmovm:
2981 1.1 is btst &0xe,%d0 # is instr fmovm ctrl
2982 1.1 is bne.b iea_dis_fmovm_data # no
2983 1.1 is # the instruction is a fmovm.l with 2 or 3 registers.
2984 1.1 is bfextu %d0{&19:&3},%d1
2985 1.1 is mov.l &0xc,%d0
2986 1.1 is cmpi.b %d1,&0x7 # move all regs?
2987 1.1 is bne.b iea_dis_cont
2988 1.1 is addq.l &0x4,%d0
2989 1.1 is bra.b iea_dis_cont
2990 1.1 is # the instruction is an fmovm.x dynamic which can use many addressing
2991 1.1 is # modes and thus can have several different total instruction lengths.
2992 1.1 is # call fmovm_calc_ea which will go through the ea calc process and,
2993 1.1 is # as a by-product, will tell us how long the instruction is.
2994 1.1 is iea_dis_fmovm_data:
2995 1.1 is clr.l %d0
2996 1.1 is bsr.l fmovm_calc_ea
2997 1.1 is mov.l EXC_EXTWPTR(%a6),%d0
2998 1.1 is sub.l EXC_PC(%a6),%d0
2999 1.1 is iea_dis_cont:
3000 1.1 is mov.w %d0,EXC_VOFF(%a6) # store stack shift value
3001 1.1 is
3002 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3003 1.1 is
3004 1.1 is unlk %a6
3005 1.1 is
3006 1.1 is # here, we actually create the 8-word frame from the 4-word frame,
3007 1.1 is # with the "next PC" as additional info.
3008 1.1 is # the <ea> field is let as undefined.
3009 1.1 is subq.l &0x8,%sp # make room for new stack
3010 1.1 is mov.l %d0,-(%sp) # save d0
3011 1.1 is mov.w 0xc(%sp),0x4(%sp) # move SR
3012 1.1 is mov.l 0xe(%sp),0x6(%sp) # move Current PC
3013 1.1 is clr.l %d0
3014 1.1 is mov.w 0x12(%sp),%d0
3015 1.1 is mov.l 0x6(%sp),0x10(%sp) # move Current PC
3016 1.1 is add.l %d0,0x6(%sp) # make Next PC
3017 1.1 is mov.w &0x402c,0xa(%sp) # insert offset,frame format
3018 1.1 is mov.l (%sp)+,%d0 # restore d0
3019 1.1 is
3020 1.1 is bra.l _real_fpu_disabled
3021 1.1 is
3022 1.1 is ##########
3023 1.1 is
3024 1.1 is iea_iacc:
3025 1.1 is movc %pcr,%d0
3026 1.1 is btst &0x1,%d0
3027 1.1 is bne.b iea_iacc_cont
3028 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3029 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack
3030 1.1 is iea_iacc_cont:
3031 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3032 1.1 is
3033 1.1 is unlk %a6
3034 1.1 is
3035 1.1 is subq.w &0x8,%sp # make stack frame bigger
3036 1.1 is mov.l 0x8(%sp),(%sp) # store SR,hi(PC)
3037 1.1 is mov.w 0xc(%sp),0x4(%sp) # store lo(PC)
3038 1.1 is mov.w &0x4008,0x6(%sp) # store voff
3039 1.1 is mov.l 0x2(%sp),0x8(%sp) # store ea
3040 1.1 is mov.l &0x09428001,0xc(%sp) # store fslw
3041 1.1 is
3042 1.1 is iea_acc_done:
3043 1.1 is btst &0x5,(%sp) # user or supervisor mode?
3044 1.1 is beq.b iea_acc_done2 # user
3045 1.1 is bset &0x2,0xd(%sp) # set supervisor TM bit
3046 1.1 is
3047 1.1 is iea_acc_done2:
3048 1.1 is bra.l _real_access
3049 1.1 is
3050 1.1 is iea_dacc:
3051 1.1 is lea -LOCAL_SIZE(%a6),%sp
3052 1.1 is
3053 1.1 is movc %pcr,%d1
3054 1.1 is btst &0x1,%d1
3055 1.1 is bne.b iea_dacc_cont
3056 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack
3057 1.1 is fmovm.l LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3058 1.1 is iea_dacc_cont:
3059 1.1 is mov.l (%a6),%a6
3060 1.1 is
3061 1.1 is mov.l 0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3062 1.1 is mov.w 0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3063 1.1 is mov.w &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3064 1.1 is mov.l %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3065 1.1 is mov.w %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3066 1.1 is mov.w &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3067 1.1 is
3068 1.1 is movm.l LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3069 1.1 is add.w &LOCAL_SIZE-0x4,%sp
3070 1.1 is
3071 1.1 is bra.b iea_acc_done
3072 1.1 is
3073 1.1 is #########################################################################
3074 1.1 is # XDEF **************************************************************** #
3075 1.1 is # _fpsp_operr(): 060FPSP entry point for FP Operr exception. #
3076 1.1 is # #
3077 1.1 is # This handler should be the first code executed upon taking the #
3078 1.1 is # FP Operand Error exception in an operating system. #
3079 1.1 is # #
3080 1.1 is # XREF **************************************************************** #
3081 1.1 is # _imem_read_long() - read instruction longword #
3082 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
3083 1.1 is # _real_operr() - "callout" to operating system operr handler #
3084 1.1 is # _dmem_write_{byte,word,long}() - store data to mem (opclass 3) #
3085 1.1 is # store_dreg_{b,w,l}() - store data to data regfile (opclass 3) #
3086 1.1 is # facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3087 1.1 is # #
3088 1.1 is # INPUT *************************************************************** #
3089 1.1 is # - The system stack contains the FP Operr exception frame #
3090 1.1 is # - The fsave frame contains the source operand #
3091 1.1 is # #
3092 1.1 is # OUTPUT ************************************************************** #
3093 1.1 is # No access error: #
3094 1.1 is # - The system stack is unchanged #
3095 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 #
3096 1.1 is # #
3097 1.1 is # ALGORITHM *********************************************************** #
3098 1.1 is # In a system where the FP Operr exception is enabled, the goal #
3099 1.1 is # is to get to the handler specified at _real_operr(). But, on the 060, #
3100 1.1 is # for opclass zero and two instruction taking this exception, the #
3101 1.1 is # input operand in the fsave frame may be incorrect for some cases #
3102 1.1 is # and needs to be corrected. This handler calls fix_skewed_ops() to #
3103 1.1 is # do just this and then exits through _real_operr(). #
3104 1.1 is # For opclass 3 instructions, the 060 doesn't store the default #
3105 1.1 is # operr result out to memory or data register file as it should. #
3106 1.1 is # This code must emulate the move out before finally exiting through #
3107 1.1 is # _real_inex(). The move out, if to memory, is performed using #
3108 1.1 is # _mem_write() "callout" routines that may return a failing result. #
3109 1.1 is # In this special case, the handler must exit through facc_out() #
3110 1.1 is # which creates an access error stack frame from the current operr #
3111 1.1 is # stack frame. #
3112 1.1 is # #
3113 1.1 is #########################################################################
3114 1.1 is
3115 1.1 is global _fpsp_operr
3116 1.1 is _fpsp_operr:
3117 1.1 is
3118 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
3119 1.1 is
3120 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
3121 1.1 is
3122 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3123 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3124 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3125 1.1 is
3126 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
3127 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3128 1.1 is
3129 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3130 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3131 1.1 is bsr.l _imem_read_long # fetch the instruction words
3132 1.1 is mov.l %d0,EXC_OPWORD(%a6)
3133 1.1 is
3134 1.1 is ##############################################################################
3135 1.1 is
3136 1.1 is btst &13,%d0 # is instr an fmove out?
3137 1.1 is bne.b foperr_out # fmove out
3138 1.1 is
3139 1.1 is
3140 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3141 1.1 is # this would be the case for opclass two operations with a source infinity or
3142 1.1 is # denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3143 1.1 is # cause an operr so we don't need to check for them here.
3144 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
3145 1.1 is bsr.l fix_skewed_ops # fix src op
3146 1.1 is
3147 1.1 is foperr_exit:
3148 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3149 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3150 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3151 1.1 is
3152 1.1 is frestore FP_SRC(%a6)
3153 1.1 is
3154 1.1 is unlk %a6
3155 1.1 is bra.l _real_operr
3156 1.1 is
3157 1.1 is ########################################################################
3158 1.1 is
3159 1.1 is #
3160 1.1 is # the hardware does not save the default result to memory on enabled
3161 1.1 is # operand error exceptions. we do this here before passing control to
3162 1.1 is # the user operand error handler.
3163 1.1 is #
3164 1.1 is # byte, word, and long destination format operations can pass
3165 1.1 is # through here. we simply need to test the sign of the src
3166 1.1 is # operand and save the appropriate minimum or maximum integer value
3167 1.1 is # to the effective address as pointed to by the stacked effective address.
3168 1.1 is #
3169 1.1 is # although packed opclass three operations can take operand error
3170 1.1 is # exceptions, they won't pass through here since they are caught
3171 1.1 is # first by the unsupported data format exception handler. that handler
3172 1.1 is # sends them directly to _real_operr() if necessary.
3173 1.1 is #
3174 1.1 is foperr_out:
3175 1.1 is
3176 1.1 is mov.w FP_SRC_EX(%a6),%d1 # fetch exponent
3177 1.1 is andi.w &0x7fff,%d1
3178 1.1 is cmpi.w %d1,&0x7fff
3179 1.1 is bne.b foperr_out_not_qnan
3180 1.1 is # the operand is either an infinity or a QNAN.
3181 1.1 is tst.l FP_SRC_LO(%a6)
3182 1.1 is bne.b foperr_out_qnan
3183 1.1 is mov.l FP_SRC_HI(%a6),%d1
3184 1.1 is andi.l &0x7fffffff,%d1
3185 1.1 is beq.b foperr_out_not_qnan
3186 1.1 is foperr_out_qnan:
3187 1.1 is mov.l FP_SRC_HI(%a6),L_SCR1(%a6)
3188 1.1 is bra.b foperr_out_jmp
3189 1.1 is
3190 1.1 is foperr_out_not_qnan:
3191 1.1 is mov.l &0x7fffffff,%d1
3192 1.1 is tst.b FP_SRC_EX(%a6)
3193 1.1 is bpl.b foperr_out_not_qnan2
3194 1.1 is addq.l &0x1,%d1
3195 1.1 is foperr_out_not_qnan2:
3196 1.1 is mov.l %d1,L_SCR1(%a6)
3197 1.1 is
3198 1.1 is foperr_out_jmp:
3199 1.1 is bfextu %d0{&19:&3},%d0 # extract dst format field
3200 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg
3201 1.1 is mov.w (tbl_operr.b,%pc,%d0.w*2),%a0
3202 1.1 is jmp (tbl_operr.b,%pc,%a0)
3203 1.1 is
3204 1.1 is tbl_operr:
3205 1.1 is short foperr_out_l - tbl_operr # long word integer
3206 1.1 is short tbl_operr - tbl_operr # sgl prec shouldn't happen
3207 1.1 is short tbl_operr - tbl_operr # ext prec shouldn't happen
3208 1.1 is short foperr_exit - tbl_operr # packed won't enter here
3209 1.1 is short foperr_out_w - tbl_operr # word integer
3210 1.1 is short tbl_operr - tbl_operr # dbl prec shouldn't happen
3211 1.1 is short foperr_out_b - tbl_operr # byte integer
3212 1.1 is short tbl_operr - tbl_operr # packed won't enter here
3213 1.1 is
3214 1.1 is foperr_out_b:
3215 1.1 is mov.b L_SCR1(%a6),%d0 # load positive default result
3216 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3217 1.1 is ble.b foperr_out_b_save_dn # yes
3218 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3219 1.1 is bsr.l _dmem_write_byte # write the default result
3220 1.1 is
3221 1.1 is tst.l %d1 # did dstore fail?
3222 1.1 is bne.l facc_out_b # yes
3223 1.1 is
3224 1.1 is bra.w foperr_exit
3225 1.1 is foperr_out_b_save_dn:
3226 1.1 is andi.w &0x0007,%d1
3227 1.1 is bsr.l store_dreg_b # store result to regfile
3228 1.1 is bra.w foperr_exit
3229 1.1 is
3230 1.1 is foperr_out_w:
3231 1.1 is mov.w L_SCR1(%a6),%d0 # load positive default result
3232 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3233 1.1 is ble.b foperr_out_w_save_dn # yes
3234 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3235 1.1 is bsr.l _dmem_write_word # write the default result
3236 1.1 is
3237 1.1 is tst.l %d1 # did dstore fail?
3238 1.1 is bne.l facc_out_w # yes
3239 1.1 is
3240 1.1 is bra.w foperr_exit
3241 1.1 is foperr_out_w_save_dn:
3242 1.1 is andi.w &0x0007,%d1
3243 1.1 is bsr.l store_dreg_w # store result to regfile
3244 1.1 is bra.w foperr_exit
3245 1.1 is
3246 1.1 is foperr_out_l:
3247 1.1 is mov.l L_SCR1(%a6),%d0 # load positive default result
3248 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3249 1.1 is ble.b foperr_out_l_save_dn # yes
3250 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3251 1.1 is bsr.l _dmem_write_long # write the default result
3252 1.1 is
3253 1.1 is tst.l %d1 # did dstore fail?
3254 1.1 is bne.l facc_out_l # yes
3255 1.1 is
3256 1.1 is bra.w foperr_exit
3257 1.1 is foperr_out_l_save_dn:
3258 1.1 is andi.w &0x0007,%d1
3259 1.1 is bsr.l store_dreg_l # store result to regfile
3260 1.1 is bra.w foperr_exit
3261 1.1 is
3262 1.1 is #########################################################################
3263 1.1 is # XDEF **************************************************************** #
3264 1.1 is # _fpsp_snan(): 060FPSP entry point for FP SNAN exception. #
3265 1.1 is # #
3266 1.1 is # This handler should be the first code executed upon taking the #
3267 1.1 is # FP Signalling NAN exception in an operating system. #
3268 1.1 is # #
3269 1.1 is # XREF **************************************************************** #
3270 1.1 is # _imem_read_long() - read instruction longword #
3271 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
3272 1.1 is # _real_snan() - "callout" to operating system SNAN handler #
3273 1.1 is # _dmem_write_{byte,word,long}() - store data to mem (opclass 3) #
3274 1.1 is # store_dreg_{b,w,l}() - store data to data regfile (opclass 3) #
3275 1.1 is # facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3) #
3276 1.1 is # _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea> #
3277 1.1 is # #
3278 1.1 is # INPUT *************************************************************** #
3279 1.1 is # - The system stack contains the FP SNAN exception frame #
3280 1.1 is # - The fsave frame contains the source operand #
3281 1.1 is # #
3282 1.1 is # OUTPUT ************************************************************** #
3283 1.1 is # No access error: #
3284 1.1 is # - The system stack is unchanged #
3285 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 #
3286 1.1 is # #
3287 1.1 is # ALGORITHM *********************************************************** #
3288 1.1 is # In a system where the FP SNAN exception is enabled, the goal #
3289 1.1 is # is to get to the handler specified at _real_snan(). But, on the 060, #
3290 1.1 is # for opclass zero and two instructions taking this exception, the #
3291 1.1 is # input operand in the fsave frame may be incorrect for some cases #
3292 1.1 is # and needs to be corrected. This handler calls fix_skewed_ops() to #
3293 1.1 is # do just this and then exits through _real_snan(). #
3294 1.1 is # For opclass 3 instructions, the 060 doesn't store the default #
3295 1.1 is # SNAN result out to memory or data register file as it should. #
3296 1.1 is # This code must emulate the move out before finally exiting through #
3297 1.1 is # _real_snan(). The move out, if to memory, is performed using #
3298 1.1 is # _mem_write() "callout" routines that may return a failing result. #
3299 1.1 is # In this special case, the handler must exit through facc_out() #
3300 1.1 is # which creates an access error stack frame from the current SNAN #
3301 1.1 is # stack frame. #
3302 1.1 is # For the case of an extended precision opclass 3 instruction, #
3303 1.1 is # if the effective addressing mode was -() or ()+, then the address #
3304 1.1 is # register must get updated by calling _calc_ea_fout(). If the <ea> #
3305 1.1 is # was -(a7) from supervisor mode, then the exception frame currently #
3306 1.1 is # on the system stack must be carefully moved "down" to make room #
3307 1.1 is # for the operand being moved. #
3308 1.1 is # #
3309 1.1 is #########################################################################
3310 1.1 is
3311 1.1 is global _fpsp_snan
3312 1.1 is _fpsp_snan:
3313 1.1 is
3314 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
3315 1.1 is
3316 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
3317 1.1 is
3318 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3319 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3320 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3321 1.1 is
3322 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
3323 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3324 1.1 is
3325 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3326 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3327 1.1 is bsr.l _imem_read_long # fetch the instruction words
3328 1.1 is mov.l %d0,EXC_OPWORD(%a6)
3329 1.1 is
3330 1.1 is ##############################################################################
3331 1.1 is
3332 1.1 is btst &13,%d0 # is instr an fmove out?
3333 1.1 is bne.w fsnan_out # fmove out
3334 1.1 is
3335 1.1 is
3336 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3337 1.1 is # this would be the case for opclass two operations with a source infinity or
3338 1.1 is # denorm operand in the sgl or dbl format. NANs also become skewed and must be
3339 1.1 is # fixed here.
3340 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
3341 1.1 is bsr.l fix_skewed_ops # fix src op
3342 1.1 is
3343 1.1 is fsnan_exit:
3344 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3345 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3346 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3347 1.1 is
3348 1.1 is frestore FP_SRC(%a6)
3349 1.1 is
3350 1.1 is unlk %a6
3351 1.1 is bra.l _real_snan
3352 1.1 is
3353 1.1 is ########################################################################
3354 1.1 is
3355 1.1 is #
3356 1.1 is # the hardware does not save the default result to memory on enabled
3357 1.1 is # snan exceptions. we do this here before passing control to
3358 1.1 is # the user snan handler.
3359 1.1 is #
3360 1.1 is # byte, word, long, and packed destination format operations can pass
3361 1.1 is # through here. since packed format operations already were handled by
3362 1.1 is # fpsp_unsupp(), then we need to do nothing else for them here.
3363 1.1 is # for byte, word, and long, we simply need to test the sign of the src
3364 1.1 is # operand and save the appropriate minimum or maximum integer value
3365 1.1 is # to the effective address as pointed to by the stacked effective address.
3366 1.1 is #
3367 1.1 is fsnan_out:
3368 1.1 is
3369 1.1 is bfextu %d0{&19:&3},%d0 # extract dst format field
3370 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg
3371 1.1 is mov.w (tbl_snan.b,%pc,%d0.w*2),%a0
3372 1.1 is jmp (tbl_snan.b,%pc,%a0)
3373 1.1 is
3374 1.1 is tbl_snan:
3375 1.1 is short fsnan_out_l - tbl_snan # long word integer
3376 1.1 is short fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3377 1.1 is short fsnan_out_x - tbl_snan # ext prec shouldn't happen
3378 1.1 is short tbl_snan - tbl_snan # packed needs no help
3379 1.1 is short fsnan_out_w - tbl_snan # word integer
3380 1.1 is short fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3381 1.1 is short fsnan_out_b - tbl_snan # byte integer
3382 1.1 is short tbl_snan - tbl_snan # packed needs no help
3383 1.1 is
3384 1.1 is fsnan_out_b:
3385 1.1 is mov.b FP_SRC_HI(%a6),%d0 # load upper byte of SNAN
3386 1.1 is bset &6,%d0 # set SNAN bit
3387 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3388 1.1 is ble.b fsnan_out_b_dn # yes
3389 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3390 1.1 is bsr.l _dmem_write_byte # write the default result
3391 1.1 is
3392 1.1 is tst.l %d1 # did dstore fail?
3393 1.1 is bne.l facc_out_b # yes
3394 1.1 is
3395 1.1 is bra.w fsnan_exit
3396 1.1 is fsnan_out_b_dn:
3397 1.1 is andi.w &0x0007,%d1
3398 1.1 is bsr.l store_dreg_b # store result to regfile
3399 1.1 is bra.w fsnan_exit
3400 1.1 is
3401 1.1 is fsnan_out_w:
3402 1.1 is mov.w FP_SRC_HI(%a6),%d0 # load upper word of SNAN
3403 1.1 is bset &14,%d0 # set SNAN bit
3404 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3405 1.1 is ble.b fsnan_out_w_dn # yes
3406 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3407 1.1 is bsr.l _dmem_write_word # write the default result
3408 1.1 is
3409 1.1 is tst.l %d1 # did dstore fail?
3410 1.1 is bne.l facc_out_w # yes
3411 1.1 is
3412 1.1 is bra.w fsnan_exit
3413 1.1 is fsnan_out_w_dn:
3414 1.1 is andi.w &0x0007,%d1
3415 1.1 is bsr.l store_dreg_w # store result to regfile
3416 1.1 is bra.w fsnan_exit
3417 1.1 is
3418 1.1 is fsnan_out_l:
3419 1.1 is mov.l FP_SRC_HI(%a6),%d0 # load upper longword of SNAN
3420 1.1 is bset &30,%d0 # set SNAN bit
3421 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3422 1.1 is ble.b fsnan_out_l_dn # yes
3423 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3424 1.1 is bsr.l _dmem_write_long # write the default result
3425 1.1 is
3426 1.1 is tst.l %d1 # did dstore fail?
3427 1.1 is bne.l facc_out_l # yes
3428 1.1 is
3429 1.1 is bra.w fsnan_exit
3430 1.1 is fsnan_out_l_dn:
3431 1.1 is andi.w &0x0007,%d1
3432 1.1 is bsr.l store_dreg_l # store result to regfile
3433 1.1 is bra.w fsnan_exit
3434 1.1 is
3435 1.1 is fsnan_out_s:
3436 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3437 1.1 is ble.b fsnan_out_d_dn # yes
3438 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3439 1.1 is andi.l &0x80000000,%d0 # keep sign
3440 1.1 is ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit
3441 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load mantissa
3442 1.1 is lsr.l &0x8,%d1 # shift mantissa for sgl
3443 1.1 is or.l %d1,%d0 # create sgl SNAN
3444 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3445 1.1 is bsr.l _dmem_write_long # write the default result
3446 1.1 is
3447 1.1 is tst.l %d1 # did dstore fail?
3448 1.1 is bne.l facc_out_l # yes
3449 1.1 is
3450 1.1 is bra.w fsnan_exit
3451 1.1 is fsnan_out_d_dn:
3452 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3453 1.1 is andi.l &0x80000000,%d0 # keep sign
3454 1.1 is ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit
3455 1.1 is mov.l %d1,-(%sp)
3456 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load mantissa
3457 1.1 is lsr.l &0x8,%d1 # shift mantissa for sgl
3458 1.1 is or.l %d1,%d0 # create sgl SNAN
3459 1.1 is mov.l (%sp)+,%d1
3460 1.1 is andi.w &0x0007,%d1
3461 1.1 is bsr.l store_dreg_l # store result to regfile
3462 1.1 is bra.w fsnan_exit
3463 1.1 is
3464 1.1 is fsnan_out_d:
3465 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3466 1.1 is andi.l &0x80000000,%d0 # keep sign
3467 1.1 is ori.l &0x7ff80000,%d0 # insert new exponent,SNAN bit
3468 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa
3469 1.1 is mov.l %d0,FP_SCR0_EX(%a6) # store to temp space
3470 1.1 is mov.l &11,%d0 # load shift amt
3471 1.1 is lsr.l %d0,%d1
3472 1.1 is or.l %d1,FP_SCR0_EX(%a6) # create dbl hi
3473 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa
3474 1.1 is andi.l &0x000007ff,%d1
3475 1.1 is ror.l %d0,%d1
3476 1.1 is mov.l %d1,FP_SCR0_HI(%a6) # store to temp space
3477 1.1 is mov.l FP_SRC_LO(%a6),%d1 # load lo mantissa
3478 1.1 is lsr.l %d0,%d1
3479 1.1 is or.l %d1,FP_SCR0_HI(%a6) # create dbl lo
3480 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
3481 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr
3482 1.1 is movq.l &0x8,%d0 # pass: size of 8 bytes
3483 1.1 is bsr.l _dmem_write # write the default result
3484 1.1 is
3485 1.1 is tst.l %d1 # did dstore fail?
3486 1.1 is bne.l facc_out_d # yes
3487 1.1 is
3488 1.1 is bra.w fsnan_exit
3489 1.1 is
3490 1.1 is # for extended precision, if the addressing mode is pre-decrement or
3491 1.1 is # post-increment, then the address register did not get updated.
3492 1.1 is # in addition, for pre-decrement, the stacked <ea> is incorrect.
3493 1.1 is fsnan_out_x:
3494 1.1 is clr.b SPCOND_FLG(%a6) # clear special case flag
3495 1.1 is
3496 1.1 is mov.w FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3497 1.1 is clr.w 2+FP_SCR0(%a6)
3498 1.1 is mov.l FP_SRC_HI(%a6),%d0
3499 1.1 is bset &30,%d0
3500 1.1 is mov.l %d0,FP_SCR0_HI(%a6)
3501 1.1 is mov.l FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3502 1.1 is
3503 1.1 is btst &0x5,EXC_SR(%a6) # supervisor mode exception?
3504 1.1 is bne.b fsnan_out_x_s # yes
3505 1.1 is
3506 1.1 is mov.l %usp,%a0 # fetch user stack pointer
3507 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack for calc_ea()
3508 1.1 is mov.l (%a6),EXC_A6(%a6)
3509 1.1 is
3510 1.1 is bsr.l _calc_ea_fout # find the correct ea,update An
3511 1.1 is mov.l %a0,%a1
3512 1.1 is mov.l %a0,EXC_EA(%a6) # stack correct <ea>
3513 1.1 is
3514 1.1 is mov.l EXC_A7(%a6),%a0
3515 1.1 is mov.l %a0,%usp # restore user stack pointer
3516 1.1 is mov.l EXC_A6(%a6),(%a6)
3517 1.1 is
3518 1.1 is fsnan_out_x_save:
3519 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
3520 1.1 is movq.l &0xc,%d0 # pass: size of extended
3521 1.1 is bsr.l _dmem_write # write the default result
3522 1.1 is
3523 1.1 is tst.l %d1 # did dstore fail?
3524 1.1 is bne.l facc_out_x # yes
3525 1.1 is
3526 1.1 is bra.w fsnan_exit
3527 1.1 is
3528 1.1 is fsnan_out_x_s:
3529 1.1 is mov.l (%a6),EXC_A6(%a6)
3530 1.1 is
3531 1.1 is bsr.l _calc_ea_fout # find the correct ea,update An
3532 1.1 is mov.l %a0,%a1
3533 1.1 is mov.l %a0,EXC_EA(%a6) # stack correct <ea>
3534 1.1 is
3535 1.1 is mov.l EXC_A6(%a6),(%a6)
3536 1.1 is
3537 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3538 1.1 is bne.b fsnan_out_x_save # no
3539 1.1 is
3540 1.1 is # the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3541 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3542 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3543 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3544 1.1 is
3545 1.1 is frestore FP_SRC(%a6)
3546 1.1 is
3547 1.1 is mov.l EXC_A6(%a6),%a6 # restore frame pointer
3548 1.1 is
3549 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3550 1.1 is mov.l LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3551 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3552 1.1 is
3553 1.1 is mov.l LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3554 1.1 is mov.l LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3555 1.1 is mov.l LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3556 1.1 is
3557 1.1 is add.l &LOCAL_SIZE-0x8,%sp
3558 1.1 is
3559 1.1 is bra.l _real_snan
3560 1.1 is
3561 1.1 is #########################################################################
3562 1.1 is # XDEF **************************************************************** #
3563 1.1 is # _fpsp_inex(): 060FPSP entry point for FP Inexact exception. #
3564 1.1 is # #
3565 1.1 is # This handler should be the first code executed upon taking the #
3566 1.1 is # FP Inexact exception in an operating system. #
3567 1.1 is # #
3568 1.1 is # XREF **************************************************************** #
3569 1.1 is # _imem_read_long() - read instruction longword #
3570 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame #
3571 1.1 is # set_tag_x() - determine optype of src/dst operands #
3572 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile #
3573 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO #
3574 1.1 is # load_fpn2() - load dst operand from FP regfile #
3575 1.1 is # smovcr() - emulate an "fmovcr" instruction #
3576 1.1 is # fout() - emulate an opclass 3 instruction #
3577 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3578 1.1 is # _real_inex() - "callout" to operating system inexact handler #
3579 1.1 is # #
3580 1.1 is # INPUT *************************************************************** #
3581 1.1 is # - The system stack contains the FP Inexact exception frame #
3582 1.1 is # - The fsave frame contains the source operand #
3583 1.1 is # #
3584 1.1 is # OUTPUT ************************************************************** #
3585 1.1 is # - The system stack is unchanged #
3586 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 #
3587 1.1 is # #
3588 1.1 is # ALGORITHM *********************************************************** #
3589 1.1 is # In a system where the FP Inexact exception is enabled, the goal #
3590 1.1 is # is to get to the handler specified at _real_inex(). But, on the 060, #
3591 1.1 is # for opclass zero and two instruction taking this exception, the #
3592 1.1 is # hardware doesn't store the correct result to the destination FP #
3593 1.1 is # register as did the '040 and '881/2. This handler must emulate the #
3594 1.1 is # instruction in order to get this value and then store it to the #
3595 1.1 is # correct register before calling _real_inex(). #
3596 1.1 is # For opclass 3 instructions, the 060 doesn't store the default #
3597 1.1 is # inexact result out to memory or data register file as it should. #
3598 1.1 is # This code must emulate the move out by calling fout() before finally #
3599 1.1 is # exiting through _real_inex(). #
3600 1.1 is # #
3601 1.1 is #########################################################################
3602 1.1 is
3603 1.1 is global _fpsp_inex
3604 1.1 is _fpsp_inex:
3605 1.1 is
3606 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
3607 1.1 is
3608 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
3609 1.1 is
3610 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3611 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3612 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3613 1.1 is
3614 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
3615 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3616 1.1 is
3617 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3618 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3619 1.1 is bsr.l _imem_read_long # fetch the instruction words
3620 1.1 is mov.l %d0,EXC_OPWORD(%a6)
3621 1.1 is
3622 1.1 is ##############################################################################
3623 1.1 is
3624 1.1 is btst &13,%d0 # is instr an fmove out?
3625 1.1 is bne.w finex_out # fmove out
3626 1.1 is
3627 1.1 is
3628 1.1 is # the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3629 1.1 is # longword integer directly into the upper longword of the mantissa along
3630 1.1 is # w/ an exponent value of 0x401e. we convert this to extended precision here.
3631 1.1 is bfextu %d0{&19:&3},%d0 # fetch instr size
3632 1.1 is bne.b finex_cont # instr size is not long
3633 1.1 is cmpi.w FP_SRC_EX(%a6),&0x401e # is exponent 0x401e?
3634 1.1 is bne.b finex_cont # no
3635 1.1 is fmov.l &0x0,%fpcr
3636 1.1 is fmov.l FP_SRC_HI(%a6),%fp0 # load integer src
3637 1.1 is fmov.x %fp0,FP_SRC(%a6) # store integer as extended precision
3638 1.1 is mov.w &0xe001,0x2+FP_SRC(%a6)
3639 1.1 is
3640 1.1 is finex_cont:
3641 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
3642 1.1 is bsr.l fix_skewed_ops # fix src op
3643 1.1 is
3644 1.1 is # Here, we zero the ccode and exception byte field since we're going to
3645 1.1 is # emulate the whole instruction. Notice, though, that we don't kill the
3646 1.1 is # INEX1 bit. This is because a packed op has long since been converted
3647 1.1 is # to extended before arriving here. Therefore, we need to retain the
3648 1.1 is # INEX1 bit from when the operand was first converted.
3649 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3650 1.1 is
3651 1.1 is fmov.l &0x0,%fpcr # zero current control regs
3652 1.1 is fmov.l &0x0,%fpsr
3653 1.1 is
3654 1.1 is bfextu EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3655 1.1 is cmpi.b %d1,&0x17 # is op an fmovecr?
3656 1.1 is beq.w finex_fmovcr # yes
3657 1.1 is
3658 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
3659 1.1 is bsr.l set_tag_x # tag the operand type
3660 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM
3661 1.1 is
3662 1.1 is # bits four and five of the fp extension word separate the monadic and dyadic
3663 1.1 is # operations that can pass through fpsp_inex(). remember that fcmp and ftst
3664 1.1 is # will never take this exception, but fsincos will.
3665 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
3666 1.1 is beq.b finex_extract # monadic
3667 1.1 is
3668 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is operation an fsincos?
3669 1.1 is bne.b finex_extract # yes
3670 1.1 is
3671 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3672 1.1 is bsr.l load_fpn2 # load dst into FP_DST
3673 1.1 is
3674 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op
3675 1.1 is bsr.l set_tag_x # tag the operand type
3676 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM?
3677 1.1 is bne.b finex_op2_done # no
3678 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
3679 1.1 is finex_op2_done:
3680 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag
3681 1.1 is
3682 1.1 is finex_extract:
3683 1.1 is clr.l %d0
3684 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
3685 1.1 is
3686 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1
3687 1.1 is andi.w &0x007f,%d1 # extract extension
3688 1.1 is
3689 1.1 is lea FP_SRC(%a6),%a0
3690 1.1 is lea FP_DST(%a6),%a1
3691 1.1 is
3692 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3693 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1)
3694 1.1 is
3695 1.1 is # the operation has been emulated. the result is in fp0.
3696 1.1 is finex_save:
3697 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0
3698 1.1 is bsr.l store_fpreg
3699 1.1 is
3700 1.1 is finex_exit:
3701 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3702 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3703 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3704 1.1 is
3705 1.1 is frestore FP_SRC(%a6)
3706 1.1 is
3707 1.1 is unlk %a6
3708 1.1 is bra.l _real_inex
3709 1.1 is
3710 1.1 is finex_fmovcr:
3711 1.1 is clr.l %d0
3712 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode
3713 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1
3714 1.1 is andi.l &0x0000007f,%d1 # pass rom offset
3715 1.1 is bsr.l smovcr
3716 1.1 is bra.b finex_save
3717 1.1 is
3718 1.1 is ########################################################################
3719 1.1 is
3720 1.1 is #
3721 1.1 is # the hardware does not save the default result to memory on enabled
3722 1.1 is # inexact exceptions. we do this here before passing control to
3723 1.1 is # the user inexact handler.
3724 1.1 is #
3725 1.1 is # byte, word, and long destination format operations can pass
3726 1.1 is # through here. so can double and single precision.
3727 1.1 is # although packed opclass three operations can take inexact
3728 1.1 is # exceptions, they won't pass through here since they are caught
3729 1.1 is # first by the unsupported data format exception handler. that handler
3730 1.1 is # sends them directly to _real_inex() if necessary.
3731 1.1 is #
3732 1.1 is finex_out:
3733 1.1 is
3734 1.1 is mov.b &NORM,STAG(%a6) # src is a NORM
3735 1.1 is
3736 1.1 is clr.l %d0
3737 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode
3738 1.1 is
3739 1.1 is andi.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
3740 1.1 is
3741 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand
3742 1.1 is
3743 1.1 is bsr.l fout # store the default result
3744 1.1 is
3745 1.1 is bra.b finex_exit
3746 1.1 is
3747 1.1 is #########################################################################
3748 1.1 is # XDEF **************************************************************** #
3749 1.1 is # _fpsp_dz(): 060FPSP entry point for FP DZ exception. #
3750 1.1 is # #
3751 1.1 is # This handler should be the first code executed upon taking #
3752 1.1 is # the FP DZ exception in an operating system. #
3753 1.1 is # #
3754 1.1 is # XREF **************************************************************** #
3755 1.1 is # _imem_read_long() - read instruction longword from memory #
3756 1.1 is # fix_skewed_ops() - adjust fsave operand #
3757 1.1 is # _real_dz() - "callout" exit point from FP DZ handler #
3758 1.1 is # #
3759 1.1 is # INPUT *************************************************************** #
3760 1.1 is # - The system stack contains the FP DZ exception stack. #
3761 1.1 is # - The fsave frame contains the source operand. #
3762 1.1 is # #
3763 1.1 is # OUTPUT ************************************************************** #
3764 1.1 is # - The system stack contains the FP DZ exception stack. #
3765 1.1 is # - The fsave frame contains the adjusted source operand. #
3766 1.1 is # #
3767 1.1 is # ALGORITHM *********************************************************** #
3768 1.1 is # In a system where the DZ exception is enabled, the goal is to #
3769 1.1 is # get to the handler specified at _real_dz(). But, on the 060, when the #
3770 1.1 is # exception is taken, the input operand in the fsave state frame may #
3771 1.1 is # be incorrect for some cases and need to be adjusted. So, this package #
3772 1.1 is # adjusts the operand using fix_skewed_ops() and then branches to #
3773 1.1 is # _real_dz(). #
3774 1.1 is # #
3775 1.1 is #########################################################################
3776 1.1 is
3777 1.1 is global _fpsp_dz
3778 1.1 is _fpsp_dz:
3779 1.1 is
3780 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame
3781 1.1 is
3782 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame
3783 1.1 is
3784 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3785 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3786 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3787 1.1 is
3788 1.1 is # the FPIAR holds the "current PC" of the faulting instruction
3789 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3790 1.1 is
3791 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3792 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3793 1.1 is bsr.l _imem_read_long # fetch the instruction words
3794 1.1 is mov.l %d0,EXC_OPWORD(%a6)
3795 1.1 is
3796 1.1 is ##############################################################################
3797 1.1 is
3798 1.1 is
3799 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3800 1.1 is # this would be the case for opclass two operations with a source zero
3801 1.1 is # in the sgl or dbl format.
3802 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op
3803 1.1 is bsr.l fix_skewed_ops # fix src op
3804 1.1 is
3805 1.1 is fdz_exit:
3806 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3807 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3808 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3809 1.1 is
3810 1.1 is frestore FP_SRC(%a6)
3811 1.1 is
3812 1.1 is unlk %a6
3813 1.1 is bra.l _real_dz
3814 1.1 is
3815 1.1 is #########################################################################
3816 1.1 is # XDEF **************************************************************** #
3817 1.1 is # _fpsp_fline(): 060FPSP entry point for "Line F emulator" #
3818 1.1 is # exception when the "reduced" version of the #
3819 1.1 is # FPSP is implemented that does not emulate #
3820 1.1 is # FP unimplemented instructions. #
3821 1.1 is # #
3822 1.1 is # This handler should be the first code executed upon taking a #
3823 1.1 is # "Line F Emulator" exception in an operating system integrating #
3824 1.1 is # the reduced version of 060FPSP. #
3825 1.1 is # #
3826 1.1 is # XREF **************************************************************** #
3827 1.1 is # _real_fpu_disabled() - Handle "FPU disabled" exceptions #
3828 1.1 is # _real_fline() - Handle all other cases (treated equally) #
3829 1.1 is # #
3830 1.1 is # INPUT *************************************************************** #
3831 1.1 is # - The system stack contains a "Line F Emulator" exception #
3832 1.1 is # stack frame. #
3833 1.1 is # #
3834 1.1 is # OUTPUT ************************************************************** #
3835 1.1 is # - The system stack is unchanged. #
3836 1.1 is # #
3837 1.1 is # ALGORITHM *********************************************************** #
3838 1.1 is # When a "Line F Emulator" exception occurs in a system where #
3839 1.1 is # "FPU Unimplemented" instructions will not be emulated, the exception #
3840 1.1 is # can occur because then FPU is disabled or the instruction is to be #
3841 1.1 is # classifed as "Line F". This module determines which case exists and #
3842 1.1 is # calls the appropriate "callout". #
3843 1.1 is # #
3844 1.1 is #########################################################################
3845 1.1 is
3846 1.1 is global _fpsp_fline
3847 1.1 is _fpsp_fline:
3848 1.1 is
3849 1.1 is # check to see if the FPU is disabled. if so, jump to the OS entry
3850 1.1 is # point for that condition.
3851 1.1 is cmpi.w 0x6(%sp),&0x402c
3852 1.1 is beq.l _real_fpu_disabled
3853 1.1 is
3854 1.1 is bra.l _real_fline
3855 1.1 is
3856 1.1 is #########################################################################
3857 1.1 is # XDEF **************************************************************** #
3858 1.1 is # _dcalc_ea(): calc correct <ea> from <ea> stacked on exception #
3859 1.1 is # #
3860 1.1 is # XREF **************************************************************** #
3861 1.1 is # inc_areg() - increment an address register #
3862 1.1 is # dec_areg() - decrement an address register #
3863 1.1 is # #
3864 1.1 is # INPUT *************************************************************** #
3865 1.1 is # d0 = number of bytes to adjust <ea> by #
3866 1.1 is # #
3867 1.1 is # OUTPUT ************************************************************** #
3868 1.1 is # None #
3869 1.1 is # #
3870 1.1 is # ALGORITHM *********************************************************** #
3871 1.1 is # "Dummy" CALCulate Effective Address: #
3872 1.1 is # The stacked <ea> for FP unimplemented instructions and opclass #
3873 1.1 is # two packed instructions is correct with the exception of... #
3874 1.1 is # #
3875 1.1 is # 1) -(An) : The register is not updated regardless of size. #
3876 1.1 is # Also, for extended precision and packed, the #
3877 1.1 is # stacked <ea> value is 8 bytes too big #
3878 1.1 is # 2) (An)+ : The register is not updated. #
3879 1.1 is # 3) #<data> : The upper longword of the immediate operand is #
3880 1.1 is # stacked b,w,l and s sizes are completely stacked. #
3881 1.1 is # d,x, and p are not. #
3882 1.1 is # #
3883 1.1 is #########################################################################
3884 1.1 is
3885 1.1 is global _dcalc_ea
3886 1.1 is _dcalc_ea:
3887 1.1 is mov.l %d0, %a0 # move # bytes to %a0
3888 1.1 is
3889 1.1 is mov.b 1+EXC_OPWORD(%a6), %d0 # fetch opcode word
3890 1.1 is mov.l %d0, %d1 # make a copy
3891 1.1 is
3892 1.1 is andi.w &0x38, %d0 # extract mode field
3893 1.1 is andi.l &0x7, %d1 # extract reg field
3894 1.1 is
3895 1.1 is cmpi.b %d0,&0x18 # is mode (An)+ ?
3896 1.1 is beq.b dcea_pi # yes
3897 1.1 is
3898 1.1 is cmpi.b %d0,&0x20 # is mode -(An) ?
3899 1.1 is beq.b dcea_pd # yes
3900 1.1 is
3901 1.1 is or.w %d1,%d0 # concat mode,reg
3902 1.1 is cmpi.b %d0,&0x3c # is mode #<data>?
3903 1.1 is
3904 1.1 is beq.b dcea_imm # yes
3905 1.1 is
3906 1.1 is mov.l EXC_EA(%a6),%a0 # return <ea>
3907 1.1 is rts
3908 1.1 is
3909 1.1 is # need to set immediate data flag here since we'll need to do
3910 1.1 is # an imem_read to fetch this later.
3911 1.1 is dcea_imm:
3912 1.1 is mov.b &immed_flg,SPCOND_FLG(%a6)
3913 1.1 is lea ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
3914 1.1 is rts
3915 1.1 is
3916 1.1 is # here, the <ea> is stacked correctly. however, we must update the
3917 1.1 is # address register...
3918 1.1 is dcea_pi:
3919 1.1 is mov.l %a0,%d0 # pass amt to inc by
3920 1.1 is bsr.l inc_areg # inc addr register
3921 1.1 is
3922 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3923 1.1 is rts
3924 1.1 is
3925 1.1 is # the <ea> is stacked correctly for all but extended and packed which
3926 1.1 is # the <ea>s are 8 bytes too large.
3927 1.1 is # it would make no sense to have a pre-decrement to a7 in supervisor
3928 1.1 is # mode so we don't even worry about this tricky case here : )
3929 1.1 is dcea_pd:
3930 1.1 is mov.l %a0,%d0 # pass amt to dec by
3931 1.1 is bsr.l dec_areg # dec addr register
3932 1.1 is
3933 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3934 1.1 is
3935 1.1 is cmpi.b %d0,&0xc # is opsize ext or packed?
3936 1.1 is beq.b dcea_pd2 # yes
3937 1.1 is rts
3938 1.1 is dcea_pd2:
3939 1.1 is sub.l &0x8,%a0 # correct <ea>
3940 1.1 is mov.l %a0,EXC_EA(%a6) # put correct <ea> on stack
3941 1.1 is rts
3942 1.1 is
3943 1.1 is #########################################################################
3944 1.1 is # XDEF **************************************************************** #
3945 1.1 is # _calc_ea_fout(): calculate correct stacked <ea> for extended #
3946 1.1 is # and packed data opclass 3 operations. #
3947 1.1 is # #
3948 1.1 is # XREF **************************************************************** #
3949 1.1 is # None #
3950 1.1 is # #
3951 1.1 is # INPUT *************************************************************** #
3952 1.1 is # None #
3953 1.1 is # #
3954 1.1 is # OUTPUT ************************************************************** #
3955 1.1 is # a0 = return correct effective address #
3956 1.1 is # #
3957 1.1 is # ALGORITHM *********************************************************** #
3958 1.1 is # For opclass 3 extended and packed data operations, the <ea> #
3959 1.1 is # stacked for the exception is incorrect for -(an) and (an)+ addressing #
3960 1.1 is # modes. Also, while we're at it, the index register itself must get #
3961 1.1 is # updated. #
3962 1.1 is # So, for -(an), we must subtract 8 off of the stacked <ea> value #
3963 1.1 is # and return that value as the correct <ea> and store that value in An. #
3964 1.1 is # For (an)+, the stacked <ea> is correct but we must adjust An by +12. #
3965 1.1 is # #
3966 1.1 is #########################################################################
3967 1.1 is
3968 1.1 is # This calc_ea is currently used to retrieve the correct <ea>
3969 1.1 is # for fmove outs of type extended and packed.
3970 1.1 is global _calc_ea_fout
3971 1.1 is _calc_ea_fout:
3972 1.1 is mov.b 1+EXC_OPWORD(%a6),%d0 # fetch opcode word
3973 1.1 is mov.l %d0,%d1 # make a copy
3974 1.1 is
3975 1.1 is andi.w &0x38,%d0 # extract mode field
3976 1.1 is andi.l &0x7,%d1 # extract reg field
3977 1.1 is
3978 1.1 is cmpi.b %d0,&0x18 # is mode (An)+ ?
3979 1.1 is beq.b ceaf_pi # yes
3980 1.1 is
3981 1.1 is cmpi.b %d0,&0x20 # is mode -(An) ?
3982 1.1 is beq.w ceaf_pd # yes
3983 1.1 is
3984 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3985 1.1 is rts
3986 1.1 is
3987 1.1 is # (An)+ : extended and packed fmove out
3988 1.1 is # : stacked <ea> is correct
3989 1.1 is # : "An" not updated
3990 1.1 is ceaf_pi:
3991 1.1 is mov.w (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
3992 1.1 is mov.l EXC_EA(%a6),%a0
3993 1.1 is jmp (tbl_ceaf_pi.b,%pc,%d1.w*1)
3994 1.1 is
3995 1.1 is swbeg &0x8
3996 1.1 is tbl_ceaf_pi:
3997 1.1 is short ceaf_pi0 - tbl_ceaf_pi
3998 1.1 is short ceaf_pi1 - tbl_ceaf_pi
3999 1.1 is short ceaf_pi2 - tbl_ceaf_pi
4000 1.1 is short ceaf_pi3 - tbl_ceaf_pi
4001 1.1 is short ceaf_pi4 - tbl_ceaf_pi
4002 1.1 is short ceaf_pi5 - tbl_ceaf_pi
4003 1.1 is short ceaf_pi6 - tbl_ceaf_pi
4004 1.1 is short ceaf_pi7 - tbl_ceaf_pi
4005 1.1 is
4006 1.1 is ceaf_pi0:
4007 1.1 is addi.l &0xc,EXC_DREGS+0x8(%a6)
4008 1.1 is rts
4009 1.1 is ceaf_pi1:
4010 1.1 is addi.l &0xc,EXC_DREGS+0xc(%a6)
4011 1.1 is rts
4012 1.1 is ceaf_pi2:
4013 1.1 is add.l &0xc,%a2
4014 1.1 is rts
4015 1.1 is ceaf_pi3:
4016 1.1 is add.l &0xc,%a3
4017 1.1 is rts
4018 1.1 is ceaf_pi4:
4019 1.1 is add.l &0xc,%a4
4020 1.1 is rts
4021 1.1 is ceaf_pi5:
4022 1.1 is add.l &0xc,%a5
4023 1.1 is rts
4024 1.1 is ceaf_pi6:
4025 1.1 is addi.l &0xc,EXC_A6(%a6)
4026 1.1 is rts
4027 1.1 is ceaf_pi7:
4028 1.1 is mov.b &mia7_flg,SPCOND_FLG(%a6)
4029 1.1 is addi.l &0xc,EXC_A7(%a6)
4030 1.1 is rts
4031 1.1 is
4032 1.1 is # -(An) : extended and packed fmove out
4033 1.1 is # : stacked <ea> = actual <ea> + 8
4034 1.1 is # : "An" not updated
4035 1.1 is ceaf_pd:
4036 1.1 is mov.w (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
4037 1.1 is mov.l EXC_EA(%a6),%a0
4038 1.1 is sub.l &0x8,%a0
4039 1.1 is sub.l &0x8,EXC_EA(%a6)
4040 1.1 is jmp (tbl_ceaf_pd.b,%pc,%d1.w*1)
4041 1.1 is
4042 1.1 is swbeg &0x8
4043 1.1 is tbl_ceaf_pd:
4044 1.1 is short ceaf_pd0 - tbl_ceaf_pd
4045 1.1 is short ceaf_pd1 - tbl_ceaf_pd
4046 1.1 is short ceaf_pd2 - tbl_ceaf_pd
4047 1.1 is short ceaf_pd3 - tbl_ceaf_pd
4048 1.1 is short ceaf_pd4 - tbl_ceaf_pd
4049 1.1 is short ceaf_pd5 - tbl_ceaf_pd
4050 1.1 is short ceaf_pd6 - tbl_ceaf_pd
4051 1.1 is short ceaf_pd7 - tbl_ceaf_pd
4052 1.1 is
4053 1.1 is ceaf_pd0:
4054 1.1 is mov.l %a0,EXC_DREGS+0x8(%a6)
4055 1.1 is rts
4056 1.1 is ceaf_pd1:
4057 1.1 is mov.l %a0,EXC_DREGS+0xc(%a6)
4058 1.1 is rts
4059 1.1 is ceaf_pd2:
4060 1.1 is mov.l %a0,%a2
4061 1.1 is rts
4062 1.1 is ceaf_pd3:
4063 1.1 is mov.l %a0,%a3
4064 1.1 is rts
4065 1.1 is ceaf_pd4:
4066 1.1 is mov.l %a0,%a4
4067 1.1 is rts
4068 1.1 is ceaf_pd5:
4069 1.1 is mov.l %a0,%a5
4070 1.1 is rts
4071 1.1 is ceaf_pd6:
4072 1.1 is mov.l %a0,EXC_A6(%a6)
4073 1.1 is rts
4074 1.1 is ceaf_pd7:
4075 1.1 is mov.l %a0,EXC_A7(%a6)
4076 1.1 is mov.b &mda7_flg,SPCOND_FLG(%a6)
4077 1.1 is rts
4078 1.1 is
4079 1.1 is #
4080 1.1 is # This table holds the offsets of the emulation routines for each individual
4081 1.1 is # math operation relative to the address of this table. Included are
4082 1.1 is # routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because
4083 1.1 is # this table is for the version if the 060FPSP without transcendentals.
4084 1.1 is # The location within the table is determined by the extension bits of the
4085 1.1 is # operation longword.
4086 1.1 is #
4087 1.1 is
4088 1.1 is swbeg &109
4089 1.1 is tbl_unsupp:
4090 1.1 is long fin - tbl_unsupp # 00: fmove
4091 1.1 is long fint - tbl_unsupp # 01: fint
4092 1.1 is long tbl_unsupp - tbl_unsupp # 02: fsinh
4093 1.1 is long fintrz - tbl_unsupp # 03: fintrz
4094 1.1 is long fsqrt - tbl_unsupp # 04: fsqrt
4095 1.1 is long tbl_unsupp - tbl_unsupp
4096 1.1 is long tbl_unsupp - tbl_unsupp # 06: flognp1
4097 1.1 is long tbl_unsupp - tbl_unsupp
4098 1.1 is long tbl_unsupp - tbl_unsupp # 08: fetoxm1
4099 1.1 is long tbl_unsupp - tbl_unsupp # 09: ftanh
4100 1.1 is long tbl_unsupp - tbl_unsupp # 0a: fatan
4101 1.1 is long tbl_unsupp - tbl_unsupp
4102 1.1 is long tbl_unsupp - tbl_unsupp # 0c: fasin
4103 1.1 is long tbl_unsupp - tbl_unsupp # 0d: fatanh
4104 1.1 is long tbl_unsupp - tbl_unsupp # 0e: fsin
4105 1.1 is long tbl_unsupp - tbl_unsupp # 0f: ftan
4106 1.1 is long tbl_unsupp - tbl_unsupp # 10: fetox
4107 1.1 is long tbl_unsupp - tbl_unsupp # 11: ftwotox
4108 1.1 is long tbl_unsupp - tbl_unsupp # 12: ftentox
4109 1.1 is long tbl_unsupp - tbl_unsupp
4110 1.1 is long tbl_unsupp - tbl_unsupp # 14: flogn
4111 1.1 is long tbl_unsupp - tbl_unsupp # 15: flog10
4112 1.1 is long tbl_unsupp - tbl_unsupp # 16: flog2
4113 1.1 is long tbl_unsupp - tbl_unsupp
4114 1.1 is long fabs - tbl_unsupp # 18: fabs
4115 1.1 is long tbl_unsupp - tbl_unsupp # 19: fcosh
4116 1.1 is long fneg - tbl_unsupp # 1a: fneg
4117 1.1 is long tbl_unsupp - tbl_unsupp
4118 1.1 is long tbl_unsupp - tbl_unsupp # 1c: facos
4119 1.1 is long tbl_unsupp - tbl_unsupp # 1d: fcos
4120 1.1 is long tbl_unsupp - tbl_unsupp # 1e: fgetexp
4121 1.1 is long tbl_unsupp - tbl_unsupp # 1f: fgetman
4122 1.1 is long fdiv - tbl_unsupp # 20: fdiv
4123 1.1 is long tbl_unsupp - tbl_unsupp # 21: fmod
4124 1.1 is long fadd - tbl_unsupp # 22: fadd
4125 1.1 is long fmul - tbl_unsupp # 23: fmul
4126 1.1 is long fsgldiv - tbl_unsupp # 24: fsgldiv
4127 1.1 is long tbl_unsupp - tbl_unsupp # 25: frem
4128 1.1 is long tbl_unsupp - tbl_unsupp # 26: fscale
4129 1.1 is long fsglmul - tbl_unsupp # 27: fsglmul
4130 1.1 is long fsub - tbl_unsupp # 28: fsub
4131 1.1 is long tbl_unsupp - tbl_unsupp
4132 1.1 is long tbl_unsupp - tbl_unsupp
4133 1.1 is long tbl_unsupp - tbl_unsupp
4134 1.1 is long tbl_unsupp - tbl_unsupp
4135 1.1 is long tbl_unsupp - tbl_unsupp
4136 1.1 is long tbl_unsupp - tbl_unsupp
4137 1.1 is long tbl_unsupp - tbl_unsupp
4138 1.1 is long tbl_unsupp - tbl_unsupp # 30: fsincos
4139 1.1 is long tbl_unsupp - tbl_unsupp # 31: fsincos
4140 1.1 is long tbl_unsupp - tbl_unsupp # 32: fsincos
4141 1.1 is long tbl_unsupp - tbl_unsupp # 33: fsincos
4142 1.1 is long tbl_unsupp - tbl_unsupp # 34: fsincos
4143 1.1 is long tbl_unsupp - tbl_unsupp # 35: fsincos
4144 1.1 is long tbl_unsupp - tbl_unsupp # 36: fsincos
4145 1.1 is long tbl_unsupp - tbl_unsupp # 37: fsincos
4146 1.1 is long fcmp - tbl_unsupp # 38: fcmp
4147 1.1 is long tbl_unsupp - tbl_unsupp
4148 1.1 is long ftst - tbl_unsupp # 3a: ftst
4149 1.1 is long tbl_unsupp - tbl_unsupp
4150 1.1 is long tbl_unsupp - tbl_unsupp
4151 1.1 is long tbl_unsupp - tbl_unsupp
4152 1.1 is long tbl_unsupp - tbl_unsupp
4153 1.1 is long tbl_unsupp - tbl_unsupp
4154 1.1 is long fsin - tbl_unsupp # 40: fsmove
4155 1.1 is long fssqrt - tbl_unsupp # 41: fssqrt
4156 1.1 is long tbl_unsupp - tbl_unsupp
4157 1.1 is long tbl_unsupp - tbl_unsupp
4158 1.1 is long fdin - tbl_unsupp # 44: fdmove
4159 1.1 is long fdsqrt - tbl_unsupp # 45: fdsqrt
4160 1.1 is long tbl_unsupp - tbl_unsupp
4161 1.1 is long tbl_unsupp - tbl_unsupp
4162 1.1 is long tbl_unsupp - tbl_unsupp
4163 1.1 is long tbl_unsupp - tbl_unsupp
4164 1.1 is long tbl_unsupp - tbl_unsupp
4165 1.1 is long tbl_unsupp - tbl_unsupp
4166 1.1 is long tbl_unsupp - tbl_unsupp
4167 1.1 is long tbl_unsupp - tbl_unsupp
4168 1.1 is long tbl_unsupp - tbl_unsupp
4169 1.1 is long tbl_unsupp - tbl_unsupp
4170 1.1 is long tbl_unsupp - tbl_unsupp
4171 1.1 is long tbl_unsupp - tbl_unsupp
4172 1.1 is long tbl_unsupp - tbl_unsupp
4173 1.1 is long tbl_unsupp - tbl_unsupp
4174 1.1 is long tbl_unsupp - tbl_unsupp
4175 1.1 is long tbl_unsupp - tbl_unsupp
4176 1.1 is long tbl_unsupp - tbl_unsupp
4177 1.1 is long tbl_unsupp - tbl_unsupp
4178 1.1 is long fsabs - tbl_unsupp # 58: fsabs
4179 1.1 is long tbl_unsupp - tbl_unsupp
4180 1.1 is long fsneg - tbl_unsupp # 5a: fsneg
4181 1.1 is long tbl_unsupp - tbl_unsupp
4182 1.1 is long fdabs - tbl_unsupp # 5c: fdabs
4183 1.1 is long tbl_unsupp - tbl_unsupp
4184 1.1 is long fdneg - tbl_unsupp # 5e: fdneg
4185 1.1 is long tbl_unsupp - tbl_unsupp
4186 1.1 is long fsdiv - tbl_unsupp # 60: fsdiv
4187 1.1 is long tbl_unsupp - tbl_unsupp
4188 1.1 is long fsadd - tbl_unsupp # 62: fsadd
4189 1.1 is long fsmul - tbl_unsupp # 63: fsmul
4190 1.1 is long fddiv - tbl_unsupp # 64: fddiv
4191 1.1 is long tbl_unsupp - tbl_unsupp
4192 1.1 is long fdadd - tbl_unsupp # 66: fdadd
4193 1.1 is long fdmul - tbl_unsupp # 67: fdmul
4194 1.1 is long fssub - tbl_unsupp # 68: fssub
4195 1.1 is long tbl_unsupp - tbl_unsupp
4196 1.1 is long tbl_unsupp - tbl_unsupp
4197 1.1 is long tbl_unsupp - tbl_unsupp
4198 1.1 is long fdsub - tbl_unsupp # 6c: fdsub
4199 1.1 is
4200 1.1 is #################################################
4201 1.1 is # Add this here so non-fp modules can compile.
4202 1.1 is # (smovcr is called from fpsp_inex.)
4203 1.1 is global smovcr
4204 1.1 is smovcr:
4205 1.1 is bra.b smovcr
4206 1.1 is
4207 1.1 is #########################################################################
4208 1.1 is # XDEF **************************************************************** #
4209 1.1 is # fmovm_dynamic(): emulate "fmovm" dynamic instruction #
4210 1.1 is # #
4211 1.1 is # XREF **************************************************************** #
4212 1.1 is # fetch_dreg() - fetch data register #
4213 1.1 is # {i,d,}mem_read() - fetch data from memory #
4214 1.1 is # _mem_write() - write data to memory #
4215 1.1 is # iea_iacc() - instruction memory access error occurred #
4216 1.1 is # iea_dacc() - data memory access error occurred #
4217 1.1 is # restore() - restore An index regs if access error occurred #
4218 1.1 is # #
4219 1.1 is # INPUT *************************************************************** #
4220 1.1 is # None #
4221 1.1 is # #
4222 1.1 is # OUTPUT ************************************************************** #
4223 1.1 is # If instr is "fmovm Dn,-(A7)" from supervisor mode, #
4224 1.1 is # d0 = size of dump #
4225 1.1 is # d1 = Dn #
4226 1.1 is # Else if instruction access error, #
4227 1.1 is # d0 = FSLW #
4228 1.1 is # Else if data access error, #
4229 1.1 is # d0 = FSLW #
4230 1.1 is # a0 = address of fault #
4231 1.1 is # Else #
4232 1.1 is # none. #
4233 1.1 is # #
4234 1.1 is # ALGORITHM *********************************************************** #
4235 1.1 is # The effective address must be calculated since this is entered #
4236 1.1 is # from an "Unimplemented Effective Address" exception handler. So, we #
4237 1.1 is # have our own fcalc_ea() routine here. If an access error is flagged #
4238 1.1 is # by a _{i,d,}mem_read() call, we must exit through the special #
4239 1.1 is # handler. #
4240 1.1 is # The data register is determined and its value loaded to get the #
4241 1.1 is # string of FP registers affected. This value is used as an index into #
4242 1.1 is # a lookup table such that we can determine the number of bytes #
4243 1.1 is # involved. #
4244 1.1 is # If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used #
4245 1.1 is # to read in all FP values. Again, _mem_read() may fail and require a #
4246 1.1 is # special exit. #
4247 1.1 is # If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used #
4248 1.1 is # to write all FP values. _mem_write() may also fail. #
4249 1.1 is # If the instruction is "fmovm.x DN,-(a7)" from supervisor mode, #
4250 1.1 is # then we return the size of the dump and the string to the caller #
4251 1.1 is # so that the move can occur outside of this routine. This special #
4252 1.1 is # case is required so that moves to the system stack are handled #
4253 1.1 is # correctly. #
4254 1.1 is # #
4255 1.1 is # DYNAMIC: #
4256 1.1 is # fmovm.x dn, <ea> #
4257 1.1 is # fmovm.x <ea>, dn #
4258 1.1 is # #
4259 1.1 is # <WORD 1> <WORD2> #
4260 1.1 is # 1111 0010 00 |<ea>| 11@& 1000 0$$$ 0000 #
4261 1.1 is # #
4262 1.1 is # & = (0): predecrement addressing mode #
4263 1.1 is # (1): postincrement or control addressing mode #
4264 1.1 is # @ = (0): move listed regs from memory to the FPU #
4265 1.1 is # (1): move listed regs from the FPU to memory #
4266 1.1 is # $$$ : index of data register holding reg select mask #
4267 1.1 is # #
4268 1.1 is # NOTES: #
4269 1.1 is # If the data register holds a zero, then the #
4270 1.1 is # instruction is a nop. #
4271 1.1 is # #
4272 1.1 is #########################################################################
4273 1.1 is
4274 1.1 is global fmovm_dynamic
4275 1.1 is fmovm_dynamic:
4276 1.1 is
4277 1.1 is # extract the data register in which the bit string resides...
4278 1.1 is mov.b 1+EXC_EXTWORD(%a6),%d1 # fetch extword
4279 1.1 is andi.w &0x70,%d1 # extract reg bits
4280 1.1 is lsr.b &0x4,%d1 # shift into lo bits
4281 1.1 is
4282 1.1 is # fetch the bit string into d0...
4283 1.1 is bsr.l fetch_dreg # fetch reg string
4284 1.1 is
4285 1.1 is andi.l &0x000000ff,%d0 # keep only lo byte
4286 1.1 is
4287 1.1 is mov.l %d0,-(%sp) # save strg
4288 1.1 is mov.b (tbl_fmovm_size.w,%pc,%d0),%d0
4289 1.1 is mov.l %d0,-(%sp) # save size
4290 1.1 is bsr.l fmovm_calc_ea # calculate <ea>
4291 1.1 is mov.l (%sp)+,%d0 # restore size
4292 1.1 is mov.l (%sp)+,%d1 # restore strg
4293 1.1 is
4294 1.1 is # if the bit string is a zero, then the operation is a no-op
4295 1.1 is # but, make sure that we've calculated ea and advanced the opword pointer
4296 1.1 is beq.w fmovm_data_done
4297 1.1 is
4298 1.1 is # separate move ins from move outs...
4299 1.1 is btst &0x5,EXC_EXTWORD(%a6) # is it a move in or out?
4300 1.1 is beq.w fmovm_data_in # it's a move out
4301 1.1 is
4302 1.1 is #############
4303 1.1 is # MOVE OUT: #
4304 1.1 is #############
4305 1.1 is fmovm_data_out:
4306 1.1 is btst &0x4,EXC_EXTWORD(%a6) # control or predecrement?
4307 1.1 is bne.w fmovm_out_ctrl # control
4308 1.1 is
4309 1.1 is ############################
4310 1.1 is fmovm_out_predec:
4311 1.1 is # for predecrement mode, the bit string is the opposite of both control
4312 1.1 is # operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
4313 1.1 is # here, we convert it to be just like the others...
4314 1.1 is mov.b (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
4315 1.1 is
4316 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode?
4317 1.1 is beq.b fmovm_out_ctrl # user
4318 1.1 is
4319 1.1 is fmovm_out_predec_s:
4320 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
4321 1.1 is bne.b fmovm_out_ctrl
4322 1.1 is
4323 1.1 is # the operation was unfortunately an: fmovm.x dn,-(sp)
4324 1.1 is # called from supervisor mode.
4325 1.1 is # we're also passing "size" and "strg" back to the calling routine
4326 1.1 is rts
4327 1.1 is
4328 1.1 is ############################
4329 1.1 is fmovm_out_ctrl:
4330 1.1 is mov.l %a0,%a1 # move <ea> to a1
4331 1.1 is
4332 1.1 is sub.l %d0,%sp # subtract size of dump
4333 1.1 is lea (%sp),%a0
4334 1.1 is
4335 1.1 is tst.b %d1 # should FP0 be moved?
4336 1.1 is bpl.b fmovm_out_ctrl_fp1 # no
4337 1.1 is
4338 1.1 is mov.l 0x0+EXC_FP0(%a6),(%a0)+ # yes
4339 1.1 is mov.l 0x4+EXC_FP0(%a6),(%a0)+
4340 1.1 is mov.l 0x8+EXC_FP0(%a6),(%a0)+
4341 1.1 is
4342 1.1 is fmovm_out_ctrl_fp1:
4343 1.1 is lsl.b &0x1,%d1 # should FP1 be moved?
4344 1.1 is bpl.b fmovm_out_ctrl_fp2 # no
4345 1.1 is
4346 1.1 is mov.l 0x0+EXC_FP1(%a6),(%a0)+ # yes
4347 1.1 is mov.l 0x4+EXC_FP1(%a6),(%a0)+
4348 1.1 is mov.l 0x8+EXC_FP1(%a6),(%a0)+
4349 1.1 is
4350 1.1 is fmovm_out_ctrl_fp2:
4351 1.1 is lsl.b &0x1,%d1 # should FP2 be moved?
4352 1.1 is bpl.b fmovm_out_ctrl_fp3 # no
4353 1.1 is
4354 1.1 is fmovm.x &0x20,(%a0) # yes
4355 1.1 is add.l &0xc,%a0
4356 1.1 is
4357 1.1 is fmovm_out_ctrl_fp3:
4358 1.1 is lsl.b &0x1,%d1 # should FP3 be moved?
4359 1.1 is bpl.b fmovm_out_ctrl_fp4 # no
4360 1.1 is
4361 1.1 is fmovm.x &0x10,(%a0) # yes
4362 1.1 is add.l &0xc,%a0
4363 1.1 is
4364 1.1 is fmovm_out_ctrl_fp4:
4365 1.1 is lsl.b &0x1,%d1 # should FP4 be moved?
4366 1.1 is bpl.b fmovm_out_ctrl_fp5 # no
4367 1.1 is
4368 1.1 is fmovm.x &0x08,(%a0) # yes
4369 1.1 is add.l &0xc,%a0
4370 1.1 is
4371 1.1 is fmovm_out_ctrl_fp5:
4372 1.1 is lsl.b &0x1,%d1 # should FP5 be moved?
4373 1.1 is bpl.b fmovm_out_ctrl_fp6 # no
4374 1.1 is
4375 1.1 is fmovm.x &0x04,(%a0) # yes
4376 1.1 is add.l &0xc,%a0
4377 1.1 is
4378 1.1 is fmovm_out_ctrl_fp6:
4379 1.1 is lsl.b &0x1,%d1 # should FP6 be moved?
4380 1.1 is bpl.b fmovm_out_ctrl_fp7 # no
4381 1.1 is
4382 1.1 is fmovm.x &0x02,(%a0) # yes
4383 1.1 is add.l &0xc,%a0
4384 1.1 is
4385 1.1 is fmovm_out_ctrl_fp7:
4386 1.1 is lsl.b &0x1,%d1 # should FP7 be moved?
4387 1.1 is bpl.b fmovm_out_ctrl_done # no
4388 1.1 is
4389 1.1 is fmovm.x &0x01,(%a0) # yes
4390 1.1 is add.l &0xc,%a0
4391 1.1 is
4392 1.1 is fmovm_out_ctrl_done:
4393 1.1 is mov.l %a1,L_SCR1(%a6)
4394 1.1 is
4395 1.1 is lea (%sp),%a0 # pass: supervisor src
4396 1.1 is mov.l %d0,-(%sp) # save size
4397 1.1 is bsr.l _dmem_write # copy data to user mem
4398 1.1 is
4399 1.1 is mov.l (%sp)+,%d0
4400 1.1 is add.l %d0,%sp # clear fpreg data from stack
4401 1.1 is
4402 1.1 is tst.l %d1 # did dstore err?
4403 1.1 is bne.w fmovm_out_err # yes
4404 1.1 is
4405 1.1 is rts
4406 1.1 is
4407 1.1 is ############
4408 1.1 is # MOVE IN: #
4409 1.1 is ############
4410 1.1 is fmovm_data_in:
4411 1.1 is mov.l %a0,L_SCR1(%a6)
4412 1.1 is
4413 1.1 is sub.l %d0,%sp # make room for fpregs
4414 1.1 is lea (%sp),%a1
4415 1.1 is
4416 1.1 is mov.l %d1,-(%sp) # save bit string for later
4417 1.1 is mov.l %d0,-(%sp) # save # of bytes
4418 1.1 is
4419 1.1 is bsr.l _dmem_read # copy data from user mem
4420 1.1 is
4421 1.1 is mov.l (%sp)+,%d0 # retrieve # of bytes
4422 1.1 is
4423 1.1 is tst.l %d1 # did dfetch fail?
4424 1.1 is bne.w fmovm_in_err # yes
4425 1.1 is
4426 1.1 is mov.l (%sp)+,%d1 # load bit string
4427 1.1 is
4428 1.1 is lea (%sp),%a0 # addr of stack
4429 1.1 is
4430 1.1 is tst.b %d1 # should FP0 be moved?
4431 1.1 is bpl.b fmovm_data_in_fp1 # no
4432 1.1 is
4433 1.1 is mov.l (%a0)+,0x0+EXC_FP0(%a6) # yes
4434 1.1 is mov.l (%a0)+,0x4+EXC_FP0(%a6)
4435 1.1 is mov.l (%a0)+,0x8+EXC_FP0(%a6)
4436 1.1 is
4437 1.1 is fmovm_data_in_fp1:
4438 1.1 is lsl.b &0x1,%d1 # should FP1 be moved?
4439 1.1 is bpl.b fmovm_data_in_fp2 # no
4440 1.1 is
4441 1.1 is mov.l (%a0)+,0x0+EXC_FP1(%a6) # yes
4442 1.1 is mov.l (%a0)+,0x4+EXC_FP1(%a6)
4443 1.1 is mov.l (%a0)+,0x8+EXC_FP1(%a6)
4444 1.1 is
4445 1.1 is fmovm_data_in_fp2:
4446 1.1 is lsl.b &0x1,%d1 # should FP2 be moved?
4447 1.1 is bpl.b fmovm_data_in_fp3 # no
4448 1.1 is
4449 1.1 is fmovm.x (%a0)+,&0x20 # yes
4450 1.1 is
4451 1.1 is fmovm_data_in_fp3:
4452 1.1 is lsl.b &0x1,%d1 # should FP3 be moved?
4453 1.1 is bpl.b fmovm_data_in_fp4 # no
4454 1.1 is
4455 1.1 is fmovm.x (%a0)+,&0x10 # yes
4456 1.1 is
4457 1.1 is fmovm_data_in_fp4:
4458 1.1 is lsl.b &0x1,%d1 # should FP4 be moved?
4459 1.1 is bpl.b fmovm_data_in_fp5 # no
4460 1.1 is
4461 1.1 is fmovm.x (%a0)+,&0x08 # yes
4462 1.1 is
4463 1.1 is fmovm_data_in_fp5:
4464 1.1 is lsl.b &0x1,%d1 # should FP5 be moved?
4465 1.1 is bpl.b fmovm_data_in_fp6 # no
4466 1.1 is
4467 1.1 is fmovm.x (%a0)+,&0x04 # yes
4468 1.1 is
4469 1.1 is fmovm_data_in_fp6:
4470 1.1 is lsl.b &0x1,%d1 # should FP6 be moved?
4471 1.1 is bpl.b fmovm_data_in_fp7 # no
4472 1.1 is
4473 1.1 is fmovm.x (%a0)+,&0x02 # yes
4474 1.1 is
4475 1.1 is fmovm_data_in_fp7:
4476 1.1 is lsl.b &0x1,%d1 # should FP7 be moved?
4477 1.1 is bpl.b fmovm_data_in_done # no
4478 1.1 is
4479 1.1 is fmovm.x (%a0)+,&0x01 # yes
4480 1.1 is
4481 1.1 is fmovm_data_in_done:
4482 1.1 is add.l %d0,%sp # remove fpregs from stack
4483 1.1 is rts
4484 1.1 is
4485 1.1 is #####################################
4486 1.1 is
4487 1.1 is fmovm_data_done:
4488 1.1 is rts
4489 1.1 is
4490 1.1 is ##############################################################################
4491 1.1 is
4492 1.1 is #
4493 1.1 is # table indexed by the operation's bit string that gives the number
4494 1.1 is # of bytes that will be moved.
4495 1.1 is #
4496 1.1 is # number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
4497 1.1 is #
4498 1.1 is tbl_fmovm_size:
4499 1.1 is byte 0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
4500 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4501 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4502 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4503 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4504 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4505 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4506 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4507 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4508 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4509 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4510 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4511 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4512 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4513 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4514 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4515 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4516 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4517 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4518 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4519 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4520 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4521 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4522 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4523 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4524 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4525 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4526 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4527 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4528 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4529 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4530 1.1 is byte 0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
4531 1.1 is
4532 1.1 is #
4533 1.1 is # table to convert a pre-decrement bit string into a post-increment
4534 1.1 is # or control bit string.
4535 1.1 is # ex: 0x00 ==> 0x00
4536 1.1 is # 0x01 ==> 0x80
4537 1.1 is # 0x02 ==> 0x40
4538 1.1 is # .
4539 1.1 is # .
4540 1.1 is # 0xfd ==> 0xbf
4541 1.1 is # 0xfe ==> 0x7f
4542 1.1 is # 0xff ==> 0xff
4543 1.1 is #
4544 1.1 is tbl_fmovm_convert:
4545 1.1 is byte 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
4546 1.1 is byte 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
4547 1.1 is byte 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
4548 1.1 is byte 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
4549 1.1 is byte 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
4550 1.1 is byte 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
4551 1.1 is byte 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
4552 1.1 is byte 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
4553 1.1 is byte 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
4554 1.1 is byte 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
4555 1.1 is byte 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
4556 1.1 is byte 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
4557 1.1 is byte 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
4558 1.1 is byte 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
4559 1.1 is byte 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
4560 1.1 is byte 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
4561 1.1 is byte 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
4562 1.1 is byte 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
4563 1.1 is byte 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
4564 1.1 is byte 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
4565 1.1 is byte 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
4566 1.1 is byte 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
4567 1.1 is byte 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
4568 1.1 is byte 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
4569 1.1 is byte 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
4570 1.1 is byte 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
4571 1.1 is byte 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
4572 1.1 is byte 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
4573 1.1 is byte 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
4574 1.1 is byte 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
4575 1.1 is byte 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
4576 1.1 is byte 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
4577 1.1 is
4578 1.1 is global fmovm_calc_ea
4579 1.1 is ###############################################
4580 1.1 is # _fmovm_calc_ea: calculate effective address #
4581 1.1 is ###############################################
4582 1.1 is fmovm_calc_ea:
4583 1.1 is mov.l %d0,%a0 # move # bytes to a0
4584 1.1 is
4585 1.1 is # currently, MODE and REG are taken from the EXC_OPWORD. this could be
4586 1.1 is # easily changed if they were inputs passed in registers.
4587 1.1 is mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word
4588 1.1 is mov.w %d0,%d1 # make a copy
4589 1.1 is
4590 1.1 is andi.w &0x3f,%d0 # extract mode field
4591 1.1 is andi.l &0x7,%d1 # extract reg field
4592 1.1 is
4593 1.1 is # jump to the corresponding function for each {MODE,REG} pair.
4594 1.1 is mov.w (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
4595 1.1 is jmp (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
4596 1.1 is
4597 1.1 is swbeg &64
4598 1.1 is tbl_fea_mode:
4599 1.1 is short tbl_fea_mode - tbl_fea_mode
4600 1.1 is short tbl_fea_mode - tbl_fea_mode
4601 1.1 is short tbl_fea_mode - tbl_fea_mode
4602 1.1 is short tbl_fea_mode - tbl_fea_mode
4603 1.1 is short tbl_fea_mode - tbl_fea_mode
4604 1.1 is short tbl_fea_mode - tbl_fea_mode
4605 1.1 is short tbl_fea_mode - tbl_fea_mode
4606 1.1 is short tbl_fea_mode - tbl_fea_mode
4607 1.1 is
4608 1.1 is short tbl_fea_mode - tbl_fea_mode
4609 1.1 is short tbl_fea_mode - tbl_fea_mode
4610 1.1 is short tbl_fea_mode - tbl_fea_mode
4611 1.1 is short tbl_fea_mode - tbl_fea_mode
4612 1.1 is short tbl_fea_mode - tbl_fea_mode
4613 1.1 is short tbl_fea_mode - tbl_fea_mode
4614 1.1 is short tbl_fea_mode - tbl_fea_mode
4615 1.1 is short tbl_fea_mode - tbl_fea_mode
4616 1.1 is
4617 1.1 is short faddr_ind_a0 - tbl_fea_mode
4618 1.1 is short faddr_ind_a1 - tbl_fea_mode
4619 1.1 is short faddr_ind_a2 - tbl_fea_mode
4620 1.1 is short faddr_ind_a3 - tbl_fea_mode
4621 1.1 is short faddr_ind_a4 - tbl_fea_mode
4622 1.1 is short faddr_ind_a5 - tbl_fea_mode
4623 1.1 is short faddr_ind_a6 - tbl_fea_mode
4624 1.1 is short faddr_ind_a7 - tbl_fea_mode
4625 1.1 is
4626 1.1 is short faddr_ind_p_a0 - tbl_fea_mode
4627 1.1 is short faddr_ind_p_a1 - tbl_fea_mode
4628 1.1 is short faddr_ind_p_a2 - tbl_fea_mode
4629 1.1 is short faddr_ind_p_a3 - tbl_fea_mode
4630 1.1 is short faddr_ind_p_a4 - tbl_fea_mode
4631 1.1 is short faddr_ind_p_a5 - tbl_fea_mode
4632 1.1 is short faddr_ind_p_a6 - tbl_fea_mode
4633 1.1 is short faddr_ind_p_a7 - tbl_fea_mode
4634 1.1 is
4635 1.1 is short faddr_ind_m_a0 - tbl_fea_mode
4636 1.1 is short faddr_ind_m_a1 - tbl_fea_mode
4637 1.1 is short faddr_ind_m_a2 - tbl_fea_mode
4638 1.1 is short faddr_ind_m_a3 - tbl_fea_mode
4639 1.1 is short faddr_ind_m_a4 - tbl_fea_mode
4640 1.1 is short faddr_ind_m_a5 - tbl_fea_mode
4641 1.1 is short faddr_ind_m_a6 - tbl_fea_mode
4642 1.1 is short faddr_ind_m_a7 - tbl_fea_mode
4643 1.1 is
4644 1.1 is short faddr_ind_disp_a0 - tbl_fea_mode
4645 1.1 is short faddr_ind_disp_a1 - tbl_fea_mode
4646 1.1 is short faddr_ind_disp_a2 - tbl_fea_mode
4647 1.1 is short faddr_ind_disp_a3 - tbl_fea_mode
4648 1.1 is short faddr_ind_disp_a4 - tbl_fea_mode
4649 1.1 is short faddr_ind_disp_a5 - tbl_fea_mode
4650 1.1 is short faddr_ind_disp_a6 - tbl_fea_mode
4651 1.1 is short faddr_ind_disp_a7 - tbl_fea_mode
4652 1.1 is
4653 1.1 is short faddr_ind_ext - tbl_fea_mode
4654 1.1 is short faddr_ind_ext - tbl_fea_mode
4655 1.1 is short faddr_ind_ext - tbl_fea_mode
4656 1.1 is short faddr_ind_ext - tbl_fea_mode
4657 1.1 is short faddr_ind_ext - tbl_fea_mode
4658 1.1 is short faddr_ind_ext - tbl_fea_mode
4659 1.1 is short faddr_ind_ext - tbl_fea_mode
4660 1.1 is short faddr_ind_ext - tbl_fea_mode
4661 1.1 is
4662 1.1 is short fabs_short - tbl_fea_mode
4663 1.1 is short fabs_long - tbl_fea_mode
4664 1.1 is short fpc_ind - tbl_fea_mode
4665 1.1 is short fpc_ind_ext - tbl_fea_mode
4666 1.1 is short tbl_fea_mode - tbl_fea_mode
4667 1.1 is short tbl_fea_mode - tbl_fea_mode
4668 1.1 is short tbl_fea_mode - tbl_fea_mode
4669 1.1 is short tbl_fea_mode - tbl_fea_mode
4670 1.1 is
4671 1.1 is ###################################
4672 1.1 is # Address register indirect: (An) #
4673 1.1 is ###################################
4674 1.1 is faddr_ind_a0:
4675 1.1 is mov.l EXC_DREGS+0x8(%a6),%a0 # Get current a0
4676 1.1 is rts
4677 1.1 is
4678 1.1 is faddr_ind_a1:
4679 1.1 is mov.l EXC_DREGS+0xc(%a6),%a0 # Get current a1
4680 1.1 is rts
4681 1.1 is
4682 1.1 is faddr_ind_a2:
4683 1.1 is mov.l %a2,%a0 # Get current a2
4684 1.1 is rts
4685 1.1 is
4686 1.1 is faddr_ind_a3:
4687 1.1 is mov.l %a3,%a0 # Get current a3
4688 1.1 is rts
4689 1.1 is
4690 1.1 is faddr_ind_a4:
4691 1.1 is mov.l %a4,%a0 # Get current a4
4692 1.1 is rts
4693 1.1 is
4694 1.1 is faddr_ind_a5:
4695 1.1 is mov.l %a5,%a0 # Get current a5
4696 1.1 is rts
4697 1.1 is
4698 1.1 is faddr_ind_a6:
4699 1.1 is mov.l (%a6),%a0 # Get current a6
4700 1.1 is rts
4701 1.1 is
4702 1.1 is faddr_ind_a7:
4703 1.1 is mov.l EXC_A7(%a6),%a0 # Get current a7
4704 1.1 is rts
4705 1.1 is
4706 1.1 is #####################################################
4707 1.1 is # Address register indirect w/ postincrement: (An)+ #
4708 1.1 is #####################################################
4709 1.1 is faddr_ind_p_a0:
4710 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0
4711 1.1 is mov.l %d0,%d1
4712 1.1 is add.l %a0,%d1 # Increment
4713 1.1 is mov.l %d1,EXC_DREGS+0x8(%a6) # Save incr value
4714 1.1 is mov.l %d0,%a0
4715 1.1 is rts
4716 1.1 is
4717 1.1 is faddr_ind_p_a1:
4718 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1
4719 1.1 is mov.l %d0,%d1
4720 1.1 is add.l %a0,%d1 # Increment
4721 1.1 is mov.l %d1,EXC_DREGS+0xc(%a6) # Save incr value
4722 1.1 is mov.l %d0,%a0
4723 1.1 is rts
4724 1.1 is
4725 1.1 is faddr_ind_p_a2:
4726 1.1 is mov.l %a2,%d0 # Get current a2
4727 1.1 is mov.l %d0,%d1
4728 1.1 is add.l %a0,%d1 # Increment
4729 1.1 is mov.l %d1,%a2 # Save incr value
4730 1.1 is mov.l %d0,%a0
4731 1.1 is rts
4732 1.1 is
4733 1.1 is faddr_ind_p_a3:
4734 1.1 is mov.l %a3,%d0 # Get current a3
4735 1.1 is mov.l %d0,%d1
4736 1.1 is add.l %a0,%d1 # Increment
4737 1.1 is mov.l %d1,%a3 # Save incr value
4738 1.1 is mov.l %d0,%a0
4739 1.1 is rts
4740 1.1 is
4741 1.1 is faddr_ind_p_a4:
4742 1.1 is mov.l %a4,%d0 # Get current a4
4743 1.1 is mov.l %d0,%d1
4744 1.1 is add.l %a0,%d1 # Increment
4745 1.1 is mov.l %d1,%a4 # Save incr value
4746 1.1 is mov.l %d0,%a0
4747 1.1 is rts
4748 1.1 is
4749 1.1 is faddr_ind_p_a5:
4750 1.1 is mov.l %a5,%d0 # Get current a5
4751 1.1 is mov.l %d0,%d1
4752 1.1 is add.l %a0,%d1 # Increment
4753 1.1 is mov.l %d1,%a5 # Save incr value
4754 1.1 is mov.l %d0,%a0
4755 1.1 is rts
4756 1.1 is
4757 1.1 is faddr_ind_p_a6:
4758 1.1 is mov.l (%a6),%d0 # Get current a6
4759 1.1 is mov.l %d0,%d1
4760 1.1 is add.l %a0,%d1 # Increment
4761 1.1 is mov.l %d1,(%a6) # Save incr value
4762 1.1 is mov.l %d0,%a0
4763 1.1 is rts
4764 1.1 is
4765 1.1 is faddr_ind_p_a7:
4766 1.1 is mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
4767 1.1 is
4768 1.1 is mov.l EXC_A7(%a6),%d0 # Get current a7
4769 1.1 is mov.l %d0,%d1
4770 1.1 is add.l %a0,%d1 # Increment
4771 1.1 is mov.l %d1,EXC_A7(%a6) # Save incr value
4772 1.1 is mov.l %d0,%a0
4773 1.1 is rts
4774 1.1 is
4775 1.1 is ####################################################
4776 1.1 is # Address register indirect w/ predecrement: -(An) #
4777 1.1 is ####################################################
4778 1.1 is faddr_ind_m_a0:
4779 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0
4780 1.1 is sub.l %a0,%d0 # Decrement
4781 1.1 is mov.l %d0,EXC_DREGS+0x8(%a6) # Save decr value
4782 1.1 is mov.l %d0,%a0
4783 1.1 is rts
4784 1.1 is
4785 1.1 is faddr_ind_m_a1:
4786 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1
4787 1.1 is sub.l %a0,%d0 # Decrement
4788 1.1 is mov.l %d0,EXC_DREGS+0xc(%a6) # Save decr value
4789 1.1 is mov.l %d0,%a0
4790 1.1 is rts
4791 1.1 is
4792 1.1 is faddr_ind_m_a2:
4793 1.1 is mov.l %a2,%d0 # Get current a2
4794 1.1 is sub.l %a0,%d0 # Decrement
4795 1.1 is mov.l %d0,%a2 # Save decr value
4796 1.1 is mov.l %d0,%a0
4797 1.1 is rts
4798 1.1 is
4799 1.1 is faddr_ind_m_a3:
4800 1.1 is mov.l %a3,%d0 # Get current a3
4801 1.1 is sub.l %a0,%d0 # Decrement
4802 1.1 is mov.l %d0,%a3 # Save decr value
4803 1.1 is mov.l %d0,%a0
4804 1.1 is rts
4805 1.1 is
4806 1.1 is faddr_ind_m_a4:
4807 1.1 is mov.l %a4,%d0 # Get current a4
4808 1.1 is sub.l %a0,%d0 # Decrement
4809 1.1 is mov.l %d0,%a4 # Save decr value
4810 1.1 is mov.l %d0,%a0
4811 1.1 is rts
4812 1.1 is
4813 1.1 is faddr_ind_m_a5:
4814 1.1 is mov.l %a5,%d0 # Get current a5
4815 1.1 is sub.l %a0,%d0 # Decrement
4816 1.1 is mov.l %d0,%a5 # Save decr value
4817 1.1 is mov.l %d0,%a0
4818 1.1 is rts
4819 1.1 is
4820 1.1 is faddr_ind_m_a6:
4821 1.1 is mov.l (%a6),%d0 # Get current a6
4822 1.1 is sub.l %a0,%d0 # Decrement
4823 1.1 is mov.l %d0,(%a6) # Save decr value
4824 1.1 is mov.l %d0,%a0
4825 1.1 is rts
4826 1.1 is
4827 1.1 is faddr_ind_m_a7:
4828 1.1 is mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
4829 1.1 is
4830 1.1 is mov.l EXC_A7(%a6),%d0 # Get current a7
4831 1.1 is sub.l %a0,%d0 # Decrement
4832 1.1 is mov.l %d0,EXC_A7(%a6) # Save decr value
4833 1.1 is mov.l %d0,%a0
4834 1.1 is rts
4835 1.1 is
4836 1.1 is ########################################################
4837 1.1 is # Address register indirect w/ displacement: (d16, An) #
4838 1.1 is ########################################################
4839 1.1 is faddr_ind_disp_a0:
4840 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4841 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4842 1.1 is bsr.l _imem_read_word
4843 1.1 is
4844 1.1 is tst.l %d1 # did ifetch fail?
4845 1.1 is bne.l iea_iacc # yes
4846 1.1 is
4847 1.1 is mov.w %d0,%a0 # sign extend displacement
4848 1.1 is
4849 1.1 is add.l EXC_DREGS+0x8(%a6),%a0 # a0 + d16
4850 1.1 is rts
4851 1.1 is
4852 1.1 is faddr_ind_disp_a1:
4853 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4854 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4855 1.1 is bsr.l _imem_read_word
4856 1.1 is
4857 1.1 is tst.l %d1 # did ifetch fail?
4858 1.1 is bne.l iea_iacc # yes
4859 1.1 is
4860 1.1 is mov.w %d0,%a0 # sign extend displacement
4861 1.1 is
4862 1.1 is add.l EXC_DREGS+0xc(%a6),%a0 # a1 + d16
4863 1.1 is rts
4864 1.1 is
4865 1.1 is faddr_ind_disp_a2:
4866 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4867 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4868 1.1 is bsr.l _imem_read_word
4869 1.1 is
4870 1.1 is tst.l %d1 # did ifetch fail?
4871 1.1 is bne.l iea_iacc # yes
4872 1.1 is
4873 1.1 is mov.w %d0,%a0 # sign extend displacement
4874 1.1 is
4875 1.1 is add.l %a2,%a0 # a2 + d16
4876 1.1 is rts
4877 1.1 is
4878 1.1 is faddr_ind_disp_a3:
4879 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4880 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4881 1.1 is bsr.l _imem_read_word
4882 1.1 is
4883 1.1 is tst.l %d1 # did ifetch fail?
4884 1.1 is bne.l iea_iacc # yes
4885 1.1 is
4886 1.1 is mov.w %d0,%a0 # sign extend displacement
4887 1.1 is
4888 1.1 is add.l %a3,%a0 # a3 + d16
4889 1.1 is rts
4890 1.1 is
4891 1.1 is faddr_ind_disp_a4:
4892 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4893 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4894 1.1 is bsr.l _imem_read_word
4895 1.1 is
4896 1.1 is tst.l %d1 # did ifetch fail?
4897 1.1 is bne.l iea_iacc # yes
4898 1.1 is
4899 1.1 is mov.w %d0,%a0 # sign extend displacement
4900 1.1 is
4901 1.1 is add.l %a4,%a0 # a4 + d16
4902 1.1 is rts
4903 1.1 is
4904 1.1 is faddr_ind_disp_a5:
4905 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4906 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4907 1.1 is bsr.l _imem_read_word
4908 1.1 is
4909 1.1 is tst.l %d1 # did ifetch fail?
4910 1.1 is bne.l iea_iacc # yes
4911 1.1 is
4912 1.1 is mov.w %d0,%a0 # sign extend displacement
4913 1.1 is
4914 1.1 is add.l %a5,%a0 # a5 + d16
4915 1.1 is rts
4916 1.1 is
4917 1.1 is faddr_ind_disp_a6:
4918 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4919 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4920 1.1 is bsr.l _imem_read_word
4921 1.1 is
4922 1.1 is tst.l %d1 # did ifetch fail?
4923 1.1 is bne.l iea_iacc # yes
4924 1.1 is
4925 1.1 is mov.w %d0,%a0 # sign extend displacement
4926 1.1 is
4927 1.1 is add.l (%a6),%a0 # a6 + d16
4928 1.1 is rts
4929 1.1 is
4930 1.1 is faddr_ind_disp_a7:
4931 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4932 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4933 1.1 is bsr.l _imem_read_word
4934 1.1 is
4935 1.1 is tst.l %d1 # did ifetch fail?
4936 1.1 is bne.l iea_iacc # yes
4937 1.1 is
4938 1.1 is mov.w %d0,%a0 # sign extend displacement
4939 1.1 is
4940 1.1 is add.l EXC_A7(%a6),%a0 # a7 + d16
4941 1.1 is rts
4942 1.1 is
4943 1.1 is ########################################################################
4944 1.1 is # Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
4945 1.1 is # " " " w/ " (base displacement): (bd, An, Xn) #
4946 1.1 is # Memory indirect postindexed: ([bd, An], Xn, od) #
4947 1.1 is # Memory indirect preindexed: ([bd, An, Xn], od) #
4948 1.1 is ########################################################################
4949 1.1 is faddr_ind_ext:
4950 1.1 is addq.l &0x8,%d1
4951 1.1 is bsr.l fetch_dreg # fetch base areg
4952 1.1 is mov.l %d0,-(%sp)
4953 1.1 is
4954 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4955 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4956 1.1 is bsr.l _imem_read_word # fetch extword in d0
4957 1.1 is
4958 1.1 is tst.l %d1 # did ifetch fail?
4959 1.1 is bne.l iea_iacc # yes
4960 1.1 is
4961 1.1 is mov.l (%sp)+,%a0
4962 1.1 is
4963 1.1 is btst &0x8,%d0
4964 1.1 is bne.w fcalc_mem_ind
4965 1.1 is
4966 1.1 is mov.l %d0,L_SCR1(%a6) # hold opword
4967 1.1 is
4968 1.1 is mov.l %d0,%d1
4969 1.1 is rol.w &0x4,%d1
4970 1.1 is andi.w &0xf,%d1 # extract index regno
4971 1.1 is
4972 1.1 is # count on fetch_dreg() not to alter a0...
4973 1.1 is bsr.l fetch_dreg # fetch index
4974 1.1 is
4975 1.1 is mov.l %d2,-(%sp) # save d2
4976 1.1 is mov.l L_SCR1(%a6),%d2 # fetch opword
4977 1.1 is
4978 1.1 is btst &0xb,%d2 # is it word or long?
4979 1.1 is bne.b faii8_long
4980 1.1 is ext.l %d0 # sign extend word index
4981 1.1 is faii8_long:
4982 1.1 is mov.l %d2,%d1
4983 1.1 is rol.w &0x7,%d1
4984 1.1 is andi.l &0x3,%d1 # extract scale value
4985 1.1 is
4986 1.1 is lsl.l %d1,%d0 # shift index by scale
4987 1.1 is
4988 1.1 is extb.l %d2 # sign extend displacement
4989 1.1 is add.l %d2,%d0 # index + disp
4990 1.1 is add.l %d0,%a0 # An + (index + disp)
4991 1.1 is
4992 1.1 is mov.l (%sp)+,%d2 # restore old d2
4993 1.1 is rts
4994 1.1 is
4995 1.1 is ###########################
4996 1.1 is # Absolute short: (XXX).W #
4997 1.1 is ###########################
4998 1.1 is fabs_short:
4999 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5000 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5001 1.1 is bsr.l _imem_read_word # fetch short address
5002 1.1 is
5003 1.1 is tst.l %d1 # did ifetch fail?
5004 1.1 is bne.l iea_iacc # yes
5005 1.1 is
5006 1.1 is mov.w %d0,%a0 # return <ea> in a0
5007 1.1 is rts
5008 1.1 is
5009 1.1 is ##########################
5010 1.1 is # Absolute long: (XXX).L #
5011 1.1 is ##########################
5012 1.1 is fabs_long:
5013 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5014 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5015 1.1 is bsr.l _imem_read_long # fetch long address
5016 1.1 is
5017 1.1 is tst.l %d1 # did ifetch fail?
5018 1.1 is bne.l iea_iacc # yes
5019 1.1 is
5020 1.1 is mov.l %d0,%a0 # return <ea> in a0
5021 1.1 is rts
5022 1.1 is
5023 1.1 is #######################################################
5024 1.1 is # Program counter indirect w/ displacement: (d16, PC) #
5025 1.1 is #######################################################
5026 1.1 is fpc_ind:
5027 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5028 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5029 1.1 is bsr.l _imem_read_word # fetch word displacement
5030 1.1 is
5031 1.1 is tst.l %d1 # did ifetch fail?
5032 1.1 is bne.l iea_iacc # yes
5033 1.1 is
5034 1.1 is mov.w %d0,%a0 # sign extend displacement
5035 1.1 is
5036 1.1 is add.l EXC_EXTWPTR(%a6),%a0 # pc + d16
5037 1.1 is
5038 1.1 is # _imem_read_word() increased the extwptr by 2. need to adjust here.
5039 1.1 is subq.l &0x2,%a0 # adjust <ea>
5040 1.1 is rts
5041 1.1 is
5042 1.1 is ##########################################################
5043 1.1 is # PC indirect w/ index(8-bit displacement): (d8, PC, An) #
5044 1.1 is # " " w/ " (base displacement): (bd, PC, An) #
5045 1.1 is # PC memory indirect postindexed: ([bd, PC], Xn, od) #
5046 1.1 is # PC memory indirect preindexed: ([bd, PC, Xn], od) #
5047 1.1 is ##########################################################
5048 1.1 is fpc_ind_ext:
5049 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5050 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5051 1.1 is bsr.l _imem_read_word # fetch ext word
5052 1.1 is
5053 1.1 is tst.l %d1 # did ifetch fail?
5054 1.1 is bne.l iea_iacc # yes
5055 1.1 is
5056 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0
5057 1.1 is subq.l &0x2,%a0 # adjust base
5058 1.1 is
5059 1.1 is btst &0x8,%d0 # is disp only 8 bits?
5060 1.1 is bne.w fcalc_mem_ind # calc memory indirect
5061 1.1 is
5062 1.1 is mov.l %d0,L_SCR1(%a6) # store opword
5063 1.1 is
5064 1.1 is mov.l %d0,%d1 # make extword copy
5065 1.1 is rol.w &0x4,%d1 # rotate reg num into place
5066 1.1 is andi.w &0xf,%d1 # extract register number
5067 1.1 is
5068 1.1 is # count on fetch_dreg() not to alter a0...
5069 1.1 is bsr.l fetch_dreg # fetch index
5070 1.1 is
5071 1.1 is mov.l %d2,-(%sp) # save d2
5072 1.1 is mov.l L_SCR1(%a6),%d2 # fetch opword
5073 1.1 is
5074 1.1 is btst &0xb,%d2 # is index word or long?
5075 1.1 is bne.b fpii8_long # long
5076 1.1 is ext.l %d0 # sign extend word index
5077 1.1 is fpii8_long:
5078 1.1 is mov.l %d2,%d1
5079 1.1 is rol.w &0x7,%d1 # rotate scale value into place
5080 1.1 is andi.l &0x3,%d1 # extract scale value
5081 1.1 is
5082 1.1 is lsl.l %d1,%d0 # shift index by scale
5083 1.1 is
5084 1.1 is extb.l %d2 # sign extend displacement
5085 1.1 is add.l %d2,%d0 # disp + index
5086 1.1 is add.l %d0,%a0 # An + (index + disp)
5087 1.1 is
5088 1.1 is mov.l (%sp)+,%d2 # restore temp register
5089 1.1 is rts
5090 1.1 is
5091 1.1 is # d2 = index
5092 1.1 is # d3 = base
5093 1.1 is # d4 = od
5094 1.1 is # d5 = extword
5095 1.1 is fcalc_mem_ind:
5096 1.1 is btst &0x6,%d0 # is the index suppressed?
5097 1.1 is beq.b fcalc_index
5098 1.1 is
5099 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5
5100 1.1 is
5101 1.1 is mov.l %d0,%d5 # put extword in d5
5102 1.1 is mov.l %a0,%d3 # put base in d3
5103 1.1 is
5104 1.1 is clr.l %d2 # yes, so index = 0
5105 1.1 is bra.b fbase_supp_ck
5106 1.1 is
5107 1.1 is # index:
5108 1.1 is fcalc_index:
5109 1.1 is mov.l %d0,L_SCR1(%a6) # save d0 (opword)
5110 1.1 is bfextu %d0{&16:&4},%d1 # fetch dreg index
5111 1.1 is bsr.l fetch_dreg
5112 1.1 is
5113 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5
5114 1.1 is mov.l %d0,%d2 # put index in d2
5115 1.1 is mov.l L_SCR1(%a6),%d5
5116 1.1 is mov.l %a0,%d3
5117 1.1 is
5118 1.1 is btst &0xb,%d5 # is index word or long?
5119 1.1 is bne.b fno_ext
5120 1.1 is ext.l %d2
5121 1.1 is
5122 1.1 is fno_ext:
5123 1.1 is bfextu %d5{&21:&2},%d0
5124 1.1 is lsl.l %d0,%d2
5125 1.1 is
5126 1.1 is # base address (passed as parameter in d3):
5127 1.1 is # we clear the value here if it should actually be suppressed.
5128 1.1 is fbase_supp_ck:
5129 1.1 is btst &0x7,%d5 # is the bd suppressed?
5130 1.1 is beq.b fno_base_sup
5131 1.1 is clr.l %d3
5132 1.1 is
5133 1.1 is # base displacement:
5134 1.1 is fno_base_sup:
5135 1.1 is bfextu %d5{&26:&2},%d0 # get bd size
5136 1.1 is # beq.l fmovm_error # if (size == 0) it's reserved
5137 1.1 is
5138 1.1 is cmpi.b %d0,&0x2
5139 1.1 is blt.b fno_bd
5140 1.1 is beq.b fget_word_bd
5141 1.1 is
5142 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5143 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5144 1.1 is bsr.l _imem_read_long
5145 1.1 is
5146 1.1 is tst.l %d1 # did ifetch fail?
5147 1.1 is bne.l fcea_iacc # yes
5148 1.1 is
5149 1.1 is bra.b fchk_ind
5150 1.1 is
5151 1.1 is fget_word_bd:
5152 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5153 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5154 1.1 is bsr.l _imem_read_word
5155 1.1 is
5156 1.1 is tst.l %d1 # did ifetch fail?
5157 1.1 is bne.l fcea_iacc # yes
5158 1.1 is
5159 1.1 is ext.l %d0 # sign extend bd
5160 1.1 is
5161 1.1 is fchk_ind:
5162 1.1 is add.l %d0,%d3 # base += bd
5163 1.1 is
5164 1.1 is # outer displacement:
5165 1.1 is fno_bd:
5166 1.1 is bfextu %d5{&30:&2},%d0 # is od suppressed?
5167 1.1 is beq.w faii_bd
5168 1.1 is
5169 1.1 is cmpi.b %d0,&0x2
5170 1.1 is blt.b fnull_od
5171 1.1 is beq.b fword_od
5172 1.1 is
5173 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5174 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5175 1.1 is bsr.l _imem_read_long
5176 1.1 is
5177 1.1 is tst.l %d1 # did ifetch fail?
5178 1.1 is bne.l fcea_iacc # yes
5179 1.1 is
5180 1.1 is bra.b fadd_them
5181 1.1 is
5182 1.1 is fword_od:
5183 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5184 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5185 1.1 is bsr.l _imem_read_word
5186 1.1 is
5187 1.1 is tst.l %d1 # did ifetch fail?
5188 1.1 is bne.l fcea_iacc # yes
5189 1.1 is
5190 1.1 is ext.l %d0 # sign extend od
5191 1.1 is bra.b fadd_them
5192 1.1 is
5193 1.1 is fnull_od:
5194 1.1 is clr.l %d0
5195 1.1 is
5196 1.1 is fadd_them:
5197 1.1 is mov.l %d0,%d4
5198 1.1 is
5199 1.1 is btst &0x2,%d5 # pre or post indexing?
5200 1.1 is beq.b fpre_indexed
5201 1.1 is
5202 1.1 is mov.l %d3,%a0
5203 1.1 is bsr.l _dmem_read_long
5204 1.1 is
5205 1.1 is tst.l %d1 # did dfetch fail?
5206 1.1 is bne.w fcea_err # yes
5207 1.1 is
5208 1.1 is add.l %d2,%d0 # <ea> += index
5209 1.1 is add.l %d4,%d0 # <ea> += od
5210 1.1 is bra.b fdone_ea
5211 1.1 is
5212 1.1 is fpre_indexed:
5213 1.1 is add.l %d2,%d3 # preindexing
5214 1.1 is mov.l %d3,%a0
5215 1.1 is bsr.l _dmem_read_long
5216 1.1 is
5217 1.1 is tst.l %d1 # did dfetch fail?
5218 1.1 is bne.w fcea_err # yes
5219 1.1 is
5220 1.1 is add.l %d4,%d0 # ea += od
5221 1.1 is bra.b fdone_ea
5222 1.1 is
5223 1.1 is faii_bd:
5224 1.1 is add.l %d2,%d3 # ea = (base + bd) + index
5225 1.1 is mov.l %d3,%d0
5226 1.1 is fdone_ea:
5227 1.1 is mov.l %d0,%a0
5228 1.1 is
5229 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5
5230 1.1 is rts
5231 1.1 is
5232 1.1 is #########################################################
5233 1.1 is fcea_err:
5234 1.1 is mov.l %d3,%a0
5235 1.1 is
5236 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5
5237 1.1 is mov.w &0x0101,%d0
5238 1.1 is bra.l iea_dacc
5239 1.1 is
5240 1.1 is fcea_iacc:
5241 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5
5242 1.1 is bra.l iea_iacc
5243 1.1 is
5244 1.1 is fmovm_out_err:
5245 1.1 is bsr.l restore
5246 1.1 is mov.w &0x00e1,%d0
5247 1.1 is bra.b fmovm_err
5248 1.1 is
5249 1.1 is fmovm_in_err:
5250 1.1 is bsr.l restore
5251 1.1 is mov.w &0x0161,%d0
5252 1.1 is
5253 1.1 is fmovm_err:
5254 1.1 is mov.l L_SCR1(%a6),%a0
5255 1.1 is bra.l iea_dacc
5256 1.1 is
5257 1.1 is #########################################################################
5258 1.1 is # XDEF **************************************************************** #
5259 1.1 is # fmovm_ctrl(): emulate fmovm.l of control registers instr #
5260 1.1 is # #
5261 1.1 is # XREF **************************************************************** #
5262 1.1 is # _imem_read_long() - read longword from memory #
5263 1.1 is # iea_iacc() - _imem_read_long() failed; error recovery #
5264 1.1 is # #
5265 1.1 is # INPUT *************************************************************** #
5266 1.1 is # None #
5267 1.1 is # #
5268 1.1 is # OUTPUT ************************************************************** #
5269 1.1 is # If _imem_read_long() doesn't fail: #
5270 1.1 is # USER_FPCR(a6) = new FPCR value #
5271 1.1 is # USER_FPSR(a6) = new FPSR value #
5272 1.1 is # USER_FPIAR(a6) = new FPIAR value #
5273 1.1 is # #
5274 1.1 is # ALGORITHM *********************************************************** #
5275 1.1 is # Decode the instruction type by looking at the extension word #
5276 1.1 is # in order to see how many control registers to fetch from memory. #
5277 1.1 is # Fetch them using _imem_read_long(). If this fetch fails, exit through #
5278 1.1 is # the special access error exit handler iea_iacc(). #
5279 1.1 is # #
5280 1.1 is # Instruction word decoding: #
5281 1.1 is # #
5282 1.1 is # fmovem.l #<data>, {FPIAR&|FPCR&|FPSR} #
5283 1.1 is # #
5284 1.1 is # WORD1 WORD2 #
5285 1.1 is # 1111 0010 00 111100 100$ $$00 0000 0000 #
5286 1.1 is # #
5287 1.1 is # $$$ (100): FPCR #
5288 1.1 is # (010): FPSR #
5289 1.1 is # (001): FPIAR #
5290 1.1 is # (000): FPIAR #
5291 1.1 is # #
5292 1.1 is #########################################################################
5293 1.1 is
5294 1.1 is global fmovm_ctrl
5295 1.1 is fmovm_ctrl:
5296 1.1 is mov.b EXC_EXTWORD(%a6),%d0 # fetch reg select bits
5297 1.1 is cmpi.b %d0,&0x9c # fpcr & fpsr & fpiar ?
5298 1.1 is beq.w fctrl_in_7 # yes
5299 1.1 is cmpi.b %d0,&0x98 # fpcr & fpsr ?
5300 1.1 is beq.w fctrl_in_6 # yes
5301 1.1 is cmpi.b %d0,&0x94 # fpcr & fpiar ?
5302 1.1 is beq.b fctrl_in_5 # yes
5303 1.1 is
5304 1.1 is # fmovem.l #<data>, fpsr/fpiar
5305 1.1 is fctrl_in_3:
5306 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5307 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5308 1.1 is bsr.l _imem_read_long # fetch FPSR from mem
5309 1.1 is
5310 1.1 is tst.l %d1 # did ifetch fail?
5311 1.1 is bne.l iea_iacc # yes
5312 1.1 is
5313 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to stack
5314 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5315 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5316 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem
5317 1.1 is
5318 1.1 is tst.l %d1 # did ifetch fail?
5319 1.1 is bne.l iea_iacc # yes
5320 1.1 is
5321 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack
5322 1.1 is rts
5323 1.1 is
5324 1.1 is # fmovem.l #<data>, fpcr/fpiar
5325 1.1 is fctrl_in_5:
5326 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5327 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5328 1.1 is bsr.l _imem_read_long # fetch FPCR from mem
5329 1.1 is
5330 1.1 is tst.l %d1 # did ifetch fail?
5331 1.1 is bne.l iea_iacc # yes
5332 1.1 is
5333 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to stack
5334 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5335 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5336 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem
5337 1.1 is
5338 1.1 is tst.l %d1 # did ifetch fail?
5339 1.1 is bne.l iea_iacc # yes
5340 1.1 is
5341 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack
5342 1.1 is rts
5343 1.1 is
5344 1.1 is # fmovem.l #<data>, fpcr/fpsr
5345 1.1 is fctrl_in_6:
5346 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5347 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5348 1.1 is bsr.l _imem_read_long # fetch FPCR from mem
5349 1.1 is
5350 1.1 is tst.l %d1 # did ifetch fail?
5351 1.1 is bne.l iea_iacc # yes
5352 1.1 is
5353 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem
5354 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5355 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5356 1.1 is bsr.l _imem_read_long # fetch FPSR from mem
5357 1.1 is
5358 1.1 is tst.l %d1 # did ifetch fail?
5359 1.1 is bne.l iea_iacc # yes
5360 1.1 is
5361 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem
5362 1.1 is rts
5363 1.1 is
5364 1.1 is # fmovem.l #<data>, fpcr/fpsr/fpiar
5365 1.1 is fctrl_in_7:
5366 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5367 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5368 1.1 is bsr.l _imem_read_long # fetch FPCR from mem
5369 1.1 is
5370 1.1 is tst.l %d1 # did ifetch fail?
5371 1.1 is bne.l iea_iacc # yes
5372 1.1 is
5373 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem
5374 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5375 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5376 1.1 is bsr.l _imem_read_long # fetch FPSR from mem
5377 1.1 is
5378 1.1 is tst.l %d1 # did ifetch fail?
5379 1.1 is bne.l iea_iacc # yes
5380 1.1 is
5381 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem
5382 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5383 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5384 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem
5385 1.1 is
5386 1.1 is tst.l %d1 # did ifetch fail?
5387 1.1 is bne.l iea_iacc # yes
5388 1.1 is
5389 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to mem
5390 1.1 is rts
5391 1.1 is
5392 1.1 is ##########################################################################
5393 1.1 is
5394 1.1 is #########################################################################
5395 1.1 is # XDEF **************************************************************** #
5396 1.1 is # addsub_scaler2(): scale inputs to fadd/fsub such that no #
5397 1.1 is # OVFL/UNFL exceptions will result #
5398 1.1 is # #
5399 1.1 is # XREF **************************************************************** #
5400 1.1 is # norm() - normalize mantissa after adjusting exponent #
5401 1.1 is # #
5402 1.1 is # INPUT *************************************************************** #
5403 1.1 is # FP_SRC(a6) = fp op1(src) #
5404 1.1 is # FP_DST(a6) = fp op2(dst) #
5405 1.1 is # #
5406 1.1 is # OUTPUT ************************************************************** #
5407 1.1 is # FP_SRC(a6) = fp op1 scaled(src) #
5408 1.1 is # FP_DST(a6) = fp op2 scaled(dst) #
5409 1.1 is # d0 = scale amount #
5410 1.1 is # #
5411 1.1 is # ALGORITHM *********************************************************** #
5412 1.1 is # If the DST exponent is > the SRC exponent, set the DST exponent #
5413 1.1 is # equal to 0x3fff and scale the SRC exponent by the value that the #
5414 1.1 is # DST exponent was scaled by. If the SRC exponent is greater or equal, #
5415 1.1 is # do the opposite. Return this scale factor in d0. #
5416 1.1 is # If the two exponents differ by > the number of mantissa bits #
5417 1.1 is # plus two, then set the smallest exponent to a very small value as a #
5418 1.1 is # quick shortcut. #
5419 1.1 is # #
5420 1.1 is #########################################################################
5421 1.1 is
5422 1.1 is global addsub_scaler2
5423 1.1 is addsub_scaler2:
5424 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
5425 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
5426 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
5427 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
5428 1.1 is mov.w SRC_EX(%a0),%d0
5429 1.1 is mov.w DST_EX(%a1),%d1
5430 1.1 is mov.w %d0,FP_SCR0_EX(%a6)
5431 1.1 is mov.w %d1,FP_SCR1_EX(%a6)
5432 1.1 is
5433 1.1 is andi.w &0x7fff,%d0
5434 1.1 is andi.w &0x7fff,%d1
5435 1.1 is mov.w %d0,L_SCR1(%a6) # store src exponent
5436 1.1 is mov.w %d1,2+L_SCR1(%a6) # store dst exponent
5437 1.1 is
5438 1.1 is cmp.w %d0, %d1 # is src exp >= dst exp?
5439 1.1 is bge.l src_exp_ge2
5440 1.1 is
5441 1.1 is # dst exp is > src exp; scale dst to exp = 0x3fff
5442 1.1 is dst_exp_gt2:
5443 1.1 is bsr.l scale_to_zero_dst
5444 1.1 is mov.l %d0,-(%sp) # save scale factor
5445 1.1 is
5446 1.1 is cmpi.b STAG(%a6),&DENORM # is dst denormalized?
5447 1.1 is bne.b cmpexp12
5448 1.1 is
5449 1.1 is lea FP_SCR0(%a6),%a0
5450 1.1 is bsr.l norm # normalize the denorm; result is new exp
5451 1.1 is neg.w %d0 # new exp = -(shft val)
5452 1.1 is mov.w %d0,L_SCR1(%a6) # inset new exp
5453 1.1 is
5454 1.1 is cmpexp12:
5455 1.1 is mov.w 2+L_SCR1(%a6),%d0
5456 1.1 is subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp
5457 1.1 is
5458 1.1 is cmp.w %d0,L_SCR1(%a6) # is difference >= len(mantissa)+2?
5459 1.1 is bge.b quick_scale12
5460 1.1 is
5461 1.1 is mov.w L_SCR1(%a6),%d0
5462 1.1 is add.w 0x2(%sp),%d0 # scale src exponent by scale factor
5463 1.1 is mov.w FP_SCR0_EX(%a6),%d1
5464 1.1 is and.w &0x8000,%d1
5465 1.1 is or.w %d1,%d0 # concat {sgn,new exp}
5466 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new dst exponent
5467 1.1 is
5468 1.1 is mov.l (%sp)+,%d0 # return SCALE factor
5469 1.1 is rts
5470 1.1 is
5471 1.1 is quick_scale12:
5472 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # zero src exponent
5473 1.1 is bset &0x0,1+FP_SCR0_EX(%a6) # set exp = 1
5474 1.1 is
5475 1.1 is mov.l (%sp)+,%d0 # return SCALE factor
5476 1.1 is rts
5477 1.1 is
5478 1.1 is # src exp is >= dst exp; scale src to exp = 0x3fff
5479 1.1 is src_exp_ge2:
5480 1.1 is bsr.l scale_to_zero_src
5481 1.1 is mov.l %d0,-(%sp) # save scale factor
5482 1.1 is
5483 1.1 is cmpi.b DTAG(%a6),&DENORM # is dst denormalized?
5484 1.1 is bne.b cmpexp22
5485 1.1 is lea FP_SCR1(%a6),%a0
5486 1.1 is bsr.l norm # normalize the denorm; result is new exp
5487 1.1 is neg.w %d0 # new exp = -(shft val)
5488 1.1 is mov.w %d0,2+L_SCR1(%a6) # inset new exp
5489 1.1 is
5490 1.1 is cmpexp22:
5491 1.1 is mov.w L_SCR1(%a6),%d0
5492 1.1 is subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp
5493 1.1 is
5494 1.1 is cmp.w %d0,2+L_SCR1(%a6) # is difference >= len(mantissa)+2?
5495 1.1 is bge.b quick_scale22
5496 1.1 is
5497 1.1 is mov.w 2+L_SCR1(%a6),%d0
5498 1.1 is add.w 0x2(%sp),%d0 # scale dst exponent by scale factor
5499 1.1 is mov.w FP_SCR1_EX(%a6),%d1
5500 1.1 is andi.w &0x8000,%d1
5501 1.1 is or.w %d1,%d0 # concat {sgn,new exp}
5502 1.1 is mov.w %d0,FP_SCR1_EX(%a6) # insert new dst exponent
5503 1.1 is
5504 1.1 is mov.l (%sp)+,%d0 # return SCALE factor
5505 1.1 is rts
5506 1.1 is
5507 1.1 is quick_scale22:
5508 1.1 is andi.w &0x8000,FP_SCR1_EX(%a6) # zero dst exponent
5509 1.1 is bset &0x0,1+FP_SCR1_EX(%a6) # set exp = 1
5510 1.1 is
5511 1.1 is mov.l (%sp)+,%d0 # return SCALE factor
5512 1.1 is rts
5513 1.1 is
5514 1.1 is ##########################################################################
5515 1.1 is
5516 1.1 is #########################################################################
5517 1.1 is # XDEF **************************************************************** #
5518 1.1 is # scale_to_zero_src(): scale the exponent of extended precision #
5519 1.1 is # value at FP_SCR0(a6). #
5520 1.1 is # #
5521 1.1 is # XREF **************************************************************** #
5522 1.1 is # norm() - normalize the mantissa if the operand was a DENORM #
5523 1.1 is # #
5524 1.1 is # INPUT *************************************************************** #
5525 1.1 is # FP_SCR0(a6) = extended precision operand to be scaled #
5526 1.1 is # #
5527 1.1 is # OUTPUT ************************************************************** #
5528 1.1 is # FP_SCR0(a6) = scaled extended precision operand #
5529 1.1 is # d0 = scale value #
5530 1.1 is # #
5531 1.1 is # ALGORITHM *********************************************************** #
5532 1.1 is # Set the exponent of the input operand to 0x3fff. Save the value #
5533 1.1 is # of the difference between the original and new exponent. Then, #
5534 1.1 is # normalize the operand if it was a DENORM. Add this normalization #
5535 1.1 is # value to the previous value. Return the result. #
5536 1.1 is # #
5537 1.1 is #########################################################################
5538 1.1 is
5539 1.1 is global scale_to_zero_src
5540 1.1 is scale_to_zero_src:
5541 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp}
5542 1.1 is mov.w %d1,%d0 # make a copy
5543 1.1 is
5544 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent
5545 1.1 is
5546 1.1 is andi.w &0x8000,%d0 # extract operand's sgn
5547 1.1 is or.w &0x3fff,%d0 # insert new operand's exponent(=0)
5548 1.1 is
5549 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert biased exponent
5550 1.1 is
5551 1.1 is cmpi.b STAG(%a6),&DENORM # is operand normalized?
5552 1.1 is beq.b stzs_denorm # normalize the DENORM
5553 1.1 is
5554 1.1 is stzs_norm:
5555 1.1 is mov.l &0x3fff,%d0
5556 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp)
5557 1.1 is
5558 1.1 is rts
5559 1.1 is
5560 1.1 is stzs_denorm:
5561 1.1 is lea FP_SCR0(%a6),%a0 # pass ptr to src op
5562 1.1 is bsr.l norm # normalize denorm
5563 1.1 is neg.l %d0 # new exponent = -(shft val)
5564 1.1 is mov.l %d0,%d1 # prepare for op_norm call
5565 1.1 is bra.b stzs_norm # finish scaling
5566 1.1 is
5567 1.1 is ###
5568 1.1 is
5569 1.1 is #########################################################################
5570 1.1 is # XDEF **************************************************************** #
5571 1.1 is # scale_sqrt(): scale the input operand exponent so a subsequent #
5572 1.1 is # fsqrt operation won't take an exception. #
5573 1.1 is # #
5574 1.1 is # XREF **************************************************************** #
5575 1.1 is # norm() - normalize the mantissa if the operand was a DENORM #
5576 1.1 is # #
5577 1.1 is # INPUT *************************************************************** #
5578 1.1 is # FP_SCR0(a6) = extended precision operand to be scaled #
5579 1.1 is # #
5580 1.1 is # OUTPUT ************************************************************** #
5581 1.1 is # FP_SCR0(a6) = scaled extended precision operand #
5582 1.1 is # d0 = scale value #
5583 1.1 is # #
5584 1.1 is # ALGORITHM *********************************************************** #
5585 1.1 is # If the input operand is a DENORM, normalize it. #
5586 1.1 is # If the exponent of the input operand is even, set the exponent #
5587 1.1 is # to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the #
5588 1.1 is # exponent of the input operand is off, set the exponent to ox3fff and #
5589 1.1 is # return a scale factor of "(exp-0x3fff)/2". #
5590 1.1 is # #
5591 1.1 is #########################################################################
5592 1.1 is
5593 1.1 is global scale_sqrt
5594 1.1 is scale_sqrt:
5595 1.1 is cmpi.b STAG(%a6),&DENORM # is operand normalized?
5596 1.1 is beq.b ss_denorm # normalize the DENORM
5597 1.1 is
5598 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp}
5599 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent
5600 1.1 is
5601 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn
5602 1.1 is
5603 1.1 is btst &0x0,%d1 # is exp even or odd?
5604 1.1 is beq.b ss_norm_even
5605 1.1 is
5606 1.1 is ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5607 1.1 is
5608 1.1 is mov.l &0x3fff,%d0
5609 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp)
5610 1.1 is asr.l &0x1,%d0 # divide scale factor by 2
5611 1.1 is rts
5612 1.1 is
5613 1.1 is ss_norm_even:
5614 1.1 is ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5615 1.1 is
5616 1.1 is mov.l &0x3ffe,%d0
5617 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp)
5618 1.1 is asr.l &0x1,%d0 # divide scale factor by 2
5619 1.1 is rts
5620 1.1 is
5621 1.1 is ss_denorm:
5622 1.1 is lea FP_SCR0(%a6),%a0 # pass ptr to src op
5623 1.1 is bsr.l norm # normalize denorm
5624 1.1 is
5625 1.1 is btst &0x0,%d0 # is exp even or odd?
5626 1.1 is beq.b ss_denorm_even
5627 1.1 is
5628 1.1 is ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5629 1.1 is
5630 1.1 is add.l &0x3fff,%d0
5631 1.1 is asr.l &0x1,%d0 # divide scale factor by 2
5632 1.1 is rts
5633 1.1 is
5634 1.1 is ss_denorm_even:
5635 1.1 is ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5636 1.1 is
5637 1.1 is add.l &0x3ffe,%d0
5638 1.1 is asr.l &0x1,%d0 # divide scale factor by 2
5639 1.1 is rts
5640 1.1 is
5641 1.1 is ###
5642 1.1 is
5643 1.1 is #########################################################################
5644 1.1 is # XDEF **************************************************************** #
5645 1.1 is # scale_to_zero_dst(): scale the exponent of extended precision #
5646 1.1 is # value at FP_SCR1(a6). #
5647 1.1 is # #
5648 1.1 is # XREF **************************************************************** #
5649 1.1 is # norm() - normalize the mantissa if the operand was a DENORM #
5650 1.1 is # #
5651 1.1 is # INPUT *************************************************************** #
5652 1.1 is # FP_SCR1(a6) = extended precision operand to be scaled #
5653 1.1 is # #
5654 1.1 is # OUTPUT ************************************************************** #
5655 1.1 is # FP_SCR1(a6) = scaled extended precision operand #
5656 1.1 is # d0 = scale value #
5657 1.1 is # #
5658 1.1 is # ALGORITHM *********************************************************** #
5659 1.1 is # Set the exponent of the input operand to 0x3fff. Save the value #
5660 1.1 is # of the difference between the original and new exponent. Then, #
5661 1.1 is # normalize the operand if it was a DENORM. Add this normalization #
5662 1.1 is # value to the previous value. Return the result. #
5663 1.1 is # #
5664 1.1 is #########################################################################
5665 1.1 is
5666 1.1 is global scale_to_zero_dst
5667 1.1 is scale_to_zero_dst:
5668 1.1 is mov.w FP_SCR1_EX(%a6),%d1 # extract operand's {sgn,exp}
5669 1.1 is mov.w %d1,%d0 # make a copy
5670 1.1 is
5671 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent
5672 1.1 is
5673 1.1 is andi.w &0x8000,%d0 # extract operand's sgn
5674 1.1 is or.w &0x3fff,%d0 # insert new operand's exponent(=0)
5675 1.1 is
5676 1.1 is mov.w %d0,FP_SCR1_EX(%a6) # insert biased exponent
5677 1.1 is
5678 1.1 is cmpi.b DTAG(%a6),&DENORM # is operand normalized?
5679 1.1 is beq.b stzd_denorm # normalize the DENORM
5680 1.1 is
5681 1.1 is stzd_norm:
5682 1.1 is mov.l &0x3fff,%d0
5683 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp)
5684 1.1 is rts
5685 1.1 is
5686 1.1 is stzd_denorm:
5687 1.1 is lea FP_SCR1(%a6),%a0 # pass ptr to dst op
5688 1.1 is bsr.l norm # normalize denorm
5689 1.1 is neg.l %d0 # new exponent = -(shft val)
5690 1.1 is mov.l %d0,%d1 # prepare for op_norm call
5691 1.1 is bra.b stzd_norm # finish scaling
5692 1.1 is
5693 1.1 is ##########################################################################
5694 1.1 is
5695 1.1 is #########################################################################
5696 1.1 is # XDEF **************************************************************** #
5697 1.1 is # res_qnan(): return default result w/ QNAN operand for dyadic #
5698 1.1 is # res_snan(): return default result w/ SNAN operand for dyadic #
5699 1.1 is # res_qnan_1op(): return dflt result w/ QNAN operand for monadic #
5700 1.1 is # res_snan_1op(): return dflt result w/ SNAN operand for monadic #
5701 1.1 is # #
5702 1.1 is # XREF **************************************************************** #
5703 1.1 is # None #
5704 1.1 is # #
5705 1.1 is # INPUT *************************************************************** #
5706 1.1 is # FP_SRC(a6) = pointer to extended precision src operand #
5707 1.1 is # FP_DST(a6) = pointer to extended precision dst operand #
5708 1.1 is # #
5709 1.1 is # OUTPUT ************************************************************** #
5710 1.1 is # fp0 = default result #
5711 1.1 is # #
5712 1.1 is # ALGORITHM *********************************************************** #
5713 1.1 is # If either operand (but not both operands) of an operation is a #
5714 1.1 is # nonsignalling NAN, then that NAN is returned as the result. If both #
5715 1.1 is # operands are nonsignalling NANs, then the destination operand #
5716 1.1 is # nonsignalling NAN is returned as the result. #
5717 1.1 is # If either operand to an operation is a signalling NAN (SNAN), #
5718 1.1 is # then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap #
5719 1.1 is # enable bit is set in the FPCR, then the trap is taken and the #
5720 1.1 is # destination is not modified. If the SNAN trap enable bit is not set, #
5721 1.1 is # then the SNAN is converted to a nonsignalling NAN (by setting the #
5722 1.1 is # SNAN bit in the operand to one), and the operation continues as #
5723 1.1 is # described in the preceding paragraph, for nonsignalling NANs. #
5724 1.1 is # Make sure the appropriate FPSR bits are set before exiting. #
5725 1.1 is # #
5726 1.1 is #########################################################################
5727 1.1 is
5728 1.1 is global res_qnan
5729 1.1 is global res_snan
5730 1.1 is res_qnan:
5731 1.1 is res_snan:
5732 1.1 is cmp.b DTAG(%a6), &SNAN # is the dst an SNAN?
5733 1.1 is beq.b dst_snan2
5734 1.1 is cmp.b DTAG(%a6), &QNAN # is the dst a QNAN?
5735 1.1 is beq.b dst_qnan2
5736 1.1 is src_nan:
5737 1.1 is cmp.b STAG(%a6), &QNAN
5738 1.1 is beq.b src_qnan2
5739 1.1 is global res_snan_1op
5740 1.1 is res_snan_1op:
5741 1.1 is src_snan2:
5742 1.1 is bset &0x6, FP_SRC_HI(%a6) # set SNAN bit
5743 1.1 is or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5744 1.1 is lea FP_SRC(%a6), %a0
5745 1.1 is bra.b nan_comp
5746 1.1 is global res_qnan_1op
5747 1.1 is res_qnan_1op:
5748 1.1 is src_qnan2:
5749 1.1 is or.l &nan_mask, USER_FPSR(%a6)
5750 1.1 is lea FP_SRC(%a6), %a0
5751 1.1 is bra.b nan_comp
5752 1.1 is dst_snan2:
5753 1.1 is or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5754 1.1 is bset &0x6, FP_DST_HI(%a6) # set SNAN bit
5755 1.1 is lea FP_DST(%a6), %a0
5756 1.1 is bra.b nan_comp
5757 1.1 is dst_qnan2:
5758 1.1 is lea FP_DST(%a6), %a0
5759 1.1 is cmp.b STAG(%a6), &SNAN
5760 1.1 is bne nan_done
5761 1.1 is or.l &aiop_mask+snan_mask, USER_FPSR(%a6)
5762 1.1 is nan_done:
5763 1.1 is or.l &nan_mask, USER_FPSR(%a6)
5764 1.1 is nan_comp:
5765 1.1 is btst &0x7, FTEMP_EX(%a0) # is NAN neg?
5766 1.1 is beq.b nan_not_neg
5767 1.1 is or.l &neg_mask, USER_FPSR(%a6)
5768 1.1 is nan_not_neg:
5769 1.1 is fmovm.x (%a0), &0x80
5770 1.1 is rts
5771 1.1 is
5772 1.1 is #########################################################################
5773 1.1 is # XDEF **************************************************************** #
5774 1.1 is # res_operr(): return default result during operand error #
5775 1.1 is # #
5776 1.1 is # XREF **************************************************************** #
5777 1.1 is # None #
5778 1.1 is # #
5779 1.1 is # INPUT *************************************************************** #
5780 1.1 is # None #
5781 1.1 is # #
5782 1.1 is # OUTPUT ************************************************************** #
5783 1.1 is # fp0 = default operand error result #
5784 1.1 is # #
5785 1.1 is # ALGORITHM *********************************************************** #
5786 1.1 is # An nonsignalling NAN is returned as the default result when #
5787 1.1 is # an operand error occurs for the following cases: #
5788 1.1 is # #
5789 1.1 is # Multiply: (Infinity x Zero) #
5790 1.1 is # Divide : (Zero / Zero) || (Infinity / Infinity) #
5791 1.1 is # #
5792 1.1 is #########################################################################
5793 1.1 is
5794 1.1 is global res_operr
5795 1.1 is res_operr:
5796 1.1 is or.l &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6)
5797 1.1 is fmovm.x nan_return(%pc), &0x80
5798 1.1 is rts
5799 1.1 is
5800 1.1 is nan_return:
5801 1.1 is long 0x7fff0000, 0xffffffff, 0xffffffff
5802 1.1 is
5803 1.1 is #########################################################################
5804 1.1 is # XDEF **************************************************************** #
5805 1.1 is # _denorm(): denormalize an intermediate result #
5806 1.1 is # #
5807 1.1 is # XREF **************************************************************** #
5808 1.1 is # None #
5809 1.1 is # #
5810 1.1 is # INPUT *************************************************************** #
5811 1.1 is # a0 = points to the operand to be denormalized #
5812 1.1 is # (in the internal extended format) #
5813 1.1 is # #
5814 1.1 is # d0 = rounding precision #
5815 1.1 is # #
5816 1.1 is # OUTPUT ************************************************************** #
5817 1.1 is # a0 = pointer to the denormalized result #
5818 1.1 is # (in the internal extended format) #
5819 1.1 is # #
5820 1.1 is # d0 = guard,round,sticky #
5821 1.1 is # #
5822 1.1 is # ALGORITHM *********************************************************** #
5823 1.1 is # According to the exponent underflow threshold for the given #
5824 1.1 is # precision, shift the mantissa bits to the right in order raise the #
5825 1.1 is # exponent of the operand to the threshold value. While shifting the #
5826 1.1 is # mantissa bits right, maintain the value of the guard, round, and #
5827 1.1 is # sticky bits. #
5828 1.1 is # other notes: #
5829 1.1 is # (1) _denorm() is called by the underflow routines #
5830 1.1 is # (2) _denorm() does NOT affect the status register #
5831 1.1 is # #
5832 1.1 is #########################################################################
5833 1.1 is
5834 1.1 is #
5835 1.1 is # table of exponent threshold values for each precision
5836 1.1 is #
5837 1.1 is tbl_thresh:
5838 1.1 is short 0x0
5839 1.1 is short sgl_thresh
5840 1.1 is short dbl_thresh
5841 1.1 is
5842 1.1 is global _denorm
5843 1.1 is _denorm:
5844 1.1 is #
5845 1.1 is # Load the exponent threshold for the precision selected and check
5846 1.1 is # to see if (threshold - exponent) is > 65 in which case we can
5847 1.1 is # simply calculate the sticky bit and zero the mantissa. otherwise
5848 1.1 is # we have to call the denormalization routine.
5849 1.1 is #
5850 1.1 is lsr.b &0x2, %d0 # shift prec to lo bits
5851 1.1 is mov.w (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
5852 1.1 is mov.w %d1, %d0 # copy d1 into d0
5853 1.1 is sub.w FTEMP_EX(%a0), %d0 # diff = threshold - exp
5854 1.1 is cmpi.w %d0, &66 # is diff > 65? (mant + g,r bits)
5855 1.1 is bpl.b denorm_set_stky # yes; just calc sticky
5856 1.1 is
5857 1.1 is clr.l %d0 # clear g,r,s
5858 1.1 is btst &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
5859 1.1 is beq.b denorm_call # no; don't change anything
5860 1.1 is bset &29, %d0 # yes; set sticky bit
5861 1.1 is
5862 1.1 is denorm_call:
5863 1.1 is bsr.l dnrm_lp # denormalize the number
5864 1.1 is rts
5865 1.1 is
5866 1.1 is #
5867 1.1 is # all bit would have been shifted off during the denorm so simply
5868 1.1 is # calculate if the sticky should be set and clear the entire mantissa.
5869 1.1 is #
5870 1.1 is denorm_set_stky:
5871 1.1 is mov.l &0x20000000, %d0 # set sticky bit in return value
5872 1.1 is mov.w %d1, FTEMP_EX(%a0) # load exp with threshold
5873 1.1 is clr.l FTEMP_HI(%a0) # set d1 = 0 (ms mantissa)
5874 1.1 is clr.l FTEMP_LO(%a0) # set d2 = 0 (ms mantissa)
5875 1.1 is rts
5876 1.1 is
5877 1.1 is # #
5878 1.1 is # dnrm_lp(): normalize exponent/mantissa to specified threshhold #
5879 1.1 is # #
5880 1.1 is # INPUT: #
5881 1.1 is # %a0 : points to the operand to be denormalized #
5882 1.1 is # %d0{31:29} : initial guard,round,sticky #
5883 1.1 is # %d1{15:0} : denormalization threshold #
5884 1.1 is # OUTPUT: #
5885 1.1 is # %a0 : points to the denormalized operand #
5886 1.1 is # %d0{31:29} : final guard,round,sticky #
5887 1.1 is # #
5888 1.1 is
5889 1.1 is # *** Local Equates *** #
5890 1.1 is set GRS, L_SCR2 # g,r,s temp storage
5891 1.1 is set FTEMP_LO2, L_SCR1 # FTEMP_LO copy
5892 1.1 is
5893 1.1 is global dnrm_lp
5894 1.1 is dnrm_lp:
5895 1.1 is
5896 1.1 is #
5897 1.1 is # make a copy of FTEMP_LO and place the g,r,s bits directly after it
5898 1.1 is # in memory so as to make the bitfield extraction for denormalization easier.
5899 1.1 is #
5900 1.1 is mov.l FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
5901 1.1 is mov.l %d0, GRS(%a6) # place g,r,s after it
5902 1.1 is
5903 1.1 is #
5904 1.1 is # check to see how much less than the underflow threshold the operand
5905 1.1 is # exponent is.
5906 1.1 is #
5907 1.1 is mov.l %d1, %d0 # copy the denorm threshold
5908 1.1 is sub.w FTEMP_EX(%a0), %d1 # d1 = threshold - uns exponent
5909 1.1 is ble.b dnrm_no_lp # d1 <= 0
5910 1.1 is cmpi.w %d1, &0x20 # is ( 0 <= d1 < 32) ?
5911 1.1 is blt.b case_1 # yes
5912 1.1 is cmpi.w %d1, &0x40 # is (32 <= d1 < 64) ?
5913 1.1 is blt.b case_2 # yes
5914 1.1 is bra.w case_3 # (d1 >= 64)
5915 1.1 is
5916 1.1 is #
5917 1.1 is # No normalization necessary
5918 1.1 is #
5919 1.1 is dnrm_no_lp:
5920 1.1 is mov.l GRS(%a6), %d0 # restore original g,r,s
5921 1.1 is rts
5922 1.1 is
5923 1.1 is #
5924 1.1 is # case (0<d1<32)
5925 1.1 is #
5926 1.1 is # %d0 = denorm threshold
5927 1.1 is # %d1 = "n" = amt to shift
5928 1.1 is #
5929 1.1 is # ---------------------------------------------------------
5930 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000|
5931 1.1 is # ---------------------------------------------------------
5932 1.1 is # <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5933 1.1 is # \ \ \ \
5934 1.1 is # \ \ \ \
5935 1.1 is # \ \ \ \
5936 1.1 is # \ \ \ \
5937 1.1 is # \ \ \ \
5938 1.1 is # \ \ \ \
5939 1.1 is # \ \ \ \
5940 1.1 is # \ \ \ \
5941 1.1 is # <-(n)-><-(32 - n)-><------(32)-------><------(32)------->
5942 1.1 is # ---------------------------------------------------------
5943 1.1 is # |0.....0| NEW_HI | NEW_FTEMP_LO |grs |
5944 1.1 is # ---------------------------------------------------------
5945 1.1 is #
5946 1.1 is case_1:
5947 1.1 is mov.l %d2, -(%sp) # create temp storage
5948 1.1 is
5949 1.1 is mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold
5950 1.1 is mov.l &32, %d0
5951 1.1 is sub.w %d1, %d0 # %d0 = 32 - %d1
5952 1.1 is
5953 1.1 is cmpi.w %d1, &29 # is shft amt >= 29
5954 1.1 is blt.b case1_extract # no; no fix needed
5955 1.1 is mov.b GRS(%a6), %d2
5956 1.1 is or.b %d2, 3+FTEMP_LO2(%a6)
5957 1.1 is
5958 1.1 is case1_extract:
5959 1.1 is bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
5960 1.1 is bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
5961 1.1 is bfextu FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S
5962 1.1 is
5963 1.1 is mov.l %d2, FTEMP_HI(%a0) # store new FTEMP_HI
5964 1.1 is mov.l %d1, FTEMP_LO(%a0) # store new FTEMP_LO
5965 1.1 is
5966 1.1 is bftst %d0{&2:&30} # were bits shifted off?
5967 1.1 is beq.b case1_sticky_clear # no; go finish
5968 1.1 is bset &rnd_stky_bit, %d0 # yes; set sticky bit
5969 1.1 is
5970 1.1 is case1_sticky_clear:
5971 1.1 is and.l &0xe0000000, %d0 # clear all but G,R,S
5972 1.1 is mov.l (%sp)+, %d2 # restore temp register
5973 1.1 is rts
5974 1.1 is
5975 1.1 is #
5976 1.1 is # case (32<=d1<64)
5977 1.1 is #
5978 1.1 is # %d0 = denorm threshold
5979 1.1 is # %d1 = "n" = amt to shift
5980 1.1 is #
5981 1.1 is # ---------------------------------------------------------
5982 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000|
5983 1.1 is # ---------------------------------------------------------
5984 1.1 is # <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5985 1.1 is # \ \ \
5986 1.1 is # \ \ \
5987 1.1 is # \ \ -------------------
5988 1.1 is # \ -------------------- \
5989 1.1 is # ------------------- \ \
5990 1.1 is # \ \ \
5991 1.1 is # \ \ \
5992 1.1 is # \ \ \
5993 1.1 is # <-------(32)------><-(n)-><-(32 - n)-><------(32)------->
5994 1.1 is # ---------------------------------------------------------
5995 1.1 is # |0...............0|0....0| NEW_LO |grs |
5996 1.1 is # ---------------------------------------------------------
5997 1.1 is #
5998 1.1 is case_2:
5999 1.1 is mov.l %d2, -(%sp) # create temp storage
6000 1.1 is
6001 1.1 is mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold
6002 1.1 is subi.w &0x20, %d1 # %d1 now between 0 and 32
6003 1.1 is mov.l &0x20, %d0
6004 1.1 is sub.w %d1, %d0 # %d0 = 32 - %d1
6005 1.1 is
6006 1.1 is # subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
6007 1.1 is # the number of bits to check for the sticky detect.
6008 1.1 is # it only plays a role in shift amounts of 61-63.
6009 1.1 is mov.b GRS(%a6), %d2
6010 1.1 is or.b %d2, 3+FTEMP_LO2(%a6)
6011 1.1 is
6012 1.1 is bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
6013 1.1 is bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S
6014 1.1 is
6015 1.1 is bftst %d1{&2:&30} # were any bits shifted off?
6016 1.1 is bne.b case2_set_sticky # yes; set sticky bit
6017 1.1 is bftst FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off?
6018 1.1 is bne.b case2_set_sticky # yes; set sticky bit
6019 1.1 is
6020 1.1 is mov.l %d1, %d0 # move new G,R,S to %d0
6021 1.1 is bra.b case2_end
6022 1.1 is
6023 1.1 is case2_set_sticky:
6024 1.1 is mov.l %d1, %d0 # move new G,R,S to %d0
6025 1.1 is bset &rnd_stky_bit, %d0 # set sticky bit
6026 1.1 is
6027 1.1 is case2_end:
6028 1.1 is clr.l FTEMP_HI(%a0) # store FTEMP_HI = 0
6029 1.1 is mov.l %d2, FTEMP_LO(%a0) # store FTEMP_LO
6030 1.1 is and.l &0xe0000000, %d0 # clear all but G,R,S
6031 1.1 is
6032 1.1 is mov.l (%sp)+,%d2 # restore temp register
6033 1.1 is rts
6034 1.1 is
6035 1.1 is #
6036 1.1 is # case (d1>=64)
6037 1.1 is #
6038 1.1 is # %d0 = denorm threshold
6039 1.1 is # %d1 = amt to shift
6040 1.1 is #
6041 1.1 is case_3:
6042 1.1 is mov.w %d0, FTEMP_EX(%a0) # insert denorm threshold
6043 1.1 is
6044 1.1 is cmpi.w %d1, &65 # is shift amt > 65?
6045 1.1 is blt.b case3_64 # no; it's == 64
6046 1.1 is beq.b case3_65 # no; it's == 65
6047 1.1 is
6048 1.1 is #
6049 1.1 is # case (d1>65)
6050 1.1 is #
6051 1.1 is # Shift value is > 65 and out of range. All bits are shifted off.
6052 1.1 is # Return a zero mantissa with the sticky bit set
6053 1.1 is #
6054 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6055 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6056 1.1 is mov.l &0x20000000, %d0 # set sticky bit
6057 1.1 is rts
6058 1.1 is
6059 1.1 is #
6060 1.1 is # case (d1 == 64)
6061 1.1 is #
6062 1.1 is # ---------------------------------------------------------
6063 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000|
6064 1.1 is # ---------------------------------------------------------
6065 1.1 is # <-------(32)------>
6066 1.1 is # \ \
6067 1.1 is # \ \
6068 1.1 is # \ \
6069 1.1 is # \ ------------------------------
6070 1.1 is # ------------------------------- \
6071 1.1 is # \ \
6072 1.1 is # \ \
6073 1.1 is # \ \
6074 1.1 is # <-------(32)------>
6075 1.1 is # ---------------------------------------------------------
6076 1.1 is # |0...............0|0................0|grs |
6077 1.1 is # ---------------------------------------------------------
6078 1.1 is #
6079 1.1 is case3_64:
6080 1.1 is mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa)
6081 1.1 is mov.l %d0, %d1 # make a copy
6082 1.1 is and.l &0xc0000000, %d0 # extract G,R
6083 1.1 is and.l &0x3fffffff, %d1 # extract other bits
6084 1.1 is
6085 1.1 is bra.b case3_complete
6086 1.1 is
6087 1.1 is #
6088 1.1 is # case (d1 == 65)
6089 1.1 is #
6090 1.1 is # ---------------------------------------------------------
6091 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000|
6092 1.1 is # ---------------------------------------------------------
6093 1.1 is # <-------(32)------>
6094 1.1 is # \ \
6095 1.1 is # \ \
6096 1.1 is # \ \
6097 1.1 is # \ ------------------------------
6098 1.1 is # -------------------------------- \
6099 1.1 is # \ \
6100 1.1 is # \ \
6101 1.1 is # \ \
6102 1.1 is # <-------(31)----->
6103 1.1 is # ---------------------------------------------------------
6104 1.1 is # |0...............0|0................0|0rs |
6105 1.1 is # ---------------------------------------------------------
6106 1.1 is #
6107 1.1 is case3_65:
6108 1.1 is mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa)
6109 1.1 is and.l &0x80000000, %d0 # extract R bit
6110 1.1 is lsr.l &0x1, %d0 # shift high bit into R bit
6111 1.1 is and.l &0x7fffffff, %d1 # extract other bits
6112 1.1 is
6113 1.1 is case3_complete:
6114 1.1 is # last operation done was an "and" of the bits shifted off so the condition
6115 1.1 is # codes are already set so branch accordingly.
6116 1.1 is bne.b case3_set_sticky # yes; go set new sticky
6117 1.1 is tst.l FTEMP_LO(%a0) # were any bits shifted off?
6118 1.1 is bne.b case3_set_sticky # yes; go set new sticky
6119 1.1 is tst.b GRS(%a6) # were any bits shifted off?
6120 1.1 is bne.b case3_set_sticky # yes; go set new sticky
6121 1.1 is
6122 1.1 is #
6123 1.1 is # no bits were shifted off so don't set the sticky bit.
6124 1.1 is # the guard and
6125 1.1 is # the entire mantissa is zero.
6126 1.1 is #
6127 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6128 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6129 1.1 is rts
6130 1.1 is
6131 1.1 is #
6132 1.1 is # some bits were shifted off so set the sticky bit.
6133 1.1 is # the entire mantissa is zero.
6134 1.1 is #
6135 1.1 is case3_set_sticky:
6136 1.1 is bset &rnd_stky_bit,%d0 # set new sticky bit
6137 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6138 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6139 1.1 is rts
6140 1.1 is
6141 1.1 is #########################################################################
6142 1.1 is # XDEF **************************************************************** #
6143 1.1 is # _round(): round result according to precision/mode #
6144 1.1 is # #
6145 1.1 is # XREF **************************************************************** #
6146 1.1 is # None #
6147 1.1 is # #
6148 1.1 is # INPUT *************************************************************** #
6149 1.1 is # a0 = ptr to input operand in internal extended format #
6150 1.1 is # d1(hi) = contains rounding precision: #
6151 1.1 is # ext = $0000xxxx #
6152 1.1 is # sgl = $0004xxxx #
6153 1.1 is # dbl = $0008xxxx #
6154 1.1 is # d1(lo) = contains rounding mode: #
6155 1.1 is # RN = $xxxx0000 #
6156 1.1 is # RZ = $xxxx0001 #
6157 1.1 is # RM = $xxxx0002 #
6158 1.1 is # RP = $xxxx0003 #
6159 1.1 is # d0{31:29} = contains the g,r,s bits (extended) #
6160 1.1 is # #
6161 1.1 is # OUTPUT ************************************************************** #
6162 1.1 is # a0 = pointer to rounded result #
6163 1.1 is # #
6164 1.1 is # ALGORITHM *********************************************************** #
6165 1.1 is # On return the value pointed to by a0 is correctly rounded, #
6166 1.1 is # a0 is preserved and the g-r-s bits in d0 are cleared. #
6167 1.1 is # The result is not typed - the tag field is invalid. The #
6168 1.1 is # result is still in the internal extended format. #
6169 1.1 is # #
6170 1.1 is # The INEX bit of USER_FPSR will be set if the rounded result was #
6171 1.1 is # inexact (i.e. if any of the g-r-s bits were set). #
6172 1.1 is # #
6173 1.1 is #########################################################################
6174 1.1 is
6175 1.1 is global _round
6176 1.1 is _round:
6177 1.1 is #
6178 1.1 is # ext_grs() looks at the rounding precision and sets the appropriate
6179 1.1 is # G,R,S bits.
6180 1.1 is # If (G,R,S == 0) then result is exact and round is done, else set
6181 1.1 is # the inex flag in status reg and continue.
6182 1.1 is #
6183 1.1 is bsr.l ext_grs # extract G,R,S
6184 1.1 is
6185 1.1 is tst.l %d0 # are G,R,S zero?
6186 1.1 is beq.w truncate # yes; round is complete
6187 1.1 is
6188 1.1 is or.w &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex
6189 1.1 is
6190 1.1 is #
6191 1.1 is # Use rounding mode as an index into a jump table for these modes.
6192 1.1 is # All of the following assumes grs != 0.
6193 1.1 is #
6194 1.1 is mov.w (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
6195 1.1 is jmp (tbl_mode.b,%pc,%a1) # jmp to rnd mode handler
6196 1.1 is
6197 1.1 is tbl_mode:
6198 1.1 is short rnd_near - tbl_mode
6199 1.1 is short truncate - tbl_mode # RZ always truncates
6200 1.1 is short rnd_mnus - tbl_mode
6201 1.1 is short rnd_plus - tbl_mode
6202 1.1 is
6203 1.1 is #################################################################
6204 1.1 is # ROUND PLUS INFINITY #
6205 1.1 is # #
6206 1.1 is # If sign of fp number = 0 (positive), then add 1 to l. #
6207 1.1 is #################################################################
6208 1.1 is rnd_plus:
6209 1.1 is tst.b FTEMP_SGN(%a0) # check for sign
6210 1.1 is bmi.w truncate # if positive then truncate
6211 1.1 is
6212 1.1 is mov.l &0xffffffff, %d0 # force g,r,s to be all f's
6213 1.1 is swap %d1 # set up d1 for round prec.
6214 1.1 is
6215 1.1 is cmpi.b %d1, &s_mode # is prec = sgl?
6216 1.1 is beq.w add_sgl # yes
6217 1.1 is bgt.w add_dbl # no; it's dbl
6218 1.1 is bra.w add_ext # no; it's ext
6219 1.1 is
6220 1.1 is #################################################################
6221 1.1 is # ROUND MINUS INFINITY #
6222 1.1 is # #
6223 1.1 is # If sign of fp number = 1 (negative), then add 1 to l. #
6224 1.1 is #################################################################
6225 1.1 is rnd_mnus:
6226 1.1 is tst.b FTEMP_SGN(%a0) # check for sign
6227 1.1 is bpl.w truncate # if negative then truncate
6228 1.1 is
6229 1.1 is mov.l &0xffffffff, %d0 # force g,r,s to be all f's
6230 1.1 is swap %d1 # set up d1 for round prec.
6231 1.1 is
6232 1.1 is cmpi.b %d1, &s_mode # is prec = sgl?
6233 1.1 is beq.w add_sgl # yes
6234 1.1 is bgt.w add_dbl # no; it's dbl
6235 1.1 is bra.w add_ext # no; it's ext
6236 1.1 is
6237 1.1 is #################################################################
6238 1.1 is # ROUND NEAREST #
6239 1.1 is # #
6240 1.1 is # If (g=1), then add 1 to l and if (r=s=0), then clear l #
6241 1.1 is # Note that this will round to even in case of a tie. #
6242 1.1 is #################################################################
6243 1.1 is rnd_near:
6244 1.1 is asl.l &0x1, %d0 # shift g-bit to c-bit
6245 1.1 is bcc.w truncate # if (g=1) then
6246 1.1 is
6247 1.1 is swap %d1 # set up d1 for round prec.
6248 1.1 is
6249 1.1 is cmpi.b %d1, &s_mode # is prec = sgl?
6250 1.1 is beq.w add_sgl # yes
6251 1.1 is bgt.w add_dbl # no; it's dbl
6252 1.1 is bra.w add_ext # no; it's ext
6253 1.1 is
6254 1.1 is # *** LOCAL EQUATES ***
6255 1.1 is set ad_1_sgl, 0x00000100 # constant to add 1 to l-bit in sgl prec
6256 1.1 is set ad_1_dbl, 0x00000800 # constant to add 1 to l-bit in dbl prec
6257 1.1 is
6258 1.1 is #########################
6259 1.1 is # ADD SINGLE #
6260 1.1 is #########################
6261 1.1 is add_sgl:
6262 1.1 is add.l &ad_1_sgl, FTEMP_HI(%a0)
6263 1.1 is bcc.b scc_clr # no mantissa overflow
6264 1.1 is roxr.w FTEMP_HI(%a0) # shift v-bit back in
6265 1.1 is roxr.w FTEMP_HI+2(%a0) # shift v-bit back in
6266 1.1 is add.w &0x1, FTEMP_EX(%a0) # and incr exponent
6267 1.1 is scc_clr:
6268 1.1 is tst.l %d0 # test for rs = 0
6269 1.1 is bne.b sgl_done
6270 1.1 is and.w &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
6271 1.1 is sgl_done:
6272 1.1 is and.l &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
6273 1.1 is clr.l FTEMP_LO(%a0) # clear d2
6274 1.1 is rts
6275 1.1 is
6276 1.1 is #########################
6277 1.1 is # ADD EXTENDED #
6278 1.1 is #########################
6279 1.1 is add_ext:
6280 1.1 is addq.l &1,FTEMP_LO(%a0) # add 1 to l-bit
6281 1.1 is bcc.b xcc_clr # test for carry out
6282 1.1 is addq.l &1,FTEMP_HI(%a0) # propogate carry
6283 1.1 is bcc.b xcc_clr
6284 1.1 is roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit
6285 1.1 is roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit
6286 1.1 is roxr.w FTEMP_LO(%a0)
6287 1.1 is roxr.w FTEMP_LO+2(%a0)
6288 1.1 is add.w &0x1,FTEMP_EX(%a0) # and inc exp
6289 1.1 is xcc_clr:
6290 1.1 is tst.l %d0 # test rs = 0
6291 1.1 is bne.b add_ext_done
6292 1.1 is and.b &0xfe,FTEMP_LO+3(%a0) # clear the l bit
6293 1.1 is add_ext_done:
6294 1.1 is rts
6295 1.1 is
6296 1.1 is #########################
6297 1.1 is # ADD DOUBLE #
6298 1.1 is #########################
6299 1.1 is add_dbl:
6300 1.1 is add.l &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
6301 1.1 is bcc.b dcc_clr # no carry
6302 1.1 is addq.l &0x1, FTEMP_HI(%a0) # propogate carry
6303 1.1 is bcc.b dcc_clr # no carry
6304 1.1 is
6305 1.1 is roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit
6306 1.1 is roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit
6307 1.1 is roxr.w FTEMP_LO(%a0)
6308 1.1 is roxr.w FTEMP_LO+2(%a0)
6309 1.1 is addq.w &0x1, FTEMP_EX(%a0) # incr exponent
6310 1.1 is dcc_clr:
6311 1.1 is tst.l %d0 # test for rs = 0
6312 1.1 is bne.b dbl_done
6313 1.1 is and.w &0xf000, FTEMP_LO+2(%a0) # clear the l-bit
6314 1.1 is
6315 1.1 is dbl_done:
6316 1.1 is and.l &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
6317 1.1 is rts
6318 1.1 is
6319 1.1 is ###########################
6320 1.1 is # Truncate all other bits #
6321 1.1 is ###########################
6322 1.1 is truncate:
6323 1.1 is swap %d1 # select rnd prec
6324 1.1 is
6325 1.1 is cmpi.b %d1, &s_mode # is prec sgl?
6326 1.1 is beq.w sgl_done # yes
6327 1.1 is bgt.b dbl_done # no; it's dbl
6328 1.1 is rts # no; it's ext
6329 1.1 is
6330 1.1 is
6331 1.1 is #
6332 1.1 is # ext_grs(): extract guard, round and sticky bits according to
6333 1.1 is # rounding precision.
6334 1.1 is #
6335 1.1 is # INPUT
6336 1.1 is # d0 = extended precision g,r,s (in d0{31:29})
6337 1.1 is # d1 = {PREC,ROUND}
6338 1.1 is # OUTPUT
6339 1.1 is # d0{31:29} = guard, round, sticky
6340 1.1 is #
6341 1.1 is # The ext_grs extract the guard/round/sticky bits according to the
6342 1.1 is # selected rounding precision. It is called by the round subroutine
6343 1.1 is # only. All registers except d0 are kept intact. d0 becomes an
6344 1.1 is # updated guard,round,sticky in d0{31:29}
6345 1.1 is #
6346 1.1 is # Notes: the ext_grs uses the round PREC, and therefore has to swap d1
6347 1.1 is # prior to usage, and needs to restore d1 to original. this
6348 1.1 is # routine is tightly tied to the round routine and not meant to
6349 1.1 is # uphold standard subroutine calling practices.
6350 1.1 is #
6351 1.1 is
6352 1.1 is ext_grs:
6353 1.1 is swap %d1 # have d1.w point to round precision
6354 1.1 is tst.b %d1 # is rnd prec = extended?
6355 1.1 is bne.b ext_grs_not_ext # no; go handle sgl or dbl
6356 1.1 is
6357 1.1 is #
6358 1.1 is # %d0 actually already hold g,r,s since _round() had it before calling
6359 1.1 is # this function. so, as long as we don't disturb it, we are "returning" it.
6360 1.1 is #
6361 1.1 is ext_grs_ext:
6362 1.1 is swap %d1 # yes; return to correct positions
6363 1.1 is rts
6364 1.1 is
6365 1.1 is ext_grs_not_ext:
6366 1.1 is movm.l &0x3000, -(%sp) # make some temp registers {d2/d3}
6367 1.1 is
6368 1.1 is cmpi.b %d1, &s_mode # is rnd prec = sgl?
6369 1.1 is bne.b ext_grs_dbl # no; go handle dbl
6370 1.1 is
6371 1.1 is #
6372 1.1 is # sgl:
6373 1.1 is # 96 64 40 32 0
6374 1.1 is # -----------------------------------------------------
6375 1.1 is # | EXP |XXXXXXX| |xx | |grs|
6376 1.1 is # -----------------------------------------------------
6377 1.1 is # <--(24)--->nn\ /
6378 1.1 is # ee ---------------------
6379 1.1 is # ww |
6380 1.1 is # v
6381 1.1 is # gr new sticky
6382 1.1 is #
6383 1.1 is ext_grs_sgl:
6384 1.1 is bfextu FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
6385 1.1 is mov.l &30, %d2 # of the sgl prec. limits
6386 1.1 is lsl.l %d2, %d3 # shift g-r bits to MSB of d3
6387 1.1 is mov.l FTEMP_HI(%a0), %d2 # get word 2 for s-bit test
6388 1.1 is and.l &0x0000003f, %d2 # s bit is the or of all other
6389 1.1 is bne.b ext_grs_st_stky # bits to the right of g-r
6390 1.1 is tst.l FTEMP_LO(%a0) # test lower mantissa
6391 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky
6392 1.1 is tst.l %d0 # test original g,r,s
6393 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky
6394 1.1 is bra.b ext_grs_end_sd # if words 3 and 4 are clr, exit
6395 1.1 is
6396 1.1 is #
6397 1.1 is # dbl:
6398 1.1 is # 96 64 32 11 0
6399 1.1 is # -----------------------------------------------------
6400 1.1 is # | EXP |XXXXXXX| | |xx |grs|
6401 1.1 is # -----------------------------------------------------
6402 1.1 is # nn\ /
6403 1.1 is # ee -------
6404 1.1 is # ww |
6405 1.1 is # v
6406 1.1 is # gr new sticky
6407 1.1 is #
6408 1.1 is ext_grs_dbl:
6409 1.1 is bfextu FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
6410 1.1 is mov.l &30, %d2 # of the dbl prec. limits
6411 1.1 is lsl.l %d2, %d3 # shift g-r bits to the MSB of d3
6412 1.1 is mov.l FTEMP_LO(%a0), %d2 # get lower mantissa for s-bit test
6413 1.1 is and.l &0x000001ff, %d2 # s bit is the or-ing of all
6414 1.1 is bne.b ext_grs_st_stky # other bits to the right of g-r
6415 1.1 is tst.l %d0 # test word original g,r,s
6416 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky
6417 1.1 is bra.b ext_grs_end_sd # if clear, exit
6418 1.1 is
6419 1.1 is ext_grs_st_stky:
6420 1.1 is bset &rnd_stky_bit, %d3 # set sticky bit
6421 1.1 is ext_grs_end_sd:
6422 1.1 is mov.l %d3, %d0 # return grs to d0
6423 1.1 is
6424 1.1 is movm.l (%sp)+, &0xc # restore scratch registers {d2/d3}
6425 1.1 is
6426 1.1 is swap %d1 # restore d1 to original
6427 1.1 is rts
6428 1.1 is
6429 1.1 is #########################################################################
6430 1.1 is # norm(): normalize the mantissa of an extended precision input. the #
6431 1.1 is # input operand should not be normalized already. #
6432 1.1 is # #
6433 1.1 is # XDEF **************************************************************** #
6434 1.1 is # norm() #
6435 1.1 is # #
6436 1.1 is # XREF **************************************************************** #
6437 1.1 is # none #
6438 1.1 is # #
6439 1.1 is # INPUT *************************************************************** #
6440 1.1 is # a0 = pointer fp extended precision operand to normalize #
6441 1.1 is # #
6442 1.1 is # OUTPUT ************************************************************** #
6443 1.1 is # d0 = number of bit positions the mantissa was shifted #
6444 1.1 is # a0 = the input operand's mantissa is normalized; the exponent #
6445 1.1 is # is unchanged. #
6446 1.1 is # #
6447 1.1 is #########################################################################
6448 1.1 is global norm
6449 1.1 is norm:
6450 1.1 is mov.l %d2, -(%sp) # create some temp regs
6451 1.1 is mov.l %d3, -(%sp)
6452 1.1 is
6453 1.1 is mov.l FTEMP_HI(%a0), %d0 # load hi(mantissa)
6454 1.1 is mov.l FTEMP_LO(%a0), %d1 # load lo(mantissa)
6455 1.1 is
6456 1.1 is bfffo %d0{&0:&32}, %d2 # how many places to shift?
6457 1.1 is beq.b norm_lo # hi(man) is all zeroes!
6458 1.1 is
6459 1.1 is norm_hi:
6460 1.1 is lsl.l %d2, %d0 # left shift hi(man)
6461 1.1 is bfextu %d1{&0:%d2}, %d3 # extract lo bits
6462 1.1 is
6463 1.1 is or.l %d3, %d0 # create hi(man)
6464 1.1 is lsl.l %d2, %d1 # create lo(man)
6465 1.1 is
6466 1.1 is mov.l %d0, FTEMP_HI(%a0) # store new hi(man)
6467 1.1 is mov.l %d1, FTEMP_LO(%a0) # store new lo(man)
6468 1.1 is
6469 1.1 is mov.l %d2, %d0 # return shift amount
6470 1.1 is
6471 1.1 is mov.l (%sp)+, %d3 # restore temp regs
6472 1.1 is mov.l (%sp)+, %d2
6473 1.1 is
6474 1.1 is rts
6475 1.1 is
6476 1.1 is norm_lo:
6477 1.1 is bfffo %d1{&0:&32}, %d2 # how many places to shift?
6478 1.1 is lsl.l %d2, %d1 # shift lo(man)
6479 1.1 is add.l &32, %d2 # add 32 to shft amount
6480 1.1 is
6481 1.1 is mov.l %d1, FTEMP_HI(%a0) # store hi(man)
6482 1.1 is clr.l FTEMP_LO(%a0) # lo(man) is now zero
6483 1.1 is
6484 1.1 is mov.l %d2, %d0 # return shift amount
6485 1.1 is
6486 1.1 is mov.l (%sp)+, %d3 # restore temp regs
6487 1.1 is mov.l (%sp)+, %d2
6488 1.1 is
6489 1.1 is rts
6490 1.1 is
6491 1.1 is #########################################################################
6492 1.1 is # unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO #
6493 1.1 is # - returns corresponding optype tag #
6494 1.1 is # #
6495 1.1 is # XDEF **************************************************************** #
6496 1.1 is # unnorm_fix() #
6497 1.1 is # #
6498 1.1 is # XREF **************************************************************** #
6499 1.1 is # norm() - normalize the mantissa #
6500 1.1 is # #
6501 1.1 is # INPUT *************************************************************** #
6502 1.1 is # a0 = pointer to unnormalized extended precision number #
6503 1.1 is # #
6504 1.1 is # OUTPUT ************************************************************** #
6505 1.1 is # d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO #
6506 1.1 is # a0 = input operand has been converted to a norm, denorm, or #
6507 1.1 is # zero; both the exponent and mantissa are changed. #
6508 1.1 is # #
6509 1.1 is #########################################################################
6510 1.1 is
6511 1.1 is global unnorm_fix
6512 1.1 is unnorm_fix:
6513 1.1 is bfffo FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
6514 1.1 is bne.b unnorm_shift # hi(man) is not all zeroes
6515 1.1 is
6516 1.1 is #
6517 1.1 is # hi(man) is all zeroes so see if any bits in lo(man) are set
6518 1.1 is #
6519 1.1 is unnorm_chk_lo:
6520 1.1 is bfffo FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
6521 1.1 is beq.w unnorm_zero # yes
6522 1.1 is
6523 1.1 is add.w &32, %d0 # no; fix shift distance
6524 1.1 is
6525 1.1 is #
6526 1.1 is # d0 = # shifts needed for complete normalization
6527 1.1 is #
6528 1.1 is unnorm_shift:
6529 1.1 is clr.l %d1 # clear top word
6530 1.1 is mov.w FTEMP_EX(%a0), %d1 # extract exponent
6531 1.1 is and.w &0x7fff, %d1 # strip off sgn
6532 1.1 is
6533 1.1 is cmp.w %d0, %d1 # will denorm push exp < 0?
6534 1.1 is bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0
6535 1.1 is
6536 1.1 is #
6537 1.1 is # exponent would not go < 0. therefore, number stays normalized
6538 1.1 is #
6539 1.1 is sub.w %d0, %d1 # shift exponent value
6540 1.1 is mov.w FTEMP_EX(%a0), %d0 # load old exponent
6541 1.1 is and.w &0x8000, %d0 # save old sign
6542 1.1 is or.w %d0, %d1 # {sgn,new exp}
6543 1.1 is mov.w %d1, FTEMP_EX(%a0) # insert new exponent
6544 1.1 is
6545 1.1 is bsr.l norm # normalize UNNORM
6546 1.1 is
6547 1.1 is mov.b &NORM, %d0 # return new optype tag
6548 1.1 is rts
6549 1.1 is
6550 1.1 is #
6551 1.1 is # exponent would go < 0, so only denormalize until exp = 0
6552 1.1 is #
6553 1.1 is unnorm_nrm_zero:
6554 1.1 is cmp.b %d1, &32 # is exp <= 32?
6555 1.1 is bgt.b unnorm_nrm_zero_lrg # no; go handle large exponent
6556 1.1 is
6557 1.1 is bfextu FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
6558 1.1 is mov.l %d0, FTEMP_HI(%a0) # save new hi(man)
6559 1.1 is
6560 1.1 is mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man)
6561 1.1 is lsl.l %d1, %d0 # extract new lo(man)
6562 1.1 is mov.l %d0, FTEMP_LO(%a0) # save new lo(man)
6563 1.1 is
6564 1.1 is and.w &0x8000, FTEMP_EX(%a0) # set exp = 0
6565 1.1 is
6566 1.1 is mov.b &DENORM, %d0 # return new optype tag
6567 1.1 is rts
6568 1.1 is
6569 1.1 is #
6570 1.1 is # only mantissa bits set are in lo(man)
6571 1.1 is #
6572 1.1 is unnorm_nrm_zero_lrg:
6573 1.1 is sub.w &32, %d1 # adjust shft amt by 32
6574 1.1 is
6575 1.1 is mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man)
6576 1.1 is lsl.l %d1, %d0 # left shift lo(man)
6577 1.1 is
6578 1.1 is mov.l %d0, FTEMP_HI(%a0) # store new hi(man)
6579 1.1 is clr.l FTEMP_LO(%a0) # lo(man) = 0
6580 1.1 is
6581 1.1 is and.w &0x8000, FTEMP_EX(%a0) # set exp = 0
6582 1.1 is
6583 1.1 is mov.b &DENORM, %d0 # return new optype tag
6584 1.1 is rts
6585 1.1 is
6586 1.1 is #
6587 1.1 is # whole mantissa is zero so this UNNORM is actually a zero
6588 1.1 is #
6589 1.1 is unnorm_zero:
6590 1.1 is and.w &0x8000, FTEMP_EX(%a0) # force exponent to zero
6591 1.1 is
6592 1.1 is mov.b &ZERO, %d0 # fix optype tag
6593 1.1 is rts
6594 1.1 is
6595 1.1 is #########################################################################
6596 1.1 is # XDEF **************************************************************** #
6597 1.1 is # set_tag_x(): return the optype of the input ext fp number #
6598 1.1 is # #
6599 1.1 is # XREF **************************************************************** #
6600 1.1 is # None #
6601 1.1 is # #
6602 1.1 is # INPUT *************************************************************** #
6603 1.1 is # a0 = pointer to extended precision operand #
6604 1.1 is # #
6605 1.1 is # OUTPUT ************************************************************** #
6606 1.1 is # d0 = value of type tag #
6607 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO #
6608 1.1 is # #
6609 1.1 is # ALGORITHM *********************************************************** #
6610 1.1 is # Simply test the exponent, j-bit, and mantissa values to #
6611 1.1 is # determine the type of operand. #
6612 1.1 is # If it's an unnormalized zero, alter the operand and force it #
6613 1.1 is # to be a normal zero. #
6614 1.1 is # #
6615 1.1 is #########################################################################
6616 1.1 is
6617 1.1 is global set_tag_x
6618 1.1 is set_tag_x:
6619 1.1 is mov.w FTEMP_EX(%a0), %d0 # extract exponent
6620 1.1 is andi.w &0x7fff, %d0 # strip off sign
6621 1.1 is cmpi.w %d0, &0x7fff # is (EXP == MAX)?
6622 1.1 is beq.b inf_or_nan_x
6623 1.1 is not_inf_or_nan_x:
6624 1.1 is btst &0x7,FTEMP_HI(%a0)
6625 1.1 is beq.b not_norm_x
6626 1.1 is is_norm_x:
6627 1.1 is mov.b &NORM, %d0
6628 1.1 is rts
6629 1.1 is not_norm_x:
6630 1.1 is tst.w %d0 # is exponent = 0?
6631 1.1 is bne.b is_unnorm_x
6632 1.1 is not_unnorm_x:
6633 1.1 is tst.l FTEMP_HI(%a0)
6634 1.1 is bne.b is_denorm_x
6635 1.1 is tst.l FTEMP_LO(%a0)
6636 1.1 is bne.b is_denorm_x
6637 1.1 is is_zero_x:
6638 1.1 is mov.b &ZERO, %d0
6639 1.1 is rts
6640 1.1 is is_denorm_x:
6641 1.1 is mov.b &DENORM, %d0
6642 1.1 is rts
6643 1.1 is # must distinguish now "Unnormalized zeroes" which we
6644 1.1 is # must convert to zero.
6645 1.1 is is_unnorm_x:
6646 1.1 is tst.l FTEMP_HI(%a0)
6647 1.1 is bne.b is_unnorm_reg_x
6648 1.1 is tst.l FTEMP_LO(%a0)
6649 1.1 is bne.b is_unnorm_reg_x
6650 1.1 is # it's an "unnormalized zero". let's convert it to an actual zero...
6651 1.1 is andi.w &0x8000,FTEMP_EX(%a0) # clear exponent
6652 1.1 is mov.b &ZERO, %d0
6653 1.1 is rts
6654 1.1 is is_unnorm_reg_x:
6655 1.1 is mov.b &UNNORM, %d0
6656 1.1 is rts
6657 1.1 is inf_or_nan_x:
6658 1.1 is tst.l FTEMP_LO(%a0)
6659 1.1 is bne.b is_nan_x
6660 1.1 is mov.l FTEMP_HI(%a0), %d0
6661 1.1 is and.l &0x7fffffff, %d0 # msb is a don't care!
6662 1.1 is bne.b is_nan_x
6663 1.1 is is_inf_x:
6664 1.1 is mov.b &INF, %d0
6665 1.1 is rts
6666 1.1 is is_nan_x:
6667 1.1 is btst &0x6, FTEMP_HI(%a0)
6668 1.1 is beq.b is_snan_x
6669 1.1 is mov.b &QNAN, %d0
6670 1.1 is rts
6671 1.1 is is_snan_x:
6672 1.1 is mov.b &SNAN, %d0
6673 1.1 is rts
6674 1.1 is
6675 1.1 is #########################################################################
6676 1.1 is # XDEF **************************************************************** #
6677 1.1 is # set_tag_d(): return the optype of the input dbl fp number #
6678 1.1 is # #
6679 1.1 is # XREF **************************************************************** #
6680 1.1 is # None #
6681 1.1 is # #
6682 1.1 is # INPUT *************************************************************** #
6683 1.1 is # a0 = points to double precision operand #
6684 1.1 is # #
6685 1.1 is # OUTPUT ************************************************************** #
6686 1.1 is # d0 = value of type tag #
6687 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, ZERO #
6688 1.1 is # #
6689 1.1 is # ALGORITHM *********************************************************** #
6690 1.1 is # Simply test the exponent, j-bit, and mantissa values to #
6691 1.1 is # determine the type of operand. #
6692 1.1 is # #
6693 1.1 is #########################################################################
6694 1.1 is
6695 1.1 is global set_tag_d
6696 1.1 is set_tag_d:
6697 1.1 is mov.l FTEMP(%a0), %d0
6698 1.1 is mov.l %d0, %d1
6699 1.1 is
6700 1.1 is andi.l &0x7ff00000, %d0
6701 1.1 is beq.b zero_or_denorm_d
6702 1.1 is
6703 1.1 is cmpi.l %d0, &0x7ff00000
6704 1.1 is beq.b inf_or_nan_d
6705 1.1 is
6706 1.1 is is_norm_d:
6707 1.1 is mov.b &NORM, %d0
6708 1.1 is rts
6709 1.1 is zero_or_denorm_d:
6710 1.1 is and.l &0x000fffff, %d1
6711 1.1 is bne is_denorm_d
6712 1.1 is tst.l 4+FTEMP(%a0)
6713 1.1 is bne is_denorm_d
6714 1.1 is is_zero_d:
6715 1.1 is mov.b &ZERO, %d0
6716 1.1 is rts
6717 1.1 is is_denorm_d:
6718 1.1 is mov.b &DENORM, %d0
6719 1.1 is rts
6720 1.1 is inf_or_nan_d:
6721 1.1 is and.l &0x000fffff, %d1
6722 1.1 is bne is_nan_d
6723 1.1 is tst.l 4+FTEMP(%a0)
6724 1.1 is bne is_nan_d
6725 1.1 is is_inf_d:
6726 1.1 is mov.b &INF, %d0
6727 1.1 is rts
6728 1.1 is is_nan_d:
6729 1.1 is btst &19, %d1
6730 1.1 is bne is_qnan_d
6731 1.1 is is_snan_d:
6732 1.1 is mov.b &SNAN, %d0
6733 1.1 is rts
6734 1.1 is is_qnan_d:
6735 1.1 is mov.b &QNAN, %d0
6736 1.1 is rts
6737 1.1 is
6738 1.1 is #########################################################################
6739 1.1 is # XDEF **************************************************************** #
6740 1.1 is # set_tag_s(): return the optype of the input sgl fp number #
6741 1.1 is # #
6742 1.1 is # XREF **************************************************************** #
6743 1.1 is # None #
6744 1.1 is # #
6745 1.1 is # INPUT *************************************************************** #
6746 1.1 is # a0 = pointer to single precision operand #
6747 1.1 is # #
6748 1.1 is # OUTPUT ************************************************************** #
6749 1.1 is # d0 = value of type tag #
6750 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, ZERO #
6751 1.1 is # #
6752 1.1 is # ALGORITHM *********************************************************** #
6753 1.1 is # Simply test the exponent, j-bit, and mantissa values to #
6754 1.1 is # determine the type of operand. #
6755 1.1 is # #
6756 1.1 is #########################################################################
6757 1.1 is
6758 1.1 is global set_tag_s
6759 1.1 is set_tag_s:
6760 1.1 is mov.l FTEMP(%a0), %d0
6761 1.1 is mov.l %d0, %d1
6762 1.1 is
6763 1.1 is andi.l &0x7f800000, %d0
6764 1.1 is beq.b zero_or_denorm_s
6765 1.1 is
6766 1.1 is cmpi.l %d0, &0x7f800000
6767 1.1 is beq.b inf_or_nan_s
6768 1.1 is
6769 1.1 is is_norm_s:
6770 1.1 is mov.b &NORM, %d0
6771 1.1 is rts
6772 1.1 is zero_or_denorm_s:
6773 1.1 is and.l &0x007fffff, %d1
6774 1.1 is bne is_denorm_s
6775 1.1 is is_zero_s:
6776 1.1 is mov.b &ZERO, %d0
6777 1.1 is rts
6778 1.1 is is_denorm_s:
6779 1.1 is mov.b &DENORM, %d0
6780 1.1 is rts
6781 1.1 is inf_or_nan_s:
6782 1.1 is and.l &0x007fffff, %d1
6783 1.1 is bne is_nan_s
6784 1.1 is is_inf_s:
6785 1.1 is mov.b &INF, %d0
6786 1.1 is rts
6787 1.1 is is_nan_s:
6788 1.1 is btst &22, %d1
6789 1.1 is bne is_qnan_s
6790 1.1 is is_snan_s:
6791 1.1 is mov.b &SNAN, %d0
6792 1.1 is rts
6793 1.1 is is_qnan_s:
6794 1.1 is mov.b &QNAN, %d0
6795 1.1 is rts
6796 1.1 is
6797 1.1 is #########################################################################
6798 1.1 is # XDEF **************************************************************** #
6799 1.1 is # unf_res(): routine to produce default underflow result of a #
6800 1.1 is # scaled extended precision number; this is used by #
6801 1.1 is # fadd/fdiv/fmul/etc. emulation routines. #
6802 1.1 is # unf_res4(): same as above but for fsglmul/fsgldiv which use #
6803 1.1 is # single round prec and extended prec mode. #
6804 1.1 is # #
6805 1.1 is # XREF **************************************************************** #
6806 1.1 is # _denorm() - denormalize according to scale factor #
6807 1.1 is # _round() - round denormalized number according to rnd prec #
6808 1.1 is # #
6809 1.1 is # INPUT *************************************************************** #
6810 1.1 is # a0 = pointer to extended precison operand #
6811 1.1 is # d0 = scale factor #
6812 1.1 is # d1 = rounding precision/mode #
6813 1.1 is # #
6814 1.1 is # OUTPUT ************************************************************** #
6815 1.1 is # a0 = pointer to default underflow result in extended precision #
6816 1.1 is # d0.b = result FPSR_cc which caller may or may not want to save #
6817 1.1 is # #
6818 1.1 is # ALGORITHM *********************************************************** #
6819 1.1 is # Convert the input operand to "internal format" which means the #
6820 1.1 is # exponent is extended to 16 bits and the sign is stored in the unused #
6821 1.1 is # portion of the extended precison operand. Denormalize the number #
6822 1.1 is # according to the scale factor passed in d0. Then, round the #
6823 1.1 is # denormalized result. #
6824 1.1 is # Set the FPSR_exc bits as appropriate but return the cc bits in #
6825 1.1 is # d0 in case the caller doesn't want to save them (as is the case for #
6826 1.1 is # fmove out). #
6827 1.1 is # unf_res4() for fsglmul/fsgldiv forces the denorm to extended #
6828 1.1 is # precision and the rounding mode to single. #
6829 1.1 is # #
6830 1.1 is #########################################################################
6831 1.1 is global unf_res
6832 1.1 is unf_res:
6833 1.1 is mov.l %d1, -(%sp) # save rnd prec,mode on stack
6834 1.1 is
6835 1.1 is btst &0x7, FTEMP_EX(%a0) # make "internal" format
6836 1.1 is sne FTEMP_SGN(%a0)
6837 1.1 is
6838 1.1 is mov.w FTEMP_EX(%a0), %d1 # extract exponent
6839 1.1 is and.w &0x7fff, %d1
6840 1.1 is sub.w %d0, %d1
6841 1.1 is mov.w %d1, FTEMP_EX(%a0) # insert 16 bit exponent
6842 1.1 is
6843 1.1 is mov.l %a0, -(%sp) # save operand ptr during calls
6844 1.1 is
6845 1.1 is mov.l 0x4(%sp),%d0 # pass rnd prec.
6846 1.1 is andi.w &0x00c0,%d0
6847 1.1 is lsr.w &0x4,%d0
6848 1.1 is bsr.l _denorm # denorm result
6849 1.1 is
6850 1.1 is mov.l (%sp),%a0
6851 1.1 is mov.w 0x6(%sp),%d1 # load prec:mode into %d1
6852 1.1 is andi.w &0xc0,%d1 # extract rnd prec
6853 1.1 is lsr.w &0x4,%d1
6854 1.1 is swap %d1
6855 1.1 is mov.w 0x6(%sp),%d1
6856 1.1 is andi.w &0x30,%d1
6857 1.1 is lsr.w &0x4,%d1
6858 1.1 is bsr.l _round # round the denorm
6859 1.1 is
6860 1.1 is mov.l (%sp)+, %a0
6861 1.1 is
6862 1.1 is # result is now rounded properly. convert back to normal format
6863 1.1 is bclr &0x7, FTEMP_EX(%a0) # clear sgn first; may have residue
6864 1.1 is tst.b FTEMP_SGN(%a0) # is "internal result" sign set?
6865 1.1 is beq.b unf_res_chkifzero # no; result is positive
6866 1.1 is bset &0x7, FTEMP_EX(%a0) # set result sgn
6867 1.1 is clr.b FTEMP_SGN(%a0) # clear temp sign
6868 1.1 is
6869 1.1 is # the number may have become zero after rounding. set ccodes accordingly.
6870 1.1 is unf_res_chkifzero:
6871 1.1 is clr.l %d0
6872 1.1 is tst.l FTEMP_HI(%a0) # is value now a zero?
6873 1.1 is bne.b unf_res_cont # no
6874 1.1 is tst.l FTEMP_LO(%a0)
6875 1.1 is bne.b unf_res_cont # no
6876 1.1 is # bset &z_bit, FPSR_CC(%a6) # yes; set zero ccode bit
6877 1.1 is bset &z_bit, %d0 # yes; set zero ccode bit
6878 1.1 is
6879 1.1 is unf_res_cont:
6880 1.1 is
6881 1.1 is #
6882 1.1 is # can inex1 also be set along with unfl and inex2???
6883 1.1 is #
6884 1.1 is # we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6885 1.1 is #
6886 1.1 is btst &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
6887 1.1 is beq.b unf_res_end # no
6888 1.1 is bset &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl
6889 1.1 is
6890 1.1 is unf_res_end:
6891 1.1 is add.l &0x4, %sp # clear stack
6892 1.1 is rts
6893 1.1 is
6894 1.1 is # unf_res() for fsglmul() and fsgldiv().
6895 1.1 is global unf_res4
6896 1.1 is unf_res4:
6897 1.1 is mov.l %d1,-(%sp) # save rnd prec,mode on stack
6898 1.1 is
6899 1.1 is btst &0x7,FTEMP_EX(%a0) # make "internal" format
6900 1.1 is sne FTEMP_SGN(%a0)
6901 1.1 is
6902 1.1 is mov.w FTEMP_EX(%a0),%d1 # extract exponent
6903 1.1 is and.w &0x7fff,%d1
6904 1.1 is sub.w %d0,%d1
6905 1.1 is mov.w %d1,FTEMP_EX(%a0) # insert 16 bit exponent
6906 1.1 is
6907 1.1 is mov.l %a0,-(%sp) # save operand ptr during calls
6908 1.1 is
6909 1.1 is clr.l %d0 # force rnd prec = ext
6910 1.1 is bsr.l _denorm # denorm result
6911 1.1 is
6912 1.1 is mov.l (%sp),%a0
6913 1.1 is mov.w &s_mode,%d1 # force rnd prec = sgl
6914 1.1 is swap %d1
6915 1.1 is mov.w 0x6(%sp),%d1 # load rnd mode
6916 1.1 is andi.w &0x30,%d1 # extract rnd prec
6917 1.1 is lsr.w &0x4,%d1
6918 1.1 is bsr.l _round # round the denorm
6919 1.1 is
6920 1.1 is mov.l (%sp)+,%a0
6921 1.1 is
6922 1.1 is # result is now rounded properly. convert back to normal format
6923 1.1 is bclr &0x7,FTEMP_EX(%a0) # clear sgn first; may have residue
6924 1.1 is tst.b FTEMP_SGN(%a0) # is "internal result" sign set?
6925 1.1 is beq.b unf_res4_chkifzero # no; result is positive
6926 1.1 is bset &0x7,FTEMP_EX(%a0) # set result sgn
6927 1.1 is clr.b FTEMP_SGN(%a0) # clear temp sign
6928 1.1 is
6929 1.1 is # the number may have become zero after rounding. set ccodes accordingly.
6930 1.1 is unf_res4_chkifzero:
6931 1.1 is clr.l %d0
6932 1.1 is tst.l FTEMP_HI(%a0) # is value now a zero?
6933 1.1 is bne.b unf_res4_cont # no
6934 1.1 is tst.l FTEMP_LO(%a0)
6935 1.1 is bne.b unf_res4_cont # no
6936 1.1 is # bset &z_bit,FPSR_CC(%a6) # yes; set zero ccode bit
6937 1.1 is bset &z_bit,%d0 # yes; set zero ccode bit
6938 1.1 is
6939 1.1 is unf_res4_cont:
6940 1.1 is
6941 1.1 is #
6942 1.1 is # can inex1 also be set along with unfl and inex2???
6943 1.1 is #
6944 1.1 is # we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6945 1.1 is #
6946 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
6947 1.1 is beq.b unf_res4_end # no
6948 1.1 is bset &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl
6949 1.1 is
6950 1.1 is unf_res4_end:
6951 1.1 is add.l &0x4,%sp # clear stack
6952 1.1 is rts
6953 1.1 is
6954 1.1 is #########################################################################
6955 1.1 is # XDEF **************************************************************** #
6956 1.1 is # ovf_res(): routine to produce the default overflow result of #
6957 1.1 is # an overflowing number. #
6958 1.1 is # ovf_res2(): same as above but the rnd mode/prec are passed #
6959 1.1 is # differently. #
6960 1.1 is # #
6961 1.1 is # XREF **************************************************************** #
6962 1.1 is # none #
6963 1.1 is # #
6964 1.1 is # INPUT *************************************************************** #
6965 1.1 is # d1.b = '-1' => (-); '0' => (+) #
6966 1.1 is # ovf_res(): #
6967 1.1 is # d0 = rnd mode/prec #
6968 1.1 is # ovf_res2(): #
6969 1.1 is # hi(d0) = rnd prec #
6970 1.1 is # lo(d0) = rnd mode #
6971 1.1 is # #
6972 1.1 is # OUTPUT ************************************************************** #
6973 1.1 is # a0 = points to extended precision result #
6974 1.1 is # d0.b = condition code bits #
6975 1.1 is # #
6976 1.1 is # ALGORITHM *********************************************************** #
6977 1.1 is # The default overflow result can be determined by the sign of #
6978 1.1 is # the result and the rounding mode/prec in effect. These bits are #
6979 1.1 is # concatenated together to create an index into the default result #
6980 1.1 is # table. A pointer to the correct result is returned in a0. The #
6981 1.1 is # resulting condition codes are returned in d0 in case the caller #
6982 1.1 is # doesn't want FPSR_cc altered (as is the case for fmove out). #
6983 1.1 is # #
6984 1.1 is #########################################################################
6985 1.1 is
6986 1.1 is global ovf_res
6987 1.1 is ovf_res:
6988 1.1 is andi.w &0x10,%d1 # keep result sign
6989 1.1 is lsr.b &0x4,%d0 # shift prec/mode
6990 1.1 is or.b %d0,%d1 # concat the two
6991 1.1 is mov.w %d1,%d0 # make a copy
6992 1.1 is lsl.b &0x1,%d1 # multiply d1 by 2
6993 1.1 is bra.b ovf_res_load
6994 1.1 is
6995 1.1 is global ovf_res2
6996 1.1 is ovf_res2:
6997 1.1 is and.w &0x10, %d1 # keep result sign
6998 1.1 is or.b %d0, %d1 # insert rnd mode
6999 1.1 is swap %d0
7000 1.1 is or.b %d0, %d1 # insert rnd prec
7001 1.1 is mov.w %d1, %d0 # make a copy
7002 1.1 is lsl.b &0x1, %d1 # shift left by 1
7003 1.1 is
7004 1.1 is #
7005 1.1 is # use the rounding mode, precision, and result sign as in index into the
7006 1.1 is # two tables below to fetch the default result and the result ccodes.
7007 1.1 is #
7008 1.1 is ovf_res_load:
7009 1.1 is mov.b (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
7010 1.1 is lea (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr
7011 1.1 is
7012 1.1 is rts
7013 1.1 is
7014 1.1 is tbl_ovfl_cc:
7015 1.1 is byte 0x2, 0x0, 0x0, 0x2
7016 1.1 is byte 0x2, 0x0, 0x0, 0x2
7017 1.1 is byte 0x2, 0x0, 0x0, 0x2
7018 1.1 is byte 0x0, 0x0, 0x0, 0x0
7019 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7020 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7021 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7022 1.1 is
7023 1.1 is tbl_ovfl_result:
7024 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7025 1.1 is long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
7026 1.1 is long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
7027 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7028 1.1 is
7029 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7030 1.1 is long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
7031 1.1 is long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
7032 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7033 1.1 is
7034 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7035 1.1 is long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
7036 1.1 is long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
7037 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7038 1.1 is
7039 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000
7040 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000
7041 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000
7042 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000
7043 1.1 is
7044 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7045 1.1 is long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
7046 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7047 1.1 is long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP
7048 1.1 is
7049 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7050 1.1 is long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
7051 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7052 1.1 is long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP
7053 1.1 is
7054 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7055 1.1 is long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
7056 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7057 1.1 is long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP
7058 1.1 is
7059 1.1 is #########################################################################
7060 1.1 is # XDEF **************************************************************** #
7061 1.1 is # fout(): move from fp register to memory or data register #
7062 1.1 is # #
7063 1.1 is # XREF **************************************************************** #
7064 1.1 is # _round() - needed to create EXOP for sgl/dbl precision #
7065 1.1 is # norm() - needed to create EXOP for extended precision #
7066 1.1 is # ovf_res() - create default overflow result for sgl/dbl precision#
7067 1.1 is # unf_res() - create default underflow result for sgl/dbl prec. #
7068 1.1 is # dst_dbl() - create rounded dbl precision result. #
7069 1.1 is # dst_sgl() - create rounded sgl precision result. #
7070 1.1 is # fetch_dreg() - fetch dynamic k-factor reg for packed. #
7071 1.1 is # bindec() - convert FP binary number to packed number. #
7072 1.1 is # _mem_write() - write data to memory. #
7073 1.1 is # _mem_write2() - write data to memory unless supv mode -(a7) exc.#
7074 1.1 is # _dmem_write_{byte,word,long}() - write data to memory. #
7075 1.1 is # store_dreg_{b,w,l}() - store data to data register file. #
7076 1.1 is # facc_out_{b,w,l,d,x}() - data access error occurred. #
7077 1.1 is # #
7078 1.1 is # INPUT *************************************************************** #
7079 1.1 is # a0 = pointer to extended precision source operand #
7080 1.1 is # d0 = round prec,mode #
7081 1.1 is # #
7082 1.1 is # OUTPUT ************************************************************** #
7083 1.1 is # fp0 : intermediate underflow or overflow result if #
7084 1.1 is # OVFL/UNFL occurred for a sgl or dbl operand #
7085 1.1 is # #
7086 1.1 is # ALGORITHM *********************************************************** #
7087 1.1 is # This routine is accessed by many handlers that need to do an #
7088 1.1 is # opclass three move of an operand out to memory. #
7089 1.1 is # Decode an fmove out (opclass 3) instruction to determine if #
7090 1.1 is # it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data #
7091 1.1 is # register or memory. The algorithm uses a standard "fmove" to create #
7092 1.1 is # the rounded result. Also, since exceptions are disabled, this also #
7093 1.1 is # create the correct OPERR default result if appropriate. #
7094 1.1 is # For sgl or dbl precision, overflow or underflow can occur. If #
7095 1.1 is # either occurs and is enabled, the EXOP. #
7096 1.1 is # For extended precision, the stacked <ea> must be fixed along #
7097 1.1 is # w/ the address index register as appropriate w/ _calc_ea_fout(). If #
7098 1.1 is # the source is a denorm and if underflow is enabled, an EXOP must be #
7099 1.1 is # created. #
7100 1.1 is # For packed, the k-factor must be fetched from the instruction #
7101 1.1 is # word or a data register. The <ea> must be fixed as w/ extended #
7102 1.1 is # precision. Then, bindec() is called to create the appropriate #
7103 1.1 is # packed result. #
7104 1.1 is # If at any time an access error is flagged by one of the move- #
7105 1.1 is # to-memory routines, then a special exit must be made so that the #
7106 1.1 is # access error can be handled properly. #
7107 1.1 is # #
7108 1.1 is #########################################################################
7109 1.1 is
7110 1.1 is global fout
7111 1.1 is fout:
7112 1.1 is bfextu EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt
7113 1.1 is mov.w (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index
7114 1.1 is jmp (tbl_fout.b,%pc,%a1) # jump to routine
7115 1.1 is
7116 1.1 is swbeg &0x8
7117 1.1 is tbl_fout:
7118 1.1 is short fout_long - tbl_fout
7119 1.1 is short fout_sgl - tbl_fout
7120 1.1 is short fout_ext - tbl_fout
7121 1.1 is short fout_pack - tbl_fout
7122 1.1 is short fout_word - tbl_fout
7123 1.1 is short fout_dbl - tbl_fout
7124 1.1 is short fout_byte - tbl_fout
7125 1.1 is short fout_pack - tbl_fout
7126 1.1 is
7127 1.1 is #################################################################
7128 1.1 is # fmove.b out ###################################################
7129 1.1 is #################################################################
7130 1.1 is
7131 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand
7132 1.1 is # is either a DENORM or a NORM.
7133 1.1 is fout_byte:
7134 1.1 is tst.b STAG(%a6) # is operand normalized?
7135 1.1 is bne.b fout_byte_denorm # no
7136 1.1 is
7137 1.1 is fmovm.x SRC(%a0),&0x80 # load value
7138 1.1 is
7139 1.1 is fout_byte_norm:
7140 1.1 is fmov.l %d0,%fpcr # insert rnd prec,mode
7141 1.1 is
7142 1.1 is fmov.b %fp0,%d0 # exec move out w/ correct rnd mode
7143 1.1 is
7144 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7145 1.1 is fmov.l %fpsr,%d1 # fetch FPSR
7146 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7147 1.1 is
7148 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7149 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7150 1.1 is beq.b fout_byte_dn # must save to integer regfile
7151 1.1 is
7152 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7153 1.1 is bsr.l _dmem_write_byte # write byte
7154 1.1 is
7155 1.1 is tst.l %d1 # did dstore fail?
7156 1.1 is bne.l facc_out_b # yes
7157 1.1 is
7158 1.1 is rts
7159 1.1 is
7160 1.1 is fout_byte_dn:
7161 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7162 1.1 is andi.w &0x7,%d1
7163 1.1 is bsr.l store_dreg_b
7164 1.1 is rts
7165 1.1 is
7166 1.1 is fout_byte_denorm:
7167 1.1 is mov.l SRC_EX(%a0),%d1
7168 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign
7169 1.1 is ori.l &0x00800000,%d1 # make smallest sgl
7170 1.1 is fmov.s %d1,%fp0
7171 1.1 is bra.b fout_byte_norm
7172 1.1 is
7173 1.1 is #################################################################
7174 1.1 is # fmove.w out ###################################################
7175 1.1 is #################################################################
7176 1.1 is
7177 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand
7178 1.1 is # is either a DENORM or a NORM.
7179 1.1 is fout_word:
7180 1.1 is tst.b STAG(%a6) # is operand normalized?
7181 1.1 is bne.b fout_word_denorm # no
7182 1.1 is
7183 1.1 is fmovm.x SRC(%a0),&0x80 # load value
7184 1.1 is
7185 1.1 is fout_word_norm:
7186 1.1 is fmov.l %d0,%fpcr # insert rnd prec:mode
7187 1.1 is
7188 1.1 is fmov.w %fp0,%d0 # exec move out w/ correct rnd mode
7189 1.1 is
7190 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7191 1.1 is fmov.l %fpsr,%d1 # fetch FPSR
7192 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7193 1.1 is
7194 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7195 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7196 1.1 is beq.b fout_word_dn # must save to integer regfile
7197 1.1 is
7198 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7199 1.1 is bsr.l _dmem_write_word # write word
7200 1.1 is
7201 1.1 is tst.l %d1 # did dstore fail?
7202 1.1 is bne.l facc_out_w # yes
7203 1.1 is
7204 1.1 is rts
7205 1.1 is
7206 1.1 is fout_word_dn:
7207 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7208 1.1 is andi.w &0x7,%d1
7209 1.1 is bsr.l store_dreg_w
7210 1.1 is rts
7211 1.1 is
7212 1.1 is fout_word_denorm:
7213 1.1 is mov.l SRC_EX(%a0),%d1
7214 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign
7215 1.1 is ori.l &0x00800000,%d1 # make smallest sgl
7216 1.1 is fmov.s %d1,%fp0
7217 1.1 is bra.b fout_word_norm
7218 1.1 is
7219 1.1 is #################################################################
7220 1.1 is # fmove.l out ###################################################
7221 1.1 is #################################################################
7222 1.1 is
7223 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand
7224 1.1 is # is either a DENORM or a NORM.
7225 1.1 is fout_long:
7226 1.1 is tst.b STAG(%a6) # is operand normalized?
7227 1.1 is bne.b fout_long_denorm # no
7228 1.1 is
7229 1.1 is fmovm.x SRC(%a0),&0x80 # load value
7230 1.1 is
7231 1.1 is fout_long_norm:
7232 1.1 is fmov.l %d0,%fpcr # insert rnd prec:mode
7233 1.1 is
7234 1.1 is fmov.l %fp0,%d0 # exec move out w/ correct rnd mode
7235 1.1 is
7236 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7237 1.1 is fmov.l %fpsr,%d1 # fetch FPSR
7238 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7239 1.1 is
7240 1.1 is fout_long_write:
7241 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7242 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7243 1.1 is beq.b fout_long_dn # must save to integer regfile
7244 1.1 is
7245 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7246 1.1 is bsr.l _dmem_write_long # write long
7247 1.1 is
7248 1.1 is tst.l %d1 # did dstore fail?
7249 1.1 is bne.l facc_out_l # yes
7250 1.1 is
7251 1.1 is rts
7252 1.1 is
7253 1.1 is fout_long_dn:
7254 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7255 1.1 is andi.w &0x7,%d1
7256 1.1 is bsr.l store_dreg_l
7257 1.1 is rts
7258 1.1 is
7259 1.1 is fout_long_denorm:
7260 1.1 is mov.l SRC_EX(%a0),%d1
7261 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign
7262 1.1 is ori.l &0x00800000,%d1 # make smallest sgl
7263 1.1 is fmov.s %d1,%fp0
7264 1.1 is bra.b fout_long_norm
7265 1.1 is
7266 1.1 is #################################################################
7267 1.1 is # fmove.x out ###################################################
7268 1.1 is #################################################################
7269 1.1 is
7270 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand
7271 1.1 is # is either a DENORM or a NORM.
7272 1.1 is # The DENORM causes an Underflow exception.
7273 1.1 is fout_ext:
7274 1.1 is
7275 1.1 is # we copy the extended precision result to FP_SCR0 so that the reserved
7276 1.1 is # 16-bit field gets zeroed. we do this since we promise not to disturb
7277 1.1 is # what's at SRC(a0).
7278 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7279 1.1 is clr.w 2+FP_SCR0_EX(%a6) # clear reserved field
7280 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7281 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7282 1.1 is
7283 1.1 is fmovm.x SRC(%a0),&0x80 # return result
7284 1.1 is
7285 1.1 is bsr.l _calc_ea_fout # fix stacked <ea>
7286 1.1 is
7287 1.1 is mov.l %a0,%a1 # pass: dst addr
7288 1.1 is lea FP_SCR0(%a6),%a0 # pass: src addr
7289 1.1 is mov.l &0xc,%d0 # pass: opsize is 12 bytes
7290 1.1 is
7291 1.1 is # we must not yet write the extended precision data to the stack
7292 1.1 is # in the pre-decrement case from supervisor mode or else we'll corrupt
7293 1.1 is # the stack frame. so, leave it in FP_SRC for now and deal with it later...
7294 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
7295 1.1 is beq.b fout_ext_a7
7296 1.1 is
7297 1.1 is bsr.l _dmem_write # write ext prec number to memory
7298 1.1 is
7299 1.1 is tst.l %d1 # did dstore fail?
7300 1.1 is bne.w fout_ext_err # yes
7301 1.1 is
7302 1.1 is tst.b STAG(%a6) # is operand normalized?
7303 1.1 is bne.b fout_ext_denorm # no
7304 1.1 is rts
7305 1.1 is
7306 1.1 is # the number is a DENORM. must set the underflow exception bit
7307 1.1 is fout_ext_denorm:
7308 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit
7309 1.1 is
7310 1.1 is mov.b FPCR_ENABLE(%a6),%d0
7311 1.1 is andi.b &0x0a,%d0 # is UNFL or INEX enabled?
7312 1.1 is bne.b fout_ext_exc # yes
7313 1.1 is rts
7314 1.1 is
7315 1.1 is # we don't want to do the write if the exception occurred in supervisor mode
7316 1.1 is # so _mem_write2() handles this for us.
7317 1.1 is fout_ext_a7:
7318 1.1 is bsr.l _mem_write2 # write ext prec number to memory
7319 1.1 is
7320 1.1 is tst.l %d1 # did dstore fail?
7321 1.1 is bne.w fout_ext_err # yes
7322 1.1 is
7323 1.1 is tst.b STAG(%a6) # is operand normalized?
7324 1.1 is bne.b fout_ext_denorm # no
7325 1.1 is rts
7326 1.1 is
7327 1.1 is fout_ext_exc:
7328 1.1 is lea FP_SCR0(%a6),%a0
7329 1.1 is bsr.l norm # normalize the mantissa
7330 1.1 is neg.w %d0 # new exp = -(shft amt)
7331 1.1 is andi.w &0x7fff,%d0
7332 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # keep only old sign
7333 1.1 is or.w %d0,FP_SCR0_EX(%a6) # insert new exponent
7334 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
7335 1.1 is rts
7336 1.1 is
7337 1.1 is fout_ext_err:
7338 1.1 is mov.l EXC_A6(%a6),(%a6) # fix stacked a6
7339 1.1 is bra.l facc_out_x
7340 1.1 is
7341 1.1 is #########################################################################
7342 1.1 is # fmove.s out ###########################################################
7343 1.1 is #########################################################################
7344 1.1 is fout_sgl:
7345 1.1 is andi.b &0x30,%d0 # clear rnd prec
7346 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec
7347 1.1 is mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack
7348 1.1 is
7349 1.1 is #
7350 1.1 is # operand is a normalized number. first, we check to see if the move out
7351 1.1 is # would cause either an underflow or overflow. these cases are handled
7352 1.1 is # separately. otherwise, set the FPCR to the proper rounding mode and
7353 1.1 is # execute the move.
7354 1.1 is #
7355 1.1 is mov.w SRC_EX(%a0),%d0 # extract exponent
7356 1.1 is andi.w &0x7fff,%d0 # strip sign
7357 1.1 is
7358 1.1 is cmpi.w %d0,&SGL_HI # will operand overflow?
7359 1.1 is bgt.w fout_sgl_ovfl # yes; go handle OVFL
7360 1.1 is beq.w fout_sgl_may_ovfl # maybe; go handle possible OVFL
7361 1.1 is cmpi.w %d0,&SGL_LO # will operand underflow?
7362 1.1 is blt.w fout_sgl_unfl # yes; go handle underflow
7363 1.1 is
7364 1.1 is #
7365 1.1 is # NORMs(in range) can be stored out by a simple "fmov.s"
7366 1.1 is # Unnormalized inputs can come through this point.
7367 1.1 is #
7368 1.1 is fout_sgl_exg:
7369 1.1 is fmovm.x SRC(%a0),&0x80 # fetch fop from stack
7370 1.1 is
7371 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
7372 1.1 is fmov.l &0x0,%fpsr # clear FPSR
7373 1.1 is
7374 1.1 is fmov.s %fp0,%d0 # store does convert and round
7375 1.1 is
7376 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7377 1.1 is fmov.l %fpsr,%d1 # save FPSR
7378 1.1 is
7379 1.1 is or.w %d1,2+USER_FPSR(%a6) # set possible inex2/ainex
7380 1.1 is
7381 1.1 is fout_sgl_exg_write:
7382 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7383 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7384 1.1 is beq.b fout_sgl_exg_write_dn # must save to integer regfile
7385 1.1 is
7386 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7387 1.1 is bsr.l _dmem_write_long # write long
7388 1.1 is
7389 1.1 is tst.l %d1 # did dstore fail?
7390 1.1 is bne.l facc_out_l # yes
7391 1.1 is
7392 1.1 is rts
7393 1.1 is
7394 1.1 is fout_sgl_exg_write_dn:
7395 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7396 1.1 is andi.w &0x7,%d1
7397 1.1 is bsr.l store_dreg_l
7398 1.1 is rts
7399 1.1 is
7400 1.1 is #
7401 1.1 is # here, we know that the operand would UNFL if moved out to single prec,
7402 1.1 is # so, denorm and round and then use generic store single routine to
7403 1.1 is # write the value to memory.
7404 1.1 is #
7405 1.1 is fout_sgl_unfl:
7406 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7407 1.1 is
7408 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7409 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7410 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7411 1.1 is mov.l %a0,-(%sp)
7412 1.1 is
7413 1.1 is clr.l %d0 # pass: S.F. = 0
7414 1.1 is
7415 1.1 is cmpi.b STAG(%a6),&DENORM # fetch src optype tag
7416 1.1 is bne.b fout_sgl_unfl_cont # let DENORMs fall through
7417 1.1 is
7418 1.1 is lea FP_SCR0(%a6),%a0
7419 1.1 is bsr.l norm # normalize the DENORM
7420 1.1 is
7421 1.1 is fout_sgl_unfl_cont:
7422 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
7423 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
7424 1.1 is bsr.l unf_res # calc default underflow result
7425 1.1 is
7426 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to fop
7427 1.1 is bsr.l dst_sgl # convert to single prec
7428 1.1 is
7429 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7430 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7431 1.1 is beq.b fout_sgl_unfl_dn # must save to integer regfile
7432 1.1 is
7433 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7434 1.1 is bsr.l _dmem_write_long # write long
7435 1.1 is
7436 1.1 is tst.l %d1 # did dstore fail?
7437 1.1 is bne.l facc_out_l # yes
7438 1.1 is
7439 1.1 is bra.b fout_sgl_unfl_chkexc
7440 1.1 is
7441 1.1 is fout_sgl_unfl_dn:
7442 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7443 1.1 is andi.w &0x7,%d1
7444 1.1 is bsr.l store_dreg_l
7445 1.1 is
7446 1.1 is fout_sgl_unfl_chkexc:
7447 1.1 is mov.b FPCR_ENABLE(%a6),%d1
7448 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7449 1.1 is bne.w fout_sd_exc_unfl # yes
7450 1.1 is addq.l &0x4,%sp
7451 1.1 is rts
7452 1.1 is
7453 1.1 is #
7454 1.1 is # it's definitely an overflow so call ovf_res to get the correct answer
7455 1.1 is #
7456 1.1 is fout_sgl_ovfl:
7457 1.1 is tst.b 3+SRC_HI(%a0) # is result inexact?
7458 1.1 is bne.b fout_sgl_ovfl_inex2
7459 1.1 is tst.l SRC_LO(%a0) # is result inexact?
7460 1.1 is bne.b fout_sgl_ovfl_inex2
7461 1.1 is ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7462 1.1 is bra.b fout_sgl_ovfl_cont
7463 1.1 is fout_sgl_ovfl_inex2:
7464 1.1 is ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7465 1.1 is
7466 1.1 is fout_sgl_ovfl_cont:
7467 1.1 is mov.l %a0,-(%sp)
7468 1.1 is
7469 1.1 is # call ovf_res() w/ sgl prec and the correct rnd mode to create the default
7470 1.1 is # overflow result. DON'T save the returned ccodes from ovf_res() since
7471 1.1 is # fmove out doesn't alter them.
7472 1.1 is tst.b SRC_EX(%a0) # is operand negative?
7473 1.1 is smi %d1 # set if so
7474 1.1 is mov.l L_SCR3(%a6),%d0 # pass: sgl prec,rnd mode
7475 1.1 is bsr.l ovf_res # calc OVFL result
7476 1.1 is fmovm.x (%a0),&0x80 # load default overflow result
7477 1.1 is fmov.s %fp0,%d0 # store to single
7478 1.1 is
7479 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7480 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7481 1.1 is beq.b fout_sgl_ovfl_dn # must save to integer regfile
7482 1.1 is
7483 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7484 1.1 is bsr.l _dmem_write_long # write long
7485 1.1 is
7486 1.1 is tst.l %d1 # did dstore fail?
7487 1.1 is bne.l facc_out_l # yes
7488 1.1 is
7489 1.1 is bra.b fout_sgl_ovfl_chkexc
7490 1.1 is
7491 1.1 is fout_sgl_ovfl_dn:
7492 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7493 1.1 is andi.w &0x7,%d1
7494 1.1 is bsr.l store_dreg_l
7495 1.1 is
7496 1.1 is fout_sgl_ovfl_chkexc:
7497 1.1 is mov.b FPCR_ENABLE(%a6),%d1
7498 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7499 1.1 is bne.w fout_sd_exc_ovfl # yes
7500 1.1 is addq.l &0x4,%sp
7501 1.1 is rts
7502 1.1 is
7503 1.1 is #
7504 1.1 is # move out MAY overflow:
7505 1.1 is # (1) force the exp to 0x3fff
7506 1.1 is # (2) do a move w/ appropriate rnd mode
7507 1.1 is # (3) if exp still equals zero, then insert original exponent
7508 1.1 is # for the correct result.
7509 1.1 is # if exp now equals one, then it overflowed so call ovf_res.
7510 1.1 is #
7511 1.1 is fout_sgl_may_ovfl:
7512 1.1 is mov.w SRC_EX(%a0),%d1 # fetch current sign
7513 1.1 is andi.w &0x8000,%d1 # keep it,clear exp
7514 1.1 is ori.w &0x3fff,%d1 # insert exp = 0
7515 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp
7516 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7517 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7518 1.1 is
7519 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
7520 1.1 is
7521 1.1 is fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded
7522 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7523 1.1 is
7524 1.1 is fabs.x %fp0 # need absolute value
7525 1.1 is fcmp.b %fp0,&0x2 # did exponent increase?
7526 1.1 is fblt.w fout_sgl_exg # no; go finish NORM
7527 1.1 is bra.w fout_sgl_ovfl # yes; go handle overflow
7528 1.1 is
7529 1.1 is ################
7530 1.1 is
7531 1.1 is fout_sd_exc_unfl:
7532 1.1 is mov.l (%sp)+,%a0
7533 1.1 is
7534 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7535 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7536 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7537 1.1 is
7538 1.1 is cmpi.b STAG(%a6),&DENORM # was src a DENORM?
7539 1.1 is bne.b fout_sd_exc_cont # no
7540 1.1 is
7541 1.1 is lea FP_SCR0(%a6),%a0
7542 1.1 is bsr.l norm
7543 1.1 is neg.l %d0
7544 1.1 is andi.w &0x7fff,%d0
7545 1.1 is bfins %d0,FP_SCR0_EX(%a6){&1:&15}
7546 1.1 is bra.b fout_sd_exc_cont
7547 1.1 is
7548 1.1 is fout_sd_exc:
7549 1.1 is fout_sd_exc_ovfl:
7550 1.1 is mov.l (%sp)+,%a0 # restore a0
7551 1.1 is
7552 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7553 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7554 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7555 1.1 is
7556 1.1 is fout_sd_exc_cont:
7557 1.1 is bclr &0x7,FP_SCR0_EX(%a6) # clear sign bit
7558 1.1 is sne.b 2+FP_SCR0_EX(%a6) # set internal sign bit
7559 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to DENORM
7560 1.1 is
7561 1.1 is mov.b 3+L_SCR3(%a6),%d1
7562 1.1 is lsr.b &0x4,%d1
7563 1.1 is andi.w &0x0c,%d1
7564 1.1 is swap %d1
7565 1.1 is mov.b 3+L_SCR3(%a6),%d1
7566 1.1 is lsr.b &0x4,%d1
7567 1.1 is andi.w &0x03,%d1
7568 1.1 is clr.l %d0 # pass: zero g,r,s
7569 1.1 is bsr.l _round # round the DENORM
7570 1.1 is
7571 1.1 is tst.b 2+FP_SCR0_EX(%a6) # is EXOP negative?
7572 1.1 is beq.b fout_sd_exc_done # no
7573 1.1 is bset &0x7,FP_SCR0_EX(%a6) # yes
7574 1.1 is
7575 1.1 is fout_sd_exc_done:
7576 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
7577 1.1 is rts
7578 1.1 is
7579 1.1 is #################################################################
7580 1.1 is # fmove.d out ###################################################
7581 1.1 is #################################################################
7582 1.1 is fout_dbl:
7583 1.1 is andi.b &0x30,%d0 # clear rnd prec
7584 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
7585 1.1 is mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack
7586 1.1 is
7587 1.1 is #
7588 1.1 is # operand is a normalized number. first, we check to see if the move out
7589 1.1 is # would cause either an underflow or overflow. these cases are handled
7590 1.1 is # separately. otherwise, set the FPCR to the proper rounding mode and
7591 1.1 is # execute the move.
7592 1.1 is #
7593 1.1 is mov.w SRC_EX(%a0),%d0 # extract exponent
7594 1.1 is andi.w &0x7fff,%d0 # strip sign
7595 1.1 is
7596 1.1 is cmpi.w %d0,&DBL_HI # will operand overflow?
7597 1.1 is bgt.w fout_dbl_ovfl # yes; go handle OVFL
7598 1.1 is beq.w fout_dbl_may_ovfl # maybe; go handle possible OVFL
7599 1.1 is cmpi.w %d0,&DBL_LO # will operand underflow?
7600 1.1 is blt.w fout_dbl_unfl # yes; go handle underflow
7601 1.1 is
7602 1.1 is #
7603 1.1 is # NORMs(in range) can be stored out by a simple "fmov.d"
7604 1.1 is # Unnormalized inputs can come through this point.
7605 1.1 is #
7606 1.1 is fout_dbl_exg:
7607 1.1 is fmovm.x SRC(%a0),&0x80 # fetch fop from stack
7608 1.1 is
7609 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
7610 1.1 is fmov.l &0x0,%fpsr # clear FPSR
7611 1.1 is
7612 1.1 is fmov.d %fp0,L_SCR1(%a6) # store does convert and round
7613 1.1 is
7614 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7615 1.1 is fmov.l %fpsr,%d0 # save FPSR
7616 1.1 is
7617 1.1 is or.w %d0,2+USER_FPSR(%a6) # set possible inex2/ainex
7618 1.1 is
7619 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr
7620 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr
7621 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes
7622 1.1 is bsr.l _dmem_write # store dbl fop to memory
7623 1.1 is
7624 1.1 is tst.l %d1 # did dstore fail?
7625 1.1 is bne.l facc_out_d # yes
7626 1.1 is
7627 1.1 is rts # no; so we're finished
7628 1.1 is
7629 1.1 is #
7630 1.1 is # here, we know that the operand would UNFL if moved out to double prec,
7631 1.1 is # so, denorm and round and then use generic store double routine to
7632 1.1 is # write the value to memory.
7633 1.1 is #
7634 1.1 is fout_dbl_unfl:
7635 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7636 1.1 is
7637 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7638 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7639 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7640 1.1 is mov.l %a0,-(%sp)
7641 1.1 is
7642 1.1 is clr.l %d0 # pass: S.F. = 0
7643 1.1 is
7644 1.1 is cmpi.b STAG(%a6),&DENORM # fetch src optype tag
7645 1.1 is bne.b fout_dbl_unfl_cont # let DENORMs fall through
7646 1.1 is
7647 1.1 is lea FP_SCR0(%a6),%a0
7648 1.1 is bsr.l norm # normalize the DENORM
7649 1.1 is
7650 1.1 is fout_dbl_unfl_cont:
7651 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
7652 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
7653 1.1 is bsr.l unf_res # calc default underflow result
7654 1.1 is
7655 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to fop
7656 1.1 is bsr.l dst_dbl # convert to single prec
7657 1.1 is mov.l %d0,L_SCR1(%a6)
7658 1.1 is mov.l %d1,L_SCR2(%a6)
7659 1.1 is
7660 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr
7661 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr
7662 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes
7663 1.1 is bsr.l _dmem_write # store dbl fop to memory
7664 1.1 is
7665 1.1 is tst.l %d1 # did dstore fail?
7666 1.1 is bne.l facc_out_d # yes
7667 1.1 is
7668 1.1 is mov.b FPCR_ENABLE(%a6),%d1
7669 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7670 1.1 is bne.w fout_sd_exc_unfl # yes
7671 1.1 is addq.l &0x4,%sp
7672 1.1 is rts
7673 1.1 is
7674 1.1 is #
7675 1.1 is # it's definitely an overflow so call ovf_res to get the correct answer
7676 1.1 is #
7677 1.1 is fout_dbl_ovfl:
7678 1.1 is mov.w 2+SRC_LO(%a0),%d0
7679 1.1 is andi.w &0x7ff,%d0
7680 1.1 is bne.b fout_dbl_ovfl_inex2
7681 1.1 is
7682 1.1 is ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7683 1.1 is bra.b fout_dbl_ovfl_cont
7684 1.1 is fout_dbl_ovfl_inex2:
7685 1.1 is ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7686 1.1 is
7687 1.1 is fout_dbl_ovfl_cont:
7688 1.1 is mov.l %a0,-(%sp)
7689 1.1 is
7690 1.1 is # call ovf_res() w/ dbl prec and the correct rnd mode to create the default
7691 1.1 is # overflow result. DON'T save the returned ccodes from ovf_res() since
7692 1.1 is # fmove out doesn't alter them.
7693 1.1 is tst.b SRC_EX(%a0) # is operand negative?
7694 1.1 is smi %d1 # set if so
7695 1.1 is mov.l L_SCR3(%a6),%d0 # pass: dbl prec,rnd mode
7696 1.1 is bsr.l ovf_res # calc OVFL result
7697 1.1 is fmovm.x (%a0),&0x80 # load default overflow result
7698 1.1 is fmov.d %fp0,L_SCR1(%a6) # store to double
7699 1.1 is
7700 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr
7701 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr
7702 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes
7703 1.1 is bsr.l _dmem_write # store dbl fop to memory
7704 1.1 is
7705 1.1 is tst.l %d1 # did dstore fail?
7706 1.1 is bne.l facc_out_d # yes
7707 1.1 is
7708 1.1 is mov.b FPCR_ENABLE(%a6),%d1
7709 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7710 1.1 is bne.w fout_sd_exc_ovfl # yes
7711 1.1 is addq.l &0x4,%sp
7712 1.1 is rts
7713 1.1 is
7714 1.1 is #
7715 1.1 is # move out MAY overflow:
7716 1.1 is # (1) force the exp to 0x3fff
7717 1.1 is # (2) do a move w/ appropriate rnd mode
7718 1.1 is # (3) if exp still equals zero, then insert original exponent
7719 1.1 is # for the correct result.
7720 1.1 is # if exp now equals one, then it overflowed so call ovf_res.
7721 1.1 is #
7722 1.1 is fout_dbl_may_ovfl:
7723 1.1 is mov.w SRC_EX(%a0),%d1 # fetch current sign
7724 1.1 is andi.w &0x8000,%d1 # keep it,clear exp
7725 1.1 is ori.w &0x3fff,%d1 # insert exp = 0
7726 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp
7727 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7728 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7729 1.1 is
7730 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
7731 1.1 is
7732 1.1 is fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded
7733 1.1 is fmov.l &0x0,%fpcr # clear FPCR
7734 1.1 is
7735 1.1 is fabs.x %fp0 # need absolute value
7736 1.1 is fcmp.b %fp0,&0x2 # did exponent increase?
7737 1.1 is fblt.w fout_dbl_exg # no; go finish NORM
7738 1.1 is bra.w fout_dbl_ovfl # yes; go handle overflow
7739 1.1 is
7740 1.1 is #########################################################################
7741 1.1 is # XDEF **************************************************************** #
7742 1.1 is # dst_dbl(): create double precision value from extended prec. #
7743 1.1 is # #
7744 1.1 is # XREF **************************************************************** #
7745 1.1 is # None #
7746 1.1 is # #
7747 1.1 is # INPUT *************************************************************** #
7748 1.1 is # a0 = pointer to source operand in extended precision #
7749 1.1 is # #
7750 1.1 is # OUTPUT ************************************************************** #
7751 1.1 is # d0 = hi(double precision result) #
7752 1.1 is # d1 = lo(double precision result) #
7753 1.1 is # #
7754 1.1 is # ALGORITHM *********************************************************** #
7755 1.1 is # #
7756 1.1 is # Changes extended precision to double precision. #
7757 1.1 is # Note: no attempt is made to round the extended value to double. #
7758 1.1 is # dbl_sign = ext_sign #
7759 1.1 is # dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias) #
7760 1.1 is # get rid of ext integer bit #
7761 1.1 is # dbl_mant = ext_mant{62:12} #
7762 1.1 is # #
7763 1.1 is # --------------- --------------- --------------- #
7764 1.1 is # extended -> |s| exp | |1| ms mant | | ls mant | #
7765 1.1 is # --------------- --------------- --------------- #
7766 1.1 is # 95 64 63 62 32 31 11 0 #
7767 1.1 is # | | #
7768 1.1 is # | | #
7769 1.1 is # | | #
7770 1.1 is # v v #
7771 1.1 is # --------------- --------------- #
7772 1.1 is # double -> |s|exp| mant | | mant | #
7773 1.1 is # --------------- --------------- #
7774 1.1 is # 63 51 32 31 0 #
7775 1.1 is # #
7776 1.1 is #########################################################################
7777 1.1 is
7778 1.1 is dst_dbl:
7779 1.1 is clr.l %d0 # clear d0
7780 1.1 is mov.w FTEMP_EX(%a0),%d0 # get exponent
7781 1.1 is subi.w &EXT_BIAS,%d0 # subtract extended precision bias
7782 1.1 is addi.w &DBL_BIAS,%d0 # add double precision bias
7783 1.1 is tst.b FTEMP_HI(%a0) # is number a denorm?
7784 1.1 is bmi.b dst_get_dupper # no
7785 1.1 is subq.w &0x1,%d0 # yes; denorm bias = DBL_BIAS - 1
7786 1.1 is dst_get_dupper:
7787 1.1 is swap %d0 # d0 now in upper word
7788 1.1 is lsl.l &0x4,%d0 # d0 in proper place for dbl prec exp
7789 1.1 is tst.b FTEMP_EX(%a0) # test sign
7790 1.1 is bpl.b dst_get_dman # if postive, go process mantissa
7791 1.1 is bset &0x1f,%d0 # if negative, set sign
7792 1.1 is dst_get_dman:
7793 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7794 1.1 is bfextu %d1{&1:&20},%d1 # get upper 20 bits of ms
7795 1.1 is or.l %d1,%d0 # put these bits in ms word of double
7796 1.1 is mov.l %d0,L_SCR1(%a6) # put the new exp back on the stack
7797 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7798 1.1 is mov.l &21,%d0 # load shift count
7799 1.1 is lsl.l %d0,%d1 # put lower 11 bits in upper bits
7800 1.1 is mov.l %d1,L_SCR2(%a6) # build lower lword in memory
7801 1.1 is mov.l FTEMP_LO(%a0),%d1 # get ls mantissa
7802 1.1 is bfextu %d1{&0:&21},%d0 # get ls 21 bits of double
7803 1.1 is mov.l L_SCR2(%a6),%d1
7804 1.1 is or.l %d0,%d1 # put them in double result
7805 1.1 is mov.l L_SCR1(%a6),%d0
7806 1.1 is rts
7807 1.1 is
7808 1.1 is #########################################################################
7809 1.1 is # XDEF **************************************************************** #
7810 1.1 is # dst_sgl(): create single precision value from extended prec #
7811 1.1 is # #
7812 1.1 is # XREF **************************************************************** #
7813 1.1 is # #
7814 1.1 is # INPUT *************************************************************** #
7815 1.1 is # a0 = pointer to source operand in extended precision #
7816 1.1 is # #
7817 1.1 is # OUTPUT ************************************************************** #
7818 1.1 is # d0 = single precision result #
7819 1.1 is # #
7820 1.1 is # ALGORITHM *********************************************************** #
7821 1.1 is # #
7822 1.1 is # Changes extended precision to single precision. #
7823 1.1 is # sgl_sign = ext_sign #
7824 1.1 is # sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias) #
7825 1.1 is # get rid of ext integer bit #
7826 1.1 is # sgl_mant = ext_mant{62:12} #
7827 1.1 is # #
7828 1.1 is # --------------- --------------- --------------- #
7829 1.1 is # extended -> |s| exp | |1| ms mant | | ls mant | #
7830 1.1 is # --------------- --------------- --------------- #
7831 1.1 is # 95 64 63 62 40 32 31 12 0 #
7832 1.1 is # | | #
7833 1.1 is # | | #
7834 1.1 is # | | #
7835 1.1 is # v v #
7836 1.1 is # --------------- #
7837 1.1 is # single -> |s|exp| mant | #
7838 1.1 is # --------------- #
7839 1.1 is # 31 22 0 #
7840 1.1 is # #
7841 1.1 is #########################################################################
7842 1.1 is
7843 1.1 is dst_sgl:
7844 1.1 is clr.l %d0
7845 1.1 is mov.w FTEMP_EX(%a0),%d0 # get exponent
7846 1.1 is subi.w &EXT_BIAS,%d0 # subtract extended precision bias
7847 1.1 is addi.w &SGL_BIAS,%d0 # add single precision bias
7848 1.1 is tst.b FTEMP_HI(%a0) # is number a denorm?
7849 1.1 is bmi.b dst_get_supper # no
7850 1.1 is subq.w &0x1,%d0 # yes; denorm bias = SGL_BIAS - 1
7851 1.1 is dst_get_supper:
7852 1.1 is swap %d0 # put exp in upper word of d0
7853 1.1 is lsl.l &0x7,%d0 # shift it into single exp bits
7854 1.1 is tst.b FTEMP_EX(%a0) # test sign
7855 1.1 is bpl.b dst_get_sman # if positive, continue
7856 1.1 is bset &0x1f,%d0 # if negative, put in sign first
7857 1.1 is dst_get_sman:
7858 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7859 1.1 is andi.l &0x7fffff00,%d1 # get upper 23 bits of ms
7860 1.1 is lsr.l &0x8,%d1 # and put them flush right
7861 1.1 is or.l %d1,%d0 # put these bits in ms word of single
7862 1.1 is rts
7863 1.1 is
7864 1.1 is ##############################################################################
7865 1.1 is fout_pack:
7866 1.1 is bsr.l _calc_ea_fout # fetch the <ea>
7867 1.1 is mov.l %a0,-(%sp)
7868 1.1 is
7869 1.1 is mov.b STAG(%a6),%d0 # fetch input type
7870 1.1 is bne.w fout_pack_not_norm # input is not NORM
7871 1.1 is
7872 1.1 is fout_pack_norm:
7873 1.1 is btst &0x4,EXC_CMDREG(%a6) # static or dynamic?
7874 1.1 is beq.b fout_pack_s # static
7875 1.1 is
7876 1.1 is fout_pack_d:
7877 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 # fetch dynamic reg
7878 1.1 is lsr.b &0x4,%d1
7879 1.1 is andi.w &0x7,%d1
7880 1.1 is
7881 1.1 is bsr.l fetch_dreg # fetch Dn w/ k-factor
7882 1.1 is
7883 1.1 is bra.b fout_pack_type
7884 1.1 is fout_pack_s:
7885 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch static field
7886 1.1 is
7887 1.1 is fout_pack_type:
7888 1.1 is bfexts %d0{&25:&7},%d0 # extract k-factor
7889 1.1 is mov.l %d0,-(%sp)
7890 1.1 is
7891 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to input
7892 1.1 is
7893 1.1 is # bindec is currently scrambling FP_SRC for denorm inputs.
7894 1.1 is # we'll have to change this, but for now, tough luck!!!
7895 1.1 is bsr.l bindec # convert xprec to packed
7896 1.1 is
7897 1.1 is # andi.l &0xcfff000f,FP_SCR0(%a6) # clear unused fields
7898 1.1 is andi.l &0xcffff00f,FP_SCR0(%a6) # clear unused fields
7899 1.1 is
7900 1.1 is mov.l (%sp)+,%d0
7901 1.1 is
7902 1.1 is tst.b 3+FP_SCR0_EX(%a6)
7903 1.1 is bne.b fout_pack_set
7904 1.1 is tst.l FP_SCR0_HI(%a6)
7905 1.1 is bne.b fout_pack_set
7906 1.1 is tst.l FP_SCR0_LO(%a6)
7907 1.1 is bne.b fout_pack_set
7908 1.1 is
7909 1.1 is # add the extra condition that only if the k-factor was zero, too, should
7910 1.1 is # we zero the exponent
7911 1.1 is tst.l %d0
7912 1.1 is bne.b fout_pack_set
7913 1.1 is # "mantissa" is all zero which means that the answer is zero. but, the '040
7914 1.1 is # algorithm allows the exponent to be non-zero. the 881/2 do not. therefore,
7915 1.1 is # if the mantissa is zero, I will zero the exponent, too.
7916 1.1 is # the question now is whether the exponents sign bit is allowed to be non-zero
7917 1.1 is # for a zero, also...
7918 1.1 is andi.w &0xf000,FP_SCR0(%a6)
7919 1.1 is
7920 1.1 is fout_pack_set:
7921 1.1 is
7922 1.1 is lea FP_SCR0(%a6),%a0 # pass: src addr
7923 1.1 is
7924 1.1 is fout_pack_write:
7925 1.1 is mov.l (%sp)+,%a1 # pass: dst addr
7926 1.1 is mov.l &0xc,%d0 # pass: opsize is 12 bytes
7927 1.1 is
7928 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg
7929 1.1 is beq.b fout_pack_a7
7930 1.1 is
7931 1.1 is bsr.l _dmem_write # write ext prec number to memory
7932 1.1 is
7933 1.1 is tst.l %d1 # did dstore fail?
7934 1.1 is bne.w fout_ext_err # yes
7935 1.1 is
7936 1.1 is rts
7937 1.1 is
7938 1.1 is # we don't want to do the write if the exception occurred in supervisor mode
7939 1.1 is # so _mem_write2() handles this for us.
7940 1.1 is fout_pack_a7:
7941 1.1 is bsr.l _mem_write2 # write ext prec number to memory
7942 1.1 is
7943 1.1 is tst.l %d1 # did dstore fail?
7944 1.1 is bne.w fout_ext_err # yes
7945 1.1 is
7946 1.1 is rts
7947 1.1 is
7948 1.1 is fout_pack_not_norm:
7949 1.1 is cmpi.b %d0,&DENORM # is it a DENORM?
7950 1.1 is beq.w fout_pack_norm # yes
7951 1.1 is lea FP_SRC(%a6),%a0
7952 1.1 is clr.w 2+FP_SRC_EX(%a6)
7953 1.1 is cmpi.b %d0,&SNAN # is it an SNAN?
7954 1.1 is beq.b fout_pack_snan # yes
7955 1.1 is bra.b fout_pack_write # no
7956 1.1 is
7957 1.1 is fout_pack_snan:
7958 1.1 is ori.w &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP
7959 1.1 is bset &0x6,FP_SRC_HI(%a6) # set snan bit
7960 1.1 is bra.b fout_pack_write
7961 1.1 is
7962 1.1 is #########################################################################
7963 1.1 is # XDEF **************************************************************** #
7964 1.1 is # fmul(): emulates the fmul instruction #
7965 1.1 is # fsmul(): emulates the fsmul instruction #
7966 1.1 is # fdmul(): emulates the fdmul instruction #
7967 1.1 is # #
7968 1.1 is # XREF **************************************************************** #
7969 1.1 is # scale_to_zero_src() - scale src exponent to zero #
7970 1.1 is # scale_to_zero_dst() - scale dst exponent to zero #
7971 1.1 is # unf_res() - return default underflow result #
7972 1.1 is # ovf_res() - return default overflow result #
7973 1.1 is # res_qnan() - return QNAN result #
7974 1.1 is # res_snan() - return SNAN result #
7975 1.1 is # #
7976 1.1 is # INPUT *************************************************************** #
7977 1.1 is # a0 = pointer to extended precision source operand #
7978 1.1 is # a1 = pointer to extended precision destination operand #
7979 1.1 is # d0 rnd prec,mode #
7980 1.1 is # #
7981 1.1 is # OUTPUT ************************************************************** #
7982 1.1 is # fp0 = result #
7983 1.1 is # fp1 = EXOP (if exception occurred) #
7984 1.1 is # #
7985 1.1 is # ALGORITHM *********************************************************** #
7986 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
7987 1.1 is # norms/denorms into ext/sgl/dbl precision. #
7988 1.1 is # For norms/denorms, scale the exponents such that a multiply #
7989 1.1 is # instruction won't cause an exception. Use the regular fmul to #
7990 1.1 is # compute a result. Check if the regular operands would have taken #
7991 1.1 is # an exception. If so, return the default overflow/underflow result #
7992 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the #
7993 1.1 is # result operand to the proper exponent. #
7994 1.1 is # #
7995 1.1 is #########################################################################
7996 1.1 is
7997 1.1 is align 0x10
7998 1.1 is tbl_fmul_ovfl:
7999 1.1 is long 0x3fff - 0x7ffe # ext_max
8000 1.1 is long 0x3fff - 0x407e # sgl_max
8001 1.1 is long 0x3fff - 0x43fe # dbl_max
8002 1.1 is tbl_fmul_unfl:
8003 1.1 is long 0x3fff + 0x0001 # ext_unfl
8004 1.1 is long 0x3fff - 0x3f80 # sgl_unfl
8005 1.1 is long 0x3fff - 0x3c00 # dbl_unfl
8006 1.1 is
8007 1.1 is global fsmul
8008 1.1 is fsmul:
8009 1.1 is andi.b &0x30,%d0 # clear rnd prec
8010 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec
8011 1.1 is bra.b fmul
8012 1.1 is
8013 1.1 is global fdmul
8014 1.1 is fdmul:
8015 1.1 is andi.b &0x30,%d0
8016 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
8017 1.1 is
8018 1.1 is global fmul
8019 1.1 is fmul:
8020 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
8021 1.1 is
8022 1.1 is clr.w %d1
8023 1.1 is mov.b DTAG(%a6),%d1
8024 1.1 is lsl.b &0x3,%d1
8025 1.1 is or.b STAG(%a6),%d1 # combine src tags
8026 1.1 is bne.w fmul_not_norm # optimize on non-norm input
8027 1.1 is
8028 1.1 is fmul_norm:
8029 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
8030 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
8031 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
8032 1.1 is
8033 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8034 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8035 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8036 1.1 is
8037 1.1 is bsr.l scale_to_zero_src # scale src exponent
8038 1.1 is mov.l %d0,-(%sp) # save scale factor 1
8039 1.1 is
8040 1.1 is bsr.l scale_to_zero_dst # scale dst exponent
8041 1.1 is
8042 1.1 is add.l %d0,(%sp) # SCALE_FACTOR = scale1 + scale2
8043 1.1 is
8044 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision
8045 1.1 is lsr.b &0x6,%d1 # shift to lo bits
8046 1.1 is mov.l (%sp)+,%d0 # load S.F.
8047 1.1 is cmp.l %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl?
8048 1.1 is beq.w fmul_may_ovfl # result may rnd to overflow
8049 1.1 is blt.w fmul_ovfl # result will overflow
8050 1.1 is
8051 1.1 is cmp.l %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl?
8052 1.1 is beq.w fmul_may_unfl # result may rnd to no unfl
8053 1.1 is bgt.w fmul_unfl # result will underflow
8054 1.1 is
8055 1.1 is #
8056 1.1 is # NORMAL:
8057 1.1 is # - the result of the multiply operation will neither overflow nor underflow.
8058 1.1 is # - do the multiply to the proper precision and rounding mode.
8059 1.1 is # - scale the result exponent using the scale factor. if both operands were
8060 1.1 is # normalized then we really don't need to go through this scaling. but for now,
8061 1.1 is # this will do.
8062 1.1 is #
8063 1.1 is fmul_normal:
8064 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8065 1.1 is
8066 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8067 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8068 1.1 is
8069 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8070 1.1 is
8071 1.1 is fmov.l %fpsr,%d1 # save status
8072 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8073 1.1 is
8074 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8075 1.1 is
8076 1.1 is fmul_normal_exit:
8077 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
8078 1.1 is mov.l %d2,-(%sp) # save d2
8079 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8080 1.1 is mov.l %d1,%d2 # make a copy
8081 1.1 is andi.l &0x7fff,%d1 # strip sign
8082 1.1 is andi.w &0x8000,%d2 # keep old sign
8083 1.1 is sub.l %d0,%d1 # add scale factor
8084 1.1 is or.w %d2,%d1 # concat old sign,new exp
8085 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8086 1.1 is mov.l (%sp)+,%d2 # restore d2
8087 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8088 1.1 is rts
8089 1.1 is
8090 1.1 is #
8091 1.1 is # OVERFLOW:
8092 1.1 is # - the result of the multiply operation is an overflow.
8093 1.1 is # - do the multiply to the proper precision and rounding mode in order to
8094 1.1 is # set the inexact bits.
8095 1.1 is # - calculate the default result and return it in fp0.
8096 1.1 is # - if overflow or inexact is enabled, we need a multiply result rounded to
8097 1.1 is # extended precision. if the original operation was extended, then we have this
8098 1.1 is # result. if the original operation was single or double, we have to do another
8099 1.1 is # multiply using extended precision and the correct rounding mode. the result
8100 1.1 is # of this operation then has its exponent scaled by -0x6000 to create the
8101 1.1 is # exceptional operand.
8102 1.1 is #
8103 1.1 is fmul_ovfl:
8104 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8105 1.1 is
8106 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8107 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8108 1.1 is
8109 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8110 1.1 is
8111 1.1 is fmov.l %fpsr,%d1 # save status
8112 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8113 1.1 is
8114 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8115 1.1 is
8116 1.1 is # save setting this until now because this is where fmul_may_ovfl may jump in
8117 1.1 is fmul_ovfl_tst:
8118 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8119 1.1 is
8120 1.1 is mov.b FPCR_ENABLE(%a6),%d1
8121 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
8122 1.1 is bne.b fmul_ovfl_ena # yes
8123 1.1 is
8124 1.1 is # calculate the default result
8125 1.1 is fmul_ovfl_dis:
8126 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
8127 1.1 is sne %d1 # set sign param accordingly
8128 1.1 is mov.l L_SCR3(%a6),%d0 # pass rnd prec,mode
8129 1.1 is bsr.l ovf_res # calculate default result
8130 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
8131 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
8132 1.1 is rts
8133 1.1 is
8134 1.1 is #
8135 1.1 is # OVFL is enabled; Create EXOP:
8136 1.1 is # - if precision is extended, then we have the EXOP. simply bias the exponent
8137 1.1 is # with an extra -0x6000. if the precision is single or double, we need to
8138 1.1 is # calculate a result rounded to extended precision.
8139 1.1 is #
8140 1.1 is fmul_ovfl_ena:
8141 1.1 is mov.l L_SCR3(%a6),%d1
8142 1.1 is andi.b &0xc0,%d1 # test the rnd prec
8143 1.1 is bne.b fmul_ovfl_ena_sd # it's sgl or dbl
8144 1.1 is
8145 1.1 is fmul_ovfl_ena_cont:
8146 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
8147 1.1 is
8148 1.1 is mov.l %d2,-(%sp) # save d2
8149 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8150 1.1 is mov.w %d1,%d2 # make a copy
8151 1.1 is andi.l &0x7fff,%d1 # strip sign
8152 1.1 is sub.l %d0,%d1 # add scale factor
8153 1.1 is subi.l &0x6000,%d1 # subtract bias
8154 1.1 is andi.w &0x7fff,%d1 # clear sign bit
8155 1.1 is andi.w &0x8000,%d2 # keep old sign
8156 1.1 is or.w %d2,%d1 # concat old sign,new exp
8157 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8158 1.1 is mov.l (%sp)+,%d2 # restore d2
8159 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8160 1.1 is bra.b fmul_ovfl_dis
8161 1.1 is
8162 1.1 is fmul_ovfl_ena_sd:
8163 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8164 1.1 is
8165 1.1 is mov.l L_SCR3(%a6),%d1
8166 1.1 is andi.b &0x30,%d1 # keep rnd mode only
8167 1.1 is fmov.l %d1,%fpcr # set FPCR
8168 1.1 is
8169 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8170 1.1 is
8171 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8172 1.1 is bra.b fmul_ovfl_ena_cont
8173 1.1 is
8174 1.1 is #
8175 1.1 is # may OVERFLOW:
8176 1.1 is # - the result of the multiply operation MAY overflow.
8177 1.1 is # - do the multiply to the proper precision and rounding mode in order to
8178 1.1 is # set the inexact bits.
8179 1.1 is # - calculate the default result and return it in fp0.
8180 1.1 is #
8181 1.1 is fmul_may_ovfl:
8182 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8183 1.1 is
8184 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8185 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8186 1.1 is
8187 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8188 1.1 is
8189 1.1 is fmov.l %fpsr,%d1 # save status
8190 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8191 1.1 is
8192 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8193 1.1 is
8194 1.1 is fabs.x %fp0,%fp1 # make a copy of result
8195 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b?
8196 1.1 is fbge.w fmul_ovfl_tst # yes; overflow has occurred
8197 1.1 is
8198 1.1 is # no, it didn't overflow; we have correct result
8199 1.1 is bra.w fmul_normal_exit
8200 1.1 is
8201 1.1 is #
8202 1.1 is # UNDERFLOW:
8203 1.1 is # - the result of the multiply operation is an underflow.
8204 1.1 is # - do the multiply to the proper precision and rounding mode in order to
8205 1.1 is # set the inexact bits.
8206 1.1 is # - calculate the default result and return it in fp0.
8207 1.1 is # - if overflow or inexact is enabled, we need a multiply result rounded to
8208 1.1 is # extended precision. if the original operation was extended, then we have this
8209 1.1 is # result. if the original operation was single or double, we have to do another
8210 1.1 is # multiply using extended precision and the correct rounding mode. the result
8211 1.1 is # of this operation then has its exponent scaled by -0x6000 to create the
8212 1.1 is # exceptional operand.
8213 1.1 is #
8214 1.1 is fmul_unfl:
8215 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8216 1.1 is
8217 1.1 is # for fun, let's use only extended precision, round to zero. then, let
8218 1.1 is # the unf_res() routine figure out all the rest.
8219 1.1 is # will we get the correct answer.
8220 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8221 1.1 is
8222 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
8223 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8224 1.1 is
8225 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8226 1.1 is
8227 1.1 is fmov.l %fpsr,%d1 # save status
8228 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8229 1.1 is
8230 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8231 1.1 is
8232 1.1 is mov.b FPCR_ENABLE(%a6),%d1
8233 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
8234 1.1 is bne.b fmul_unfl_ena # yes
8235 1.1 is
8236 1.1 is fmul_unfl_dis:
8237 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
8238 1.1 is
8239 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
8240 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
8241 1.1 is bsr.l unf_res # calculate default result
8242 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res2 may have set 'Z'
8243 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8244 1.1 is rts
8245 1.1 is
8246 1.1 is #
8247 1.1 is # UNFL is enabled.
8248 1.1 is #
8249 1.1 is fmul_unfl_ena:
8250 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op
8251 1.1 is
8252 1.1 is mov.l L_SCR3(%a6),%d1
8253 1.1 is andi.b &0xc0,%d1 # is precision extended?
8254 1.1 is bne.b fmul_unfl_ena_sd # no, sgl or dbl
8255 1.1 is
8256 1.1 is # if the rnd mode is anything but RZ, then we have to re-do the above
8257 1.3 wiz # multiplication because we used RZ for all.
8258 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8259 1.1 is
8260 1.1 is fmul_unfl_ena_cont:
8261 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8262 1.1 is
8263 1.1 is fmul.x FP_SCR0(%a6),%fp1 # execute multiply
8264 1.1 is
8265 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8266 1.1 is
8267 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
8268 1.1 is mov.l %d2,-(%sp) # save d2
8269 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8270 1.1 is mov.l %d1,%d2 # make a copy
8271 1.1 is andi.l &0x7fff,%d1 # strip sign
8272 1.1 is andi.w &0x8000,%d2 # keep old sign
8273 1.1 is sub.l %d0,%d1 # add scale factor
8274 1.1 is addi.l &0x6000,%d1 # add bias
8275 1.1 is andi.w &0x7fff,%d1
8276 1.1 is or.w %d2,%d1 # concat old sign,new exp
8277 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8278 1.1 is mov.l (%sp)+,%d2 # restore d2
8279 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8280 1.1 is bra.w fmul_unfl_dis
8281 1.1 is
8282 1.1 is fmul_unfl_ena_sd:
8283 1.1 is mov.l L_SCR3(%a6),%d1
8284 1.1 is andi.b &0x30,%d1 # use only rnd mode
8285 1.1 is fmov.l %d1,%fpcr # set FPCR
8286 1.1 is
8287 1.1 is bra.b fmul_unfl_ena_cont
8288 1.1 is
8289 1.1 is # MAY UNDERFLOW:
8290 1.1 is # -use the correct rounding mode and precision. this code favors operations
8291 1.1 is # that do not underflow.
8292 1.1 is fmul_may_unfl:
8293 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8294 1.1 is
8295 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8296 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8297 1.1 is
8298 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8299 1.1 is
8300 1.1 is fmov.l %fpsr,%d1 # save status
8301 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8302 1.1 is
8303 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8304 1.1 is
8305 1.1 is fabs.x %fp0,%fp1 # make a copy of result
8306 1.1 is fcmp.b %fp1,&0x2 # is |result| > 2.b?
8307 1.1 is fbgt.w fmul_normal_exit # no; no underflow occurred
8308 1.1 is fblt.w fmul_unfl # yes; underflow occurred
8309 1.1 is
8310 1.1 is #
8311 1.1 is # we still don't know if underflow occurred. result is ~ equal to 2. but,
8312 1.1 is # we don't know if the result was an underflow that rounded up to a 2 or
8313 1.1 is # a normalized number that rounded down to a 2. so, redo the entire operation
8314 1.1 is # using RZ as the rounding mode to see what the pre-rounded result is.
8315 1.1 is # this case should be relatively rare.
8316 1.1 is #
8317 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst operand
8318 1.1 is
8319 1.1 is mov.l L_SCR3(%a6),%d1
8320 1.1 is andi.b &0xc0,%d1 # keep rnd prec
8321 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ
8322 1.1 is
8323 1.1 is fmov.l %d1,%fpcr # set FPCR
8324 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8325 1.1 is
8326 1.1 is fmul.x FP_SCR0(%a6),%fp1 # execute multiply
8327 1.1 is
8328 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8329 1.1 is fabs.x %fp1 # make absolute value
8330 1.1 is fcmp.b %fp1,&0x2 # is |result| < 2.b?
8331 1.1 is fbge.w fmul_normal_exit # no; no underflow occurred
8332 1.1 is bra.w fmul_unfl # yes, underflow occurred
8333 1.1 is
8334 1.1 is ################################################################################
8335 1.1 is
8336 1.1 is #
8337 1.1 is # Multiply: inputs are not both normalized; what are they?
8338 1.1 is #
8339 1.1 is fmul_not_norm:
8340 1.1 is mov.w (tbl_fmul_op.b,%pc,%d1.w*2),%d1
8341 1.1 is jmp (tbl_fmul_op.b,%pc,%d1.w)
8342 1.1 is
8343 1.1 is swbeg &48
8344 1.1 is tbl_fmul_op:
8345 1.1 is short fmul_norm - tbl_fmul_op # NORM x NORM
8346 1.1 is short fmul_zero - tbl_fmul_op # NORM x ZERO
8347 1.1 is short fmul_inf_src - tbl_fmul_op # NORM x INF
8348 1.1 is short fmul_res_qnan - tbl_fmul_op # NORM x QNAN
8349 1.1 is short fmul_norm - tbl_fmul_op # NORM x DENORM
8350 1.1 is short fmul_res_snan - tbl_fmul_op # NORM x SNAN
8351 1.1 is short tbl_fmul_op - tbl_fmul_op #
8352 1.1 is short tbl_fmul_op - tbl_fmul_op #
8353 1.1 is
8354 1.1 is short fmul_zero - tbl_fmul_op # ZERO x NORM
8355 1.1 is short fmul_zero - tbl_fmul_op # ZERO x ZERO
8356 1.1 is short fmul_res_operr - tbl_fmul_op # ZERO x INF
8357 1.1 is short fmul_res_qnan - tbl_fmul_op # ZERO x QNAN
8358 1.1 is short fmul_zero - tbl_fmul_op # ZERO x DENORM
8359 1.1 is short fmul_res_snan - tbl_fmul_op # ZERO x SNAN
8360 1.1 is short tbl_fmul_op - tbl_fmul_op #
8361 1.1 is short tbl_fmul_op - tbl_fmul_op #
8362 1.1 is
8363 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x NORM
8364 1.1 is short fmul_res_operr - tbl_fmul_op # INF x ZERO
8365 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x INF
8366 1.1 is short fmul_res_qnan - tbl_fmul_op # INF x QNAN
8367 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x DENORM
8368 1.1 is short fmul_res_snan - tbl_fmul_op # INF x SNAN
8369 1.1 is short tbl_fmul_op - tbl_fmul_op #
8370 1.1 is short tbl_fmul_op - tbl_fmul_op #
8371 1.1 is
8372 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x NORM
8373 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x ZERO
8374 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x INF
8375 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x QNAN
8376 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x DENORM
8377 1.1 is short fmul_res_snan - tbl_fmul_op # QNAN x SNAN
8378 1.1 is short tbl_fmul_op - tbl_fmul_op #
8379 1.1 is short tbl_fmul_op - tbl_fmul_op #
8380 1.1 is
8381 1.1 is short fmul_norm - tbl_fmul_op # NORM x NORM
8382 1.1 is short fmul_zero - tbl_fmul_op # NORM x ZERO
8383 1.1 is short fmul_inf_src - tbl_fmul_op # NORM x INF
8384 1.1 is short fmul_res_qnan - tbl_fmul_op # NORM x QNAN
8385 1.1 is short fmul_norm - tbl_fmul_op # NORM x DENORM
8386 1.1 is short fmul_res_snan - tbl_fmul_op # NORM x SNAN
8387 1.1 is short tbl_fmul_op - tbl_fmul_op #
8388 1.1 is short tbl_fmul_op - tbl_fmul_op #
8389 1.1 is
8390 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x NORM
8391 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x ZERO
8392 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x INF
8393 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x QNAN
8394 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x DENORM
8395 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x SNAN
8396 1.1 is short tbl_fmul_op - tbl_fmul_op #
8397 1.1 is short tbl_fmul_op - tbl_fmul_op #
8398 1.1 is
8399 1.1 is fmul_res_operr:
8400 1.1 is bra.l res_operr
8401 1.1 is fmul_res_snan:
8402 1.1 is bra.l res_snan
8403 1.1 is fmul_res_qnan:
8404 1.1 is bra.l res_qnan
8405 1.1 is
8406 1.1 is #
8407 1.1 is # Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm)
8408 1.1 is #
8409 1.1 is global fmul_zero # global for fsglmul
8410 1.1 is fmul_zero:
8411 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8412 1.1 is mov.b DST_EX(%a1),%d1
8413 1.1 is eor.b %d0,%d1
8414 1.1 is bpl.b fmul_zero_p # result ZERO is pos.
8415 1.1 is fmul_zero_n:
8416 1.1 is fmov.s &0x80000000,%fp0 # load -ZERO
8417 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
8418 1.1 is rts
8419 1.1 is fmul_zero_p:
8420 1.1 is fmov.s &0x00000000,%fp0 # load +ZERO
8421 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
8422 1.1 is rts
8423 1.1 is
8424 1.1 is #
8425 1.1 is # Multiply: (inf x inf) || (inf x norm) || (inf x denorm)
8426 1.1 is #
8427 1.1 is # Note: The j-bit for an infinity is a don't-care. However, to be
8428 1.1 is # strictly compatible w/ the 68881/882, we make sure to return an
8429 1.1 is # INF w/ the j-bit set if the input INF j-bit was set. Destination
8430 1.1 is # INFs take priority.
8431 1.1 is #
8432 1.1 is global fmul_inf_dst # global for fsglmul
8433 1.1 is fmul_inf_dst:
8434 1.1 is fmovm.x DST(%a1),&0x80 # return INF result in fp0
8435 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8436 1.1 is mov.b DST_EX(%a1),%d1
8437 1.1 is eor.b %d0,%d1
8438 1.1 is bpl.b fmul_inf_dst_p # result INF is pos.
8439 1.1 is fmul_inf_dst_n:
8440 1.1 is fabs.x %fp0 # clear result sign
8441 1.1 is fneg.x %fp0 # set result sign
8442 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
8443 1.1 is rts
8444 1.1 is fmul_inf_dst_p:
8445 1.1 is fabs.x %fp0 # clear result sign
8446 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF
8447 1.1 is rts
8448 1.1 is
8449 1.1 is global fmul_inf_src # global for fsglmul
8450 1.1 is fmul_inf_src:
8451 1.1 is fmovm.x SRC(%a0),&0x80 # return INF result in fp0
8452 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8453 1.1 is mov.b DST_EX(%a1),%d1
8454 1.1 is eor.b %d0,%d1
8455 1.1 is bpl.b fmul_inf_dst_p # result INF is pos.
8456 1.1 is bra.b fmul_inf_dst_n
8457 1.1 is
8458 1.1 is #########################################################################
8459 1.1 is # XDEF **************************************************************** #
8460 1.1 is # fin(): emulates the fmove instruction #
8461 1.1 is # fsin(): emulates the fsmove instruction #
8462 1.1 is # fdin(): emulates the fdmove instruction #
8463 1.1 is # #
8464 1.1 is # XREF **************************************************************** #
8465 1.1 is # norm() - normalize mantissa for EXOP on denorm #
8466 1.1 is # scale_to_zero_src() - scale src exponent to zero #
8467 1.1 is # ovf_res() - return default overflow result #
8468 1.1 is # unf_res() - return default underflow result #
8469 1.1 is # res_qnan_1op() - return QNAN result #
8470 1.1 is # res_snan_1op() - return SNAN result #
8471 1.1 is # #
8472 1.1 is # INPUT *************************************************************** #
8473 1.1 is # a0 = pointer to extended precision source operand #
8474 1.1 is # d0 = round prec/mode #
8475 1.1 is # #
8476 1.1 is # OUTPUT ************************************************************** #
8477 1.1 is # fp0 = result #
8478 1.1 is # fp1 = EXOP (if exception occurred) #
8479 1.1 is # #
8480 1.1 is # ALGORITHM *********************************************************** #
8481 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
8482 1.1 is # norms into extended, single, and double precision. #
8483 1.1 is # Norms can be emulated w/ a regular fmove instruction. For #
8484 1.1 is # sgl/dbl, must scale exponent and perform an "fmove". Check to see #
8485 1.1 is # if the result would have overflowed/underflowed. If so, use unf_res() #
8486 1.1 is # or ovf_res() to return the default result. Also return EXOP if #
8487 1.1 is # exception is enabled. If no exception, return the default result. #
8488 1.1 is # Unnorms don't pass through here. #
8489 1.1 is # #
8490 1.1 is #########################################################################
8491 1.1 is
8492 1.1 is global fsin
8493 1.1 is fsin:
8494 1.1 is andi.b &0x30,%d0 # clear rnd prec
8495 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision
8496 1.1 is bra.b fin
8497 1.1 is
8498 1.1 is global fdin
8499 1.1 is fdin:
8500 1.1 is andi.b &0x30,%d0 # clear rnd prec
8501 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision
8502 1.1 is
8503 1.1 is global fin
8504 1.1 is fin:
8505 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
8506 1.1 is
8507 1.1 is mov.b STAG(%a6),%d1 # fetch src optype tag
8508 1.1 is bne.w fin_not_norm # optimize on non-norm input
8509 1.1 is
8510 1.1 is #
8511 1.1 is # FP MOVE IN: NORMs and DENORMs ONLY!
8512 1.1 is #
8513 1.1 is fin_norm:
8514 1.1 is andi.b &0xc0,%d0 # is precision extended?
8515 1.1 is bne.w fin_not_ext # no, so go handle dbl or sgl
8516 1.1 is
8517 1.1 is #
8518 1.1 is # precision selected is extended. so...we cannot get an underflow
8519 1.1 is # or overflow because of rounding to the correct precision. so...
8520 1.1 is # skip the scaling and unscaling...
8521 1.1 is #
8522 1.1 is tst.b SRC_EX(%a0) # is the operand negative?
8523 1.1 is bpl.b fin_norm_done # no
8524 1.1 is bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit
8525 1.1 is fin_norm_done:
8526 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0
8527 1.1 is rts
8528 1.1 is
8529 1.1 is #
8530 1.1 is # for an extended precision DENORM, the UNFL exception bit is set
8531 1.1 is # the accrued bit is NOT set in this instance(no inexactness!)
8532 1.1 is #
8533 1.1 is fin_denorm:
8534 1.1 is andi.b &0xc0,%d0 # is precision extended?
8535 1.1 is bne.w fin_not_ext # no, so go handle dbl or sgl
8536 1.1 is
8537 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8538 1.1 is tst.b SRC_EX(%a0) # is the operand negative?
8539 1.1 is bpl.b fin_denorm_done # no
8540 1.1 is bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit
8541 1.1 is fin_denorm_done:
8542 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0
8543 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
8544 1.1 is bne.b fin_denorm_unfl_ena # yes
8545 1.1 is rts
8546 1.1 is
8547 1.1 is #
8548 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR.
8549 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative
8550 1.1 is # exponent and insert back into the operand.
8551 1.1 is #
8552 1.1 is fin_denorm_unfl_ena:
8553 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8554 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8555 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8556 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
8557 1.1 is bsr.l norm # normalize result
8558 1.1 is neg.w %d0 # new exponent = -(shft val)
8559 1.1 is addi.w &0x6000,%d0 # add new bias to exponent
8560 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
8561 1.1 is andi.w &0x8000,%d1 # keep old sign
8562 1.1 is andi.w &0x7fff,%d0 # clear sign position
8563 1.1 is or.w %d1,%d0 # concat new exo,old sign
8564 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
8565 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8566 1.1 is rts
8567 1.1 is
8568 1.1 is #
8569 1.1 is # operand is to be rounded to single or double precision
8570 1.1 is #
8571 1.1 is fin_not_ext:
8572 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
8573 1.1 is bne.b fin_dbl
8574 1.1 is
8575 1.1 is #
8576 1.1 is # operand is to be rounded to single precision
8577 1.1 is #
8578 1.1 is fin_sgl:
8579 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8580 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8581 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8582 1.1 is bsr.l scale_to_zero_src # calculate scale factor
8583 1.1 is
8584 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
8585 1.1 is bge.w fin_sd_unfl # yes; go handle underflow
8586 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
8587 1.1 is beq.w fin_sd_may_ovfl # maybe; go check
8588 1.1 is blt.w fin_sd_ovfl # yes; go handle overflow
8589 1.1 is
8590 1.1 is #
8591 1.1 is # operand will NOT overflow or underflow when moved into the fp reg file
8592 1.1 is #
8593 1.1 is fin_sd_normal:
8594 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8595 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8596 1.1 is
8597 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform move
8598 1.1 is
8599 1.1 is fmov.l %fpsr,%d1 # save FPSR
8600 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8601 1.1 is
8602 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8603 1.1 is
8604 1.1 is fin_sd_normal_exit:
8605 1.1 is mov.l %d2,-(%sp) # save d2
8606 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
8607 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8608 1.1 is mov.w %d1,%d2 # make a copy
8609 1.1 is andi.l &0x7fff,%d1 # strip sign
8610 1.1 is sub.l %d0,%d1 # add scale factor
8611 1.1 is andi.w &0x8000,%d2 # keep old sign
8612 1.1 is or.w %d1,%d2 # concat old sign,new exponent
8613 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
8614 1.1 is mov.l (%sp)+,%d2 # restore d2
8615 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
8616 1.1 is rts
8617 1.1 is
8618 1.1 is #
8619 1.1 is # operand is to be rounded to double precision
8620 1.1 is #
8621 1.1 is fin_dbl:
8622 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8623 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8624 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8625 1.1 is bsr.l scale_to_zero_src # calculate scale factor
8626 1.1 is
8627 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
8628 1.1 is bge.w fin_sd_unfl # yes; go handle underflow
8629 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
8630 1.1 is beq.w fin_sd_may_ovfl # maybe; go check
8631 1.1 is blt.w fin_sd_ovfl # yes; go handle overflow
8632 1.1 is bra.w fin_sd_normal # no; ho handle normalized op
8633 1.1 is
8634 1.1 is #
8635 1.1 is # operand WILL underflow when moved in to the fp register file
8636 1.1 is #
8637 1.1 is fin_sd_unfl:
8638 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8639 1.1 is
8640 1.1 is tst.b FP_SCR0_EX(%a6) # is operand negative?
8641 1.1 is bpl.b fin_sd_unfl_tst
8642 1.1 is bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit
8643 1.1 is
8644 1.1 is # if underflow or inexact is enabled, then go calculate the EXOP first.
8645 1.1 is fin_sd_unfl_tst:
8646 1.1 is mov.b FPCR_ENABLE(%a6),%d1
8647 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
8648 1.1 is bne.b fin_sd_unfl_ena # yes
8649 1.1 is
8650 1.1 is fin_sd_unfl_dis:
8651 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
8652 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
8653 1.1 is bsr.l unf_res # calculate default result
8654 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z'
8655 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8656 1.1 is rts
8657 1.1 is
8658 1.1 is #
8659 1.1 is # operand will underflow AND underflow or inexact is enabled.
8660 1.1 is # therefore, we must return the result rounded to extended precision.
8661 1.1 is #
8662 1.1 is fin_sd_unfl_ena:
8663 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
8664 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
8665 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
8666 1.1 is
8667 1.1 is mov.l %d2,-(%sp) # save d2
8668 1.1 is mov.w %d1,%d2 # make a copy
8669 1.1 is andi.l &0x7fff,%d1 # strip sign
8670 1.1 is sub.l %d0,%d1 # subtract scale factor
8671 1.1 is andi.w &0x8000,%d2 # extract old sign
8672 1.1 is addi.l &0x6000,%d1 # add new bias
8673 1.1 is andi.w &0x7fff,%d1
8674 1.1 is or.w %d1,%d2 # concat old sign,new exp
8675 1.1 is mov.w %d2,FP_SCR1_EX(%a6) # insert new exponent
8676 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
8677 1.1 is mov.l (%sp)+,%d2 # restore d2
8678 1.1 is bra.b fin_sd_unfl_dis
8679 1.1 is
8680 1.1 is #
8681 1.1 is # operand WILL overflow.
8682 1.1 is #
8683 1.1 is fin_sd_ovfl:
8684 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8685 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8686 1.1 is
8687 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform move
8688 1.1 is
8689 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8690 1.1 is fmov.l %fpsr,%d1 # save FPSR
8691 1.1 is
8692 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8693 1.1 is
8694 1.1 is fin_sd_ovfl_tst:
8695 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8696 1.1 is
8697 1.1 is mov.b FPCR_ENABLE(%a6),%d1
8698 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
8699 1.1 is bne.b fin_sd_ovfl_ena # yes
8700 1.1 is
8701 1.1 is #
8702 1.1 is # OVFL is not enabled; therefore, we must create the default result by
8703 1.1 is # calling ovf_res().
8704 1.1 is #
8705 1.1 is fin_sd_ovfl_dis:
8706 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
8707 1.1 is sne %d1 # set sign param accordingly
8708 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode
8709 1.1 is bsr.l ovf_res # calculate default result
8710 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
8711 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
8712 1.1 is rts
8713 1.1 is
8714 1.1 is #
8715 1.1 is # OVFL is enabled.
8716 1.1 is # the INEX2 bit has already been updated by the round to the correct precision.
8717 1.1 is # now, round to extended(and don't alter the FPSR).
8718 1.1 is #
8719 1.1 is fin_sd_ovfl_ena:
8720 1.1 is mov.l %d2,-(%sp) # save d2
8721 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8722 1.1 is mov.l %d1,%d2 # make a copy
8723 1.1 is andi.l &0x7fff,%d1 # strip sign
8724 1.1 is andi.w &0x8000,%d2 # keep old sign
8725 1.1 is sub.l %d0,%d1 # add scale factor
8726 1.1 is sub.l &0x6000,%d1 # subtract bias
8727 1.1 is andi.w &0x7fff,%d1
8728 1.1 is or.w %d2,%d1
8729 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8730 1.1 is mov.l (%sp)+,%d2 # restore d2
8731 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8732 1.1 is bra.b fin_sd_ovfl_dis
8733 1.1 is
8734 1.1 is #
8735 1.1 is # the move in MAY overflow. so...
8736 1.1 is #
8737 1.1 is fin_sd_may_ovfl:
8738 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8739 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8740 1.1 is
8741 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform the move
8742 1.1 is
8743 1.1 is fmov.l %fpsr,%d1 # save status
8744 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8745 1.1 is
8746 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8747 1.1 is
8748 1.1 is fabs.x %fp0,%fp1 # make a copy of result
8749 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b?
8750 1.1 is fbge.w fin_sd_ovfl_tst # yes; overflow has occurred
8751 1.1 is
8752 1.1 is # no, it didn't overflow; we have correct result
8753 1.1 is bra.w fin_sd_normal_exit
8754 1.1 is
8755 1.1 is ##########################################################################
8756 1.1 is
8757 1.1 is #
8758 1.1 is # operand is not a NORM: check its optype and branch accordingly
8759 1.1 is #
8760 1.1 is fin_not_norm:
8761 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
8762 1.1 is beq.w fin_denorm
8763 1.1 is cmpi.b %d1,&SNAN # weed out SNANs
8764 1.1 is beq.l res_snan_1op
8765 1.1 is cmpi.b %d1,&QNAN # weed out QNANs
8766 1.1 is beq.l res_qnan_1op
8767 1.1 is
8768 1.1 is #
8769 1.1 is # do the fmove in; at this point, only possible ops are ZERO and INF.
8770 1.1 is # use fmov to determine ccodes.
8771 1.1 is # prec:mode should be zero at this point but it won't affect answer anyways.
8772 1.1 is #
8773 1.1 is fmov.x SRC(%a0),%fp0 # do fmove in
8774 1.1 is fmov.l %fpsr,%d0 # no exceptions possible
8775 1.1 is rol.l &0x8,%d0 # put ccodes in lo byte
8776 1.1 is mov.b %d0,FPSR_CC(%a6) # insert correct ccodes
8777 1.1 is rts
8778 1.1 is
8779 1.1 is #########################################################################
8780 1.1 is # XDEF **************************************************************** #
8781 1.1 is # fdiv(): emulates the fdiv instruction #
8782 1.1 is # fsdiv(): emulates the fsdiv instruction #
8783 1.1 is # fddiv(): emulates the fddiv instruction #
8784 1.1 is # #
8785 1.1 is # XREF **************************************************************** #
8786 1.1 is # scale_to_zero_src() - scale src exponent to zero #
8787 1.1 is # scale_to_zero_dst() - scale dst exponent to zero #
8788 1.1 is # unf_res() - return default underflow result #
8789 1.1 is # ovf_res() - return default overflow result #
8790 1.1 is # res_qnan() - return QNAN result #
8791 1.1 is # res_snan() - return SNAN result #
8792 1.1 is # #
8793 1.1 is # INPUT *************************************************************** #
8794 1.1 is # a0 = pointer to extended precision source operand #
8795 1.1 is # a1 = pointer to extended precision destination operand #
8796 1.1 is # d0 rnd prec,mode #
8797 1.1 is # #
8798 1.1 is # OUTPUT ************************************************************** #
8799 1.1 is # fp0 = result #
8800 1.1 is # fp1 = EXOP (if exception occurred) #
8801 1.1 is # #
8802 1.1 is # ALGORITHM *********************************************************** #
8803 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
8804 1.1 is # norms/denorms into ext/sgl/dbl precision. #
8805 1.1 is # For norms/denorms, scale the exponents such that a divide #
8806 1.1 is # instruction won't cause an exception. Use the regular fdiv to #
8807 1.1 is # compute a result. Check if the regular operands would have taken #
8808 1.1 is # an exception. If so, return the default overflow/underflow result #
8809 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the #
8810 1.1 is # result operand to the proper exponent. #
8811 1.1 is # #
8812 1.1 is #########################################################################
8813 1.1 is
8814 1.1 is align 0x10
8815 1.1 is tbl_fdiv_unfl:
8816 1.1 is long 0x3fff - 0x0000 # ext_unfl
8817 1.1 is long 0x3fff - 0x3f81 # sgl_unfl
8818 1.1 is long 0x3fff - 0x3c01 # dbl_unfl
8819 1.1 is
8820 1.1 is tbl_fdiv_ovfl:
8821 1.1 is long 0x3fff - 0x7ffe # ext overflow exponent
8822 1.1 is long 0x3fff - 0x407e # sgl overflow exponent
8823 1.1 is long 0x3fff - 0x43fe # dbl overflow exponent
8824 1.1 is
8825 1.1 is global fsdiv
8826 1.1 is fsdiv:
8827 1.1 is andi.b &0x30,%d0 # clear rnd prec
8828 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec
8829 1.1 is bra.b fdiv
8830 1.1 is
8831 1.1 is global fddiv
8832 1.1 is fddiv:
8833 1.1 is andi.b &0x30,%d0 # clear rnd prec
8834 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
8835 1.1 is
8836 1.1 is global fdiv
8837 1.1 is fdiv:
8838 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
8839 1.1 is
8840 1.1 is clr.w %d1
8841 1.1 is mov.b DTAG(%a6),%d1
8842 1.1 is lsl.b &0x3,%d1
8843 1.1 is or.b STAG(%a6),%d1 # combine src tags
8844 1.1 is
8845 1.1 is bne.w fdiv_not_norm # optimize on non-norm input
8846 1.1 is
8847 1.1 is #
8848 1.1 is # DIVIDE: NORMs and DENORMs ONLY!
8849 1.1 is #
8850 1.1 is fdiv_norm:
8851 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
8852 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
8853 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
8854 1.1 is
8855 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8856 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8857 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8858 1.1 is
8859 1.1 is bsr.l scale_to_zero_src # scale src exponent
8860 1.1 is mov.l %d0,-(%sp) # save scale factor 1
8861 1.1 is
8862 1.1 is bsr.l scale_to_zero_dst # scale dst exponent
8863 1.1 is
8864 1.1 is neg.l (%sp) # SCALE FACTOR = scale1 - scale2
8865 1.1 is add.l %d0,(%sp)
8866 1.1 is
8867 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision
8868 1.1 is lsr.b &0x6,%d1 # shift to lo bits
8869 1.1 is mov.l (%sp)+,%d0 # load S.F.
8870 1.1 is cmp.l %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow?
8871 1.1 is ble.w fdiv_may_ovfl # result will overflow
8872 1.1 is
8873 1.1 is cmp.l %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow?
8874 1.1 is beq.w fdiv_may_unfl # maybe
8875 1.1 is bgt.w fdiv_unfl # yes; go handle underflow
8876 1.1 is
8877 1.1 is fdiv_normal:
8878 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8879 1.1 is
8880 1.1 is fmov.l L_SCR3(%a6),%fpcr # save FPCR
8881 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8882 1.1 is
8883 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # perform divide
8884 1.1 is
8885 1.1 is fmov.l %fpsr,%d1 # save FPSR
8886 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8887 1.1 is
8888 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
8889 1.1 is
8890 1.1 is fdiv_normal_exit:
8891 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store result on stack
8892 1.1 is mov.l %d2,-(%sp) # store d2
8893 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8894 1.1 is mov.l %d1,%d2 # make a copy
8895 1.1 is andi.l &0x7fff,%d1 # strip sign
8896 1.1 is andi.w &0x8000,%d2 # keep old sign
8897 1.1 is sub.l %d0,%d1 # add scale factor
8898 1.1 is or.w %d2,%d1 # concat old sign,new exp
8899 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8900 1.1 is mov.l (%sp)+,%d2 # restore d2
8901 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
8902 1.1 is rts
8903 1.1 is
8904 1.1 is tbl_fdiv_ovfl2:
8905 1.1 is long 0x7fff
8906 1.1 is long 0x407f
8907 1.1 is long 0x43ff
8908 1.1 is
8909 1.1 is fdiv_no_ovfl:
8910 1.1 is mov.l (%sp)+,%d0 # restore scale factor
8911 1.1 is bra.b fdiv_normal_exit
8912 1.1 is
8913 1.1 is fdiv_may_ovfl:
8914 1.1 is mov.l %d0,-(%sp) # save scale factor
8915 1.1 is
8916 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8917 1.1 is
8918 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
8919 1.1 is fmov.l &0x0,%fpsr # set FPSR
8920 1.1 is
8921 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8922 1.1 is
8923 1.1 is fmov.l %fpsr,%d0
8924 1.1 is fmov.l &0x0,%fpcr
8925 1.1 is
8926 1.1 is or.l %d0,USER_FPSR(%a6) # save INEX,N
8927 1.1 is
8928 1.1 is fmovm.x &0x01,-(%sp) # save result to stack
8929 1.1 is mov.w (%sp),%d0 # fetch new exponent
8930 1.1 is add.l &0xc,%sp # clear result from stack
8931 1.1 is andi.l &0x7fff,%d0 # strip sign
8932 1.1 is sub.l (%sp),%d0 # add scale factor
8933 1.1 is cmp.l %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4)
8934 1.1 is blt.b fdiv_no_ovfl
8935 1.1 is mov.l (%sp)+,%d0
8936 1.1 is
8937 1.1 is fdiv_ovfl_tst:
8938 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8939 1.1 is
8940 1.1 is mov.b FPCR_ENABLE(%a6),%d1
8941 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
8942 1.1 is bne.b fdiv_ovfl_ena # yes
8943 1.1 is
8944 1.1 is fdiv_ovfl_dis:
8945 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
8946 1.1 is sne %d1 # set sign param accordingly
8947 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd
8948 1.1 is bsr.l ovf_res # calculate default result
8949 1.1 is or.b %d0,FPSR_CC(%a6) # set INF if applicable
8950 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
8951 1.1 is rts
8952 1.1 is
8953 1.1 is fdiv_ovfl_ena:
8954 1.1 is mov.l L_SCR3(%a6),%d1
8955 1.1 is andi.b &0xc0,%d1 # is precision extended?
8956 1.1 is bne.b fdiv_ovfl_ena_sd # no, do sgl or dbl
8957 1.1 is
8958 1.1 is fdiv_ovfl_ena_cont:
8959 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
8960 1.1 is
8961 1.1 is mov.l %d2,-(%sp) # save d2
8962 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8963 1.1 is mov.w %d1,%d2 # make a copy
8964 1.1 is andi.l &0x7fff,%d1 # strip sign
8965 1.1 is sub.l %d0,%d1 # add scale factor
8966 1.1 is subi.l &0x6000,%d1 # subtract bias
8967 1.1 is andi.w &0x7fff,%d1 # clear sign bit
8968 1.1 is andi.w &0x8000,%d2 # keep old sign
8969 1.1 is or.w %d2,%d1 # concat old sign,new exp
8970 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8971 1.1 is mov.l (%sp)+,%d2 # restore d2
8972 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8973 1.1 is bra.b fdiv_ovfl_dis
8974 1.1 is
8975 1.1 is fdiv_ovfl_ena_sd:
8976 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8977 1.1 is
8978 1.1 is mov.l L_SCR3(%a6),%d1
8979 1.1 is andi.b &0x30,%d1 # keep rnd mode
8980 1.1 is fmov.l %d1,%fpcr # set FPCR
8981 1.1 is
8982 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8983 1.1 is
8984 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8985 1.1 is bra.b fdiv_ovfl_ena_cont
8986 1.1 is
8987 1.1 is fdiv_unfl:
8988 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8989 1.1 is
8990 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8991 1.1 is
8992 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
8993 1.1 is fmov.l &0x0,%fpsr # clear FPSR
8994 1.1 is
8995 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8996 1.1 is
8997 1.1 is fmov.l %fpsr,%d1 # save status
8998 1.1 is fmov.l &0x0,%fpcr # clear FPCR
8999 1.1 is
9000 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
9001 1.1 is
9002 1.1 is mov.b FPCR_ENABLE(%a6),%d1
9003 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
9004 1.1 is bne.b fdiv_unfl_ena # yes
9005 1.1 is
9006 1.1 is fdiv_unfl_dis:
9007 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
9008 1.1 is
9009 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
9010 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
9011 1.1 is bsr.l unf_res # calculate default result
9012 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' may have been set
9013 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9014 1.1 is rts
9015 1.1 is
9016 1.1 is #
9017 1.1 is # UNFL is enabled.
9018 1.1 is #
9019 1.1 is fdiv_unfl_ena:
9020 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op
9021 1.1 is
9022 1.1 is mov.l L_SCR3(%a6),%d1
9023 1.1 is andi.b &0xc0,%d1 # is precision extended?
9024 1.1 is bne.b fdiv_unfl_ena_sd # no, sgl or dbl
9025 1.1 is
9026 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9027 1.1 is
9028 1.1 is fdiv_unfl_ena_cont:
9029 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9030 1.1 is
9031 1.1 is fdiv.x FP_SCR0(%a6),%fp1 # execute divide
9032 1.1 is
9033 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9034 1.1 is
9035 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
9036 1.1 is mov.l %d2,-(%sp) # save d2
9037 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
9038 1.1 is mov.l %d1,%d2 # make a copy
9039 1.1 is andi.l &0x7fff,%d1 # strip sign
9040 1.1 is andi.w &0x8000,%d2 # keep old sign
9041 1.1 is sub.l %d0,%d1 # add scale factoer
9042 1.1 is addi.l &0x6000,%d1 # add bias
9043 1.1 is andi.w &0x7fff,%d1
9044 1.1 is or.w %d2,%d1 # concat old sign,new exp
9045 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exp
9046 1.1 is mov.l (%sp)+,%d2 # restore d2
9047 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9048 1.1 is bra.w fdiv_unfl_dis
9049 1.1 is
9050 1.1 is fdiv_unfl_ena_sd:
9051 1.1 is mov.l L_SCR3(%a6),%d1
9052 1.1 is andi.b &0x30,%d1 # use only rnd mode
9053 1.1 is fmov.l %d1,%fpcr # set FPCR
9054 1.1 is
9055 1.1 is bra.b fdiv_unfl_ena_cont
9056 1.1 is
9057 1.1 is #
9058 1.1 is # the divide operation MAY underflow:
9059 1.1 is #
9060 1.1 is fdiv_may_unfl:
9061 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
9062 1.1 is
9063 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9064 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9065 1.1 is
9066 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide
9067 1.1 is
9068 1.1 is fmov.l %fpsr,%d1 # save status
9069 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9070 1.1 is
9071 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
9072 1.1 is
9073 1.1 is fabs.x %fp0,%fp1 # make a copy of result
9074 1.1 is fcmp.b %fp1,&0x1 # is |result| > 1.b?
9075 1.1 is fbgt.w fdiv_normal_exit # no; no underflow occurred
9076 1.1 is fblt.w fdiv_unfl # yes; underflow occurred
9077 1.1 is
9078 1.1 is #
9079 1.1 is # we still don't know if underflow occurred. result is ~ equal to 1. but,
9080 1.1 is # we don't know if the result was an underflow that rounded up to a 1
9081 1.1 is # or a normalized number that rounded down to a 1. so, redo the entire
9082 1.1 is # operation using RZ as the rounding mode to see what the pre-rounded
9083 1.1 is # result is. this case should be relatively rare.
9084 1.1 is #
9085 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
9086 1.1 is
9087 1.1 is mov.l L_SCR3(%a6),%d1
9088 1.1 is andi.b &0xc0,%d1 # keep rnd prec
9089 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ
9090 1.1 is
9091 1.1 is fmov.l %d1,%fpcr # set FPCR
9092 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9093 1.1 is
9094 1.1 is fdiv.x FP_SCR0(%a6),%fp1 # execute divide
9095 1.1 is
9096 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9097 1.1 is fabs.x %fp1 # make absolute value
9098 1.1 is fcmp.b %fp1,&0x1 # is |result| < 1.b?
9099 1.1 is fbge.w fdiv_normal_exit # no; no underflow occurred
9100 1.1 is bra.w fdiv_unfl # yes; underflow occurred
9101 1.1 is
9102 1.1 is ############################################################################
9103 1.1 is
9104 1.1 is #
9105 1.1 is # Divide: inputs are not both normalized; what are they?
9106 1.1 is #
9107 1.1 is fdiv_not_norm:
9108 1.1 is mov.w (tbl_fdiv_op.b,%pc,%d1.w*2),%d1
9109 1.1 is jmp (tbl_fdiv_op.b,%pc,%d1.w*1)
9110 1.1 is
9111 1.1 is swbeg &48
9112 1.1 is tbl_fdiv_op:
9113 1.1 is short fdiv_norm - tbl_fdiv_op # NORM / NORM
9114 1.1 is short fdiv_inf_load - tbl_fdiv_op # NORM / ZERO
9115 1.1 is short fdiv_zero_load - tbl_fdiv_op # NORM / INF
9116 1.1 is short fdiv_res_qnan - tbl_fdiv_op # NORM / QNAN
9117 1.1 is short fdiv_norm - tbl_fdiv_op # NORM / DENORM
9118 1.1 is short fdiv_res_snan - tbl_fdiv_op # NORM / SNAN
9119 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9120 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9121 1.1 is
9122 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / NORM
9123 1.1 is short fdiv_res_operr - tbl_fdiv_op # ZERO / ZERO
9124 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / INF
9125 1.1 is short fdiv_res_qnan - tbl_fdiv_op # ZERO / QNAN
9126 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / DENORM
9127 1.1 is short fdiv_res_snan - tbl_fdiv_op # ZERO / SNAN
9128 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9129 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9130 1.1 is
9131 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / NORM
9132 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / ZERO
9133 1.1 is short fdiv_res_operr - tbl_fdiv_op # INF / INF
9134 1.1 is short fdiv_res_qnan - tbl_fdiv_op # INF / QNAN
9135 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / DENORM
9136 1.1 is short fdiv_res_snan - tbl_fdiv_op # INF / SNAN
9137 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9138 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9139 1.1 is
9140 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / NORM
9141 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / ZERO
9142 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / INF
9143 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / QNAN
9144 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / DENORM
9145 1.1 is short fdiv_res_snan - tbl_fdiv_op # QNAN / SNAN
9146 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9147 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9148 1.1 is
9149 1.1 is short fdiv_norm - tbl_fdiv_op # DENORM / NORM
9150 1.1 is short fdiv_inf_load - tbl_fdiv_op # DENORM / ZERO
9151 1.1 is short fdiv_zero_load - tbl_fdiv_op # DENORM / INF
9152 1.1 is short fdiv_res_qnan - tbl_fdiv_op # DENORM / QNAN
9153 1.1 is short fdiv_norm - tbl_fdiv_op # DENORM / DENORM
9154 1.1 is short fdiv_res_snan - tbl_fdiv_op # DENORM / SNAN
9155 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9156 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9157 1.1 is
9158 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / NORM
9159 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / ZERO
9160 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / INF
9161 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / QNAN
9162 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / DENORM
9163 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / SNAN
9164 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9165 1.1 is short tbl_fdiv_op - tbl_fdiv_op #
9166 1.1 is
9167 1.1 is fdiv_res_qnan:
9168 1.1 is bra.l res_qnan
9169 1.1 is fdiv_res_snan:
9170 1.1 is bra.l res_snan
9171 1.1 is fdiv_res_operr:
9172 1.1 is bra.l res_operr
9173 1.1 is
9174 1.1 is global fdiv_zero_load # global for fsgldiv
9175 1.1 is fdiv_zero_load:
9176 1.1 is mov.b SRC_EX(%a0),%d0 # result sign is exclusive
9177 1.1 is mov.b DST_EX(%a1),%d1 # or of input signs.
9178 1.1 is eor.b %d0,%d1
9179 1.1 is bpl.b fdiv_zero_load_p # result is positive
9180 1.1 is fmov.s &0x80000000,%fp0 # load a -ZERO
9181 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
9182 1.1 is rts
9183 1.1 is fdiv_zero_load_p:
9184 1.1 is fmov.s &0x00000000,%fp0 # load a +ZERO
9185 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
9186 1.1 is rts
9187 1.1 is
9188 1.1 is #
9189 1.1 is # The destination was In Range and the source was a ZERO. The result,
9190 1.1 is # therefore, is an INF w/ the proper sign.
9191 1.1 is # So, determine the sign and return a new INF (w/ the j-bit cleared).
9192 1.1 is #
9193 1.1 is global fdiv_inf_load # global for fsgldiv
9194 1.1 is fdiv_inf_load:
9195 1.1 is ori.w &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ
9196 1.1 is mov.b SRC_EX(%a0),%d0 # load both signs
9197 1.1 is mov.b DST_EX(%a1),%d1
9198 1.1 is eor.b %d0,%d1
9199 1.1 is bpl.b fdiv_inf_load_p # result is positive
9200 1.1 is fmov.s &0xff800000,%fp0 # make result -INF
9201 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
9202 1.1 is rts
9203 1.1 is fdiv_inf_load_p:
9204 1.1 is fmov.s &0x7f800000,%fp0 # make result +INF
9205 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF
9206 1.1 is rts
9207 1.1 is
9208 1.1 is #
9209 1.1 is # The destination was an INF w/ an In Range or ZERO source, the result is
9210 1.1 is # an INF w/ the proper sign.
9211 1.1 is # The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the
9212 1.1 is # dst INF is set, then then j-bit of the result INF is also set).
9213 1.1 is #
9214 1.1 is global fdiv_inf_dst # global for fsgldiv
9215 1.1 is fdiv_inf_dst:
9216 1.1 is mov.b DST_EX(%a1),%d0 # load both signs
9217 1.1 is mov.b SRC_EX(%a0),%d1
9218 1.1 is eor.b %d0,%d1
9219 1.1 is bpl.b fdiv_inf_dst_p # result is positive
9220 1.1 is
9221 1.1 is fmovm.x DST(%a1),&0x80 # return result in fp0
9222 1.1 is fabs.x %fp0 # clear sign bit
9223 1.1 is fneg.x %fp0 # set sign bit
9224 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG
9225 1.1 is rts
9226 1.1 is
9227 1.1 is fdiv_inf_dst_p:
9228 1.1 is fmovm.x DST(%a1),&0x80 # return result in fp0
9229 1.1 is fabs.x %fp0 # return positive INF
9230 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF
9231 1.1 is rts
9232 1.1 is
9233 1.1 is #########################################################################
9234 1.1 is # XDEF **************************************************************** #
9235 1.1 is # fneg(): emulates the fneg instruction #
9236 1.1 is # fsneg(): emulates the fsneg instruction #
9237 1.1 is # fdneg(): emulates the fdneg instruction #
9238 1.1 is # #
9239 1.1 is # XREF **************************************************************** #
9240 1.1 is # norm() - normalize a denorm to provide EXOP #
9241 1.1 is # scale_to_zero_src() - scale sgl/dbl source exponent #
9242 1.1 is # ovf_res() - return default overflow result #
9243 1.1 is # unf_res() - return default underflow result #
9244 1.1 is # res_qnan_1op() - return QNAN result #
9245 1.1 is # res_snan_1op() - return SNAN result #
9246 1.1 is # #
9247 1.1 is # INPUT *************************************************************** #
9248 1.1 is # a0 = pointer to extended precision source operand #
9249 1.1 is # d0 = rnd prec,mode #
9250 1.1 is # #
9251 1.1 is # OUTPUT ************************************************************** #
9252 1.1 is # fp0 = result #
9253 1.1 is # fp1 = EXOP (if exception occurred) #
9254 1.1 is # #
9255 1.1 is # ALGORITHM *********************************************************** #
9256 1.1 is # Handle NANs, zeroes, and infinities as special cases. Separate #
9257 1.1 is # norms/denorms into ext/sgl/dbl precisions. Extended precision can be #
9258 1.1 is # emulated by simply setting sign bit. Sgl/dbl operands must be scaled #
9259 1.1 is # and an actual fneg performed to see if overflow/underflow would have #
9260 1.1 is # occurred. If so, return default underflow/overflow result. Else, #
9261 1.1 is # scale the result exponent and return result. FPSR gets set based on #
9262 1.1 is # the result value. #
9263 1.1 is # #
9264 1.1 is #########################################################################
9265 1.1 is
9266 1.1 is global fsneg
9267 1.1 is fsneg:
9268 1.1 is andi.b &0x30,%d0 # clear rnd prec
9269 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision
9270 1.1 is bra.b fneg
9271 1.1 is
9272 1.1 is global fdneg
9273 1.1 is fdneg:
9274 1.1 is andi.b &0x30,%d0 # clear rnd prec
9275 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
9276 1.1 is
9277 1.1 is global fneg
9278 1.1 is fneg:
9279 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
9280 1.1 is mov.b STAG(%a6),%d1
9281 1.1 is bne.w fneg_not_norm # optimize on non-norm input
9282 1.1 is
9283 1.1 is #
9284 1.1 is # NEGATE SIGN : norms and denorms ONLY!
9285 1.1 is #
9286 1.1 is fneg_norm:
9287 1.1 is andi.b &0xc0,%d0 # is precision extended?
9288 1.1 is bne.w fneg_not_ext # no; go handle sgl or dbl
9289 1.1 is
9290 1.1 is #
9291 1.1 is # precision selected is extended. so...we can not get an underflow
9292 1.1 is # or overflow because of rounding to the correct precision. so...
9293 1.1 is # skip the scaling and unscaling...
9294 1.1 is #
9295 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9296 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9297 1.1 is mov.w SRC_EX(%a0),%d0
9298 1.1 is eori.w &0x8000,%d0 # negate sign
9299 1.1 is bpl.b fneg_norm_load # sign is positive
9300 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9301 1.1 is fneg_norm_load:
9302 1.1 is mov.w %d0,FP_SCR0_EX(%a6)
9303 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9304 1.1 is rts
9305 1.1 is
9306 1.1 is #
9307 1.1 is # for an extended precision DENORM, the UNFL exception bit is set
9308 1.1 is # the accrued bit is NOT set in this instance(no inexactness!)
9309 1.1 is #
9310 1.1 is fneg_denorm:
9311 1.1 is andi.b &0xc0,%d0 # is precision extended?
9312 1.1 is bne.b fneg_not_ext # no; go handle sgl or dbl
9313 1.1 is
9314 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9315 1.1 is
9316 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9317 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9318 1.1 is mov.w SRC_EX(%a0),%d0
9319 1.1 is eori.w &0x8000,%d0 # negate sign
9320 1.1 is bpl.b fneg_denorm_done # no
9321 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit
9322 1.1 is fneg_denorm_done:
9323 1.1 is mov.w %d0,FP_SCR0_EX(%a6)
9324 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9325 1.1 is
9326 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9327 1.1 is bne.b fneg_ext_unfl_ena # yes
9328 1.1 is rts
9329 1.1 is
9330 1.1 is #
9331 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR.
9332 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative
9333 1.1 is # exponent and insert back into the operand.
9334 1.1 is #
9335 1.1 is fneg_ext_unfl_ena:
9336 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
9337 1.1 is bsr.l norm # normalize result
9338 1.1 is neg.w %d0 # new exponent = -(shft val)
9339 1.1 is addi.w &0x6000,%d0 # add new bias to exponent
9340 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
9341 1.1 is andi.w &0x8000,%d1 # keep old sign
9342 1.1 is andi.w &0x7fff,%d0 # clear sign position
9343 1.1 is or.w %d1,%d0 # concat old sign, new exponent
9344 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
9345 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9346 1.1 is rts
9347 1.1 is
9348 1.1 is #
9349 1.1 is # operand is either single or double
9350 1.1 is #
9351 1.1 is fneg_not_ext:
9352 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
9353 1.1 is bne.b fneg_dbl
9354 1.1 is
9355 1.1 is #
9356 1.1 is # operand is to be rounded to single precision
9357 1.1 is #
9358 1.1 is fneg_sgl:
9359 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9360 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9361 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9362 1.1 is bsr.l scale_to_zero_src # calculate scale factor
9363 1.1 is
9364 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
9365 1.1 is bge.w fneg_sd_unfl # yes; go handle underflow
9366 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
9367 1.1 is beq.w fneg_sd_may_ovfl # maybe; go check
9368 1.1 is blt.w fneg_sd_ovfl # yes; go handle overflow
9369 1.1 is
9370 1.1 is #
9371 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file
9372 1.1 is #
9373 1.1 is fneg_sd_normal:
9374 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9375 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9376 1.1 is
9377 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation
9378 1.1 is
9379 1.1 is fmov.l %fpsr,%d1 # save FPSR
9380 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9381 1.1 is
9382 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
9383 1.1 is
9384 1.1 is fneg_sd_normal_exit:
9385 1.1 is mov.l %d2,-(%sp) # save d2
9386 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
9387 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
9388 1.1 is mov.w %d1,%d2 # make a copy
9389 1.1 is andi.l &0x7fff,%d1 # strip sign
9390 1.1 is sub.l %d0,%d1 # add scale factor
9391 1.1 is andi.w &0x8000,%d2 # keep old sign
9392 1.1 is or.w %d1,%d2 # concat old sign,new exp
9393 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
9394 1.1 is mov.l (%sp)+,%d2 # restore d2
9395 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9396 1.1 is rts
9397 1.1 is
9398 1.1 is #
9399 1.1 is # operand is to be rounded to double precision
9400 1.1 is #
9401 1.1 is fneg_dbl:
9402 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9403 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9404 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9405 1.1 is bsr.l scale_to_zero_src # calculate scale factor
9406 1.1 is
9407 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
9408 1.1 is bge.b fneg_sd_unfl # yes; go handle underflow
9409 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
9410 1.1 is beq.w fneg_sd_may_ovfl # maybe; go check
9411 1.1 is blt.w fneg_sd_ovfl # yes; go handle overflow
9412 1.1 is bra.w fneg_sd_normal # no; ho handle normalized op
9413 1.1 is
9414 1.1 is #
9415 1.1 is # operand WILL underflow when moved in to the fp register file
9416 1.1 is #
9417 1.1 is fneg_sd_unfl:
9418 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9419 1.1 is
9420 1.1 is eori.b &0x80,FP_SCR0_EX(%a6) # negate sign
9421 1.1 is bpl.b fneg_sd_unfl_tst
9422 1.1 is bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit
9423 1.1 is
9424 1.1 is # if underflow or inexact is enabled, go calculate EXOP first.
9425 1.1 is fneg_sd_unfl_tst:
9426 1.1 is mov.b FPCR_ENABLE(%a6),%d1
9427 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
9428 1.1 is bne.b fneg_sd_unfl_ena # yes
9429 1.1 is
9430 1.1 is fneg_sd_unfl_dis:
9431 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
9432 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
9433 1.1 is bsr.l unf_res # calculate default result
9434 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z'
9435 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9436 1.1 is rts
9437 1.1 is
9438 1.1 is #
9439 1.1 is # operand will underflow AND underflow is enabled.
9440 1.1 is # therefore, we must return the result rounded to extended precision.
9441 1.1 is #
9442 1.1 is fneg_sd_unfl_ena:
9443 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
9444 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
9445 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
9446 1.1 is
9447 1.1 is mov.l %d2,-(%sp) # save d2
9448 1.1 is mov.l %d1,%d2 # make a copy
9449 1.1 is andi.l &0x7fff,%d1 # strip sign
9450 1.1 is andi.w &0x8000,%d2 # keep old sign
9451 1.1 is sub.l %d0,%d1 # subtract scale factor
9452 1.1 is addi.l &0x6000,%d1 # add new bias
9453 1.1 is andi.w &0x7fff,%d1
9454 1.1 is or.w %d2,%d1 # concat new sign,new exp
9455 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
9456 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
9457 1.1 is mov.l (%sp)+,%d2 # restore d2
9458 1.1 is bra.b fneg_sd_unfl_dis
9459 1.1 is
9460 1.1 is #
9461 1.1 is # operand WILL overflow.
9462 1.1 is #
9463 1.1 is fneg_sd_ovfl:
9464 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9465 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9466 1.1 is
9467 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation
9468 1.1 is
9469 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9470 1.1 is fmov.l %fpsr,%d1 # save FPSR
9471 1.1 is
9472 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
9473 1.1 is
9474 1.1 is fneg_sd_ovfl_tst:
9475 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
9476 1.1 is
9477 1.1 is mov.b FPCR_ENABLE(%a6),%d1
9478 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
9479 1.1 is bne.b fneg_sd_ovfl_ena # yes
9480 1.1 is
9481 1.1 is #
9482 1.1 is # OVFL is not enabled; therefore, we must create the default result by
9483 1.1 is # calling ovf_res().
9484 1.1 is #
9485 1.1 is fneg_sd_ovfl_dis:
9486 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
9487 1.1 is sne %d1 # set sign param accordingly
9488 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode
9489 1.1 is bsr.l ovf_res # calculate default result
9490 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
9491 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
9492 1.1 is rts
9493 1.1 is
9494 1.1 is #
9495 1.1 is # OVFL is enabled.
9496 1.1 is # the INEX2 bit has already been updated by the round to the correct precision.
9497 1.1 is # now, round to extended(and don't alter the FPSR).
9498 1.1 is #
9499 1.1 is fneg_sd_ovfl_ena:
9500 1.1 is mov.l %d2,-(%sp) # save d2
9501 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
9502 1.1 is mov.l %d1,%d2 # make a copy
9503 1.1 is andi.l &0x7fff,%d1 # strip sign
9504 1.1 is andi.w &0x8000,%d2 # keep old sign
9505 1.1 is sub.l %d0,%d1 # add scale factor
9506 1.1 is subi.l &0x6000,%d1 # subtract bias
9507 1.1 is andi.w &0x7fff,%d1
9508 1.1 is or.w %d2,%d1 # concat sign,exp
9509 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
9510 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9511 1.1 is mov.l (%sp)+,%d2 # restore d2
9512 1.1 is bra.b fneg_sd_ovfl_dis
9513 1.1 is
9514 1.1 is #
9515 1.1 is # the move in MAY underflow. so...
9516 1.1 is #
9517 1.1 is fneg_sd_may_ovfl:
9518 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9519 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9520 1.1 is
9521 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation
9522 1.1 is
9523 1.1 is fmov.l %fpsr,%d1 # save status
9524 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9525 1.1 is
9526 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
9527 1.1 is
9528 1.1 is fabs.x %fp0,%fp1 # make a copy of result
9529 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b?
9530 1.1 is fbge.w fneg_sd_ovfl_tst # yes; overflow has occurred
9531 1.1 is
9532 1.1 is # no, it didn't overflow; we have correct result
9533 1.1 is bra.w fneg_sd_normal_exit
9534 1.1 is
9535 1.1 is ##########################################################################
9536 1.1 is
9537 1.1 is #
9538 1.1 is # input is not normalized; what is it?
9539 1.1 is #
9540 1.1 is fneg_not_norm:
9541 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
9542 1.1 is beq.w fneg_denorm
9543 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
9544 1.1 is beq.l res_snan_1op
9545 1.1 is cmpi.b %d1,&QNAN # weed out QNAN
9546 1.1 is beq.l res_qnan_1op
9547 1.1 is
9548 1.1 is #
9549 1.1 is # do the fneg; at this point, only possible ops are ZERO and INF.
9550 1.1 is # use fneg to determine ccodes.
9551 1.1 is # prec:mode should be zero at this point but it won't affect answer anyways.
9552 1.1 is #
9553 1.1 is fneg.x SRC_EX(%a0),%fp0 # do fneg
9554 1.1 is fmov.l %fpsr,%d0
9555 1.1 is rol.l &0x8,%d0 # put ccodes in lo byte
9556 1.1 is mov.b %d0,FPSR_CC(%a6) # insert correct ccodes
9557 1.1 is rts
9558 1.1 is
9559 1.1 is #########################################################################
9560 1.1 is # XDEF **************************************************************** #
9561 1.1 is # ftst(): emulates the ftest instruction #
9562 1.1 is # #
9563 1.1 is # XREF **************************************************************** #
9564 1.1 is # res{s,q}nan_1op() - set NAN result for monadic instruction #
9565 1.1 is # #
9566 1.1 is # INPUT *************************************************************** #
9567 1.1 is # a0 = pointer to extended precision source operand #
9568 1.1 is # #
9569 1.1 is # OUTPUT ************************************************************** #
9570 1.1 is # none #
9571 1.1 is # #
9572 1.1 is # ALGORITHM *********************************************************** #
9573 1.1 is # Check the source operand tag (STAG) and set the FPCR according #
9574 1.1 is # to the operand type and sign. #
9575 1.1 is # #
9576 1.1 is #########################################################################
9577 1.1 is
9578 1.1 is global ftst
9579 1.1 is ftst:
9580 1.1 is mov.b STAG(%a6),%d1
9581 1.1 is bne.b ftst_not_norm # optimize on non-norm input
9582 1.1 is
9583 1.1 is #
9584 1.1 is # Norm:
9585 1.1 is #
9586 1.1 is ftst_norm:
9587 1.1 is tst.b SRC_EX(%a0) # is operand negative?
9588 1.1 is bmi.b ftst_norm_m # yes
9589 1.1 is rts
9590 1.1 is ftst_norm_m:
9591 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9592 1.1 is rts
9593 1.1 is
9594 1.1 is #
9595 1.1 is # input is not normalized; what is it?
9596 1.1 is #
9597 1.1 is ftst_not_norm:
9598 1.1 is cmpi.b %d1,&ZERO # weed out ZERO
9599 1.1 is beq.b ftst_zero
9600 1.1 is cmpi.b %d1,&INF # weed out INF
9601 1.1 is beq.b ftst_inf
9602 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
9603 1.1 is beq.l res_snan_1op
9604 1.1 is cmpi.b %d1,&QNAN # weed out QNAN
9605 1.1 is beq.l res_qnan_1op
9606 1.1 is
9607 1.1 is #
9608 1.1 is # Denorm:
9609 1.1 is #
9610 1.1 is ftst_denorm:
9611 1.1 is tst.b SRC_EX(%a0) # is operand negative?
9612 1.1 is bmi.b ftst_denorm_m # yes
9613 1.1 is rts
9614 1.1 is ftst_denorm_m:
9615 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9616 1.1 is rts
9617 1.1 is
9618 1.1 is #
9619 1.1 is # Infinity:
9620 1.1 is #
9621 1.1 is ftst_inf:
9622 1.1 is tst.b SRC_EX(%a0) # is operand negative?
9623 1.1 is bmi.b ftst_inf_m # yes
9624 1.1 is ftst_inf_p:
9625 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9626 1.1 is rts
9627 1.1 is ftst_inf_m:
9628 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits
9629 1.1 is rts
9630 1.1 is
9631 1.1 is #
9632 1.1 is # Zero:
9633 1.1 is #
9634 1.1 is ftst_zero:
9635 1.1 is tst.b SRC_EX(%a0) # is operand negative?
9636 1.1 is bmi.b ftst_zero_m # yes
9637 1.1 is ftst_zero_p:
9638 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9639 1.1 is rts
9640 1.1 is ftst_zero_m:
9641 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9642 1.1 is rts
9643 1.1 is
9644 1.1 is #########################################################################
9645 1.1 is # XDEF **************************************************************** #
9646 1.1 is # fint(): emulates the fint instruction #
9647 1.1 is # #
9648 1.1 is # XREF **************************************************************** #
9649 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation #
9650 1.1 is # #
9651 1.1 is # INPUT *************************************************************** #
9652 1.1 is # a0 = pointer to extended precision source operand #
9653 1.1 is # d0 = round precision/mode #
9654 1.1 is # #
9655 1.1 is # OUTPUT ************************************************************** #
9656 1.1 is # fp0 = result #
9657 1.1 is # #
9658 1.1 is # ALGORITHM *********************************************************** #
9659 1.1 is # Separate according to operand type. Unnorms don't pass through #
9660 1.1 is # here. For norms, load the rounding mode/prec, execute a "fint", then #
9661 1.1 is # store the resulting FPSR bits. #
9662 1.1 is # For denorms, force the j-bit to a one and do the same as for #
9663 1.1 is # norms. Denorms are so low that the answer will either be a zero or a #
9664 1.1 is # one. #
9665 1.1 is # For zeroes/infs/NANs, return the same while setting the FPSR #
9666 1.1 is # as appropriate. #
9667 1.1 is # #
9668 1.1 is #########################################################################
9669 1.1 is
9670 1.1 is global fint
9671 1.1 is fint:
9672 1.1 is mov.b STAG(%a6),%d1
9673 1.1 is bne.b fint_not_norm # optimize on non-norm input
9674 1.1 is
9675 1.1 is #
9676 1.1 is # Norm:
9677 1.1 is #
9678 1.1 is fint_norm:
9679 1.1 is andi.b &0x30,%d0 # set prec = ext
9680 1.1 is
9681 1.1 is fmov.l %d0,%fpcr # set FPCR
9682 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9683 1.1 is
9684 1.1 is fint.x SRC(%a0),%fp0 # execute fint
9685 1.1 is
9686 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9687 1.1 is fmov.l %fpsr,%d0 # save FPSR
9688 1.1 is or.l %d0,USER_FPSR(%a6) # set exception bits
9689 1.1 is
9690 1.1 is rts
9691 1.1 is
9692 1.1 is #
9693 1.1 is # input is not normalized; what is it?
9694 1.1 is #
9695 1.1 is fint_not_norm:
9696 1.1 is cmpi.b %d1,&ZERO # weed out ZERO
9697 1.1 is beq.b fint_zero
9698 1.1 is cmpi.b %d1,&INF # weed out INF
9699 1.1 is beq.b fint_inf
9700 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
9701 1.1 is beq.b fint_denorm
9702 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
9703 1.1 is beq.l res_snan_1op
9704 1.1 is bra.l res_qnan_1op # weed out QNAN
9705 1.1 is
9706 1.1 is #
9707 1.1 is # Denorm:
9708 1.1 is #
9709 1.1 is # for DENORMs, the result will be either (+/-)ZERO or (+/-)1.
9710 1.1 is # also, the INEX2 and AINEX exception bits will be set.
9711 1.1 is # so, we could either set these manually or force the DENORM
9712 1.1 is # to a very small NORM and ship it to the NORM routine.
9713 1.1 is # I do the latter.
9714 1.1 is #
9715 1.1 is fint_denorm:
9716 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9717 1.1 is mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM
9718 1.1 is lea FP_SCR0(%a6),%a0
9719 1.1 is bra.b fint_norm
9720 1.1 is
9721 1.1 is #
9722 1.1 is # Zero:
9723 1.1 is #
9724 1.1 is fint_zero:
9725 1.1 is tst.b SRC_EX(%a0) # is ZERO negative?
9726 1.1 is bmi.b fint_zero_m # yes
9727 1.1 is fint_zero_p:
9728 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO in fp0
9729 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
9730 1.1 is rts
9731 1.1 is fint_zero_m:
9732 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO in fp0
9733 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9734 1.1 is rts
9735 1.1 is
9736 1.1 is #
9737 1.1 is # Infinity:
9738 1.1 is #
9739 1.1 is fint_inf:
9740 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0
9741 1.1 is tst.b SRC_EX(%a0) # is INF negative?
9742 1.1 is bmi.b fint_inf_m # yes
9743 1.1 is fint_inf_p:
9744 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9745 1.1 is rts
9746 1.1 is fint_inf_m:
9747 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9748 1.1 is rts
9749 1.1 is
9750 1.1 is #########################################################################
9751 1.1 is # XDEF **************************************************************** #
9752 1.1 is # fintrz(): emulates the fintrz instruction #
9753 1.1 is # #
9754 1.1 is # XREF **************************************************************** #
9755 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation #
9756 1.1 is # #
9757 1.1 is # INPUT *************************************************************** #
9758 1.1 is # a0 = pointer to extended precision source operand #
9759 1.1 is # d0 = round precision/mode #
9760 1.1 is # #
9761 1.1 is # OUTPUT ************************************************************** #
9762 1.1 is # fp0 = result #
9763 1.1 is # #
9764 1.1 is # ALGORITHM *********************************************************** #
9765 1.1 is # Separate according to operand type. Unnorms don't pass through #
9766 1.1 is # here. For norms, load the rounding mode/prec, execute a "fintrz", #
9767 1.1 is # then store the resulting FPSR bits. #
9768 1.1 is # For denorms, force the j-bit to a one and do the same as for #
9769 1.1 is # norms. Denorms are so low that the answer will either be a zero or a #
9770 1.1 is # one. #
9771 1.1 is # For zeroes/infs/NANs, return the same while setting the FPSR #
9772 1.1 is # as appropriate. #
9773 1.1 is # #
9774 1.1 is #########################################################################
9775 1.1 is
9776 1.1 is global fintrz
9777 1.1 is fintrz:
9778 1.1 is mov.b STAG(%a6),%d1
9779 1.1 is bne.b fintrz_not_norm # optimize on non-norm input
9780 1.1 is
9781 1.1 is #
9782 1.1 is # Norm:
9783 1.1 is #
9784 1.1 is fintrz_norm:
9785 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9786 1.1 is
9787 1.1 is fintrz.x SRC(%a0),%fp0 # execute fintrz
9788 1.1 is
9789 1.1 is fmov.l %fpsr,%d0 # save FPSR
9790 1.1 is or.l %d0,USER_FPSR(%a6) # set exception bits
9791 1.1 is
9792 1.1 is rts
9793 1.1 is
9794 1.1 is #
9795 1.1 is # input is not normalized; what is it?
9796 1.1 is #
9797 1.1 is fintrz_not_norm:
9798 1.1 is cmpi.b %d1,&ZERO # weed out ZERO
9799 1.1 is beq.b fintrz_zero
9800 1.1 is cmpi.b %d1,&INF # weed out INF
9801 1.1 is beq.b fintrz_inf
9802 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
9803 1.1 is beq.b fintrz_denorm
9804 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
9805 1.1 is beq.l res_snan_1op
9806 1.1 is bra.l res_qnan_1op # weed out QNAN
9807 1.1 is
9808 1.1 is #
9809 1.1 is # Denorm:
9810 1.1 is #
9811 1.1 is # for DENORMs, the result will be (+/-)ZERO.
9812 1.1 is # also, the INEX2 and AINEX exception bits will be set.
9813 1.1 is # so, we could either set these manually or force the DENORM
9814 1.1 is # to a very small NORM and ship it to the NORM routine.
9815 1.1 is # I do the latter.
9816 1.1 is #
9817 1.1 is fintrz_denorm:
9818 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9819 1.1 is mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM
9820 1.1 is lea FP_SCR0(%a6),%a0
9821 1.1 is bra.b fintrz_norm
9822 1.1 is
9823 1.1 is #
9824 1.1 is # Zero:
9825 1.1 is #
9826 1.1 is fintrz_zero:
9827 1.1 is tst.b SRC_EX(%a0) # is ZERO negative?
9828 1.1 is bmi.b fintrz_zero_m # yes
9829 1.1 is fintrz_zero_p:
9830 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO in fp0
9831 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
9832 1.1 is rts
9833 1.1 is fintrz_zero_m:
9834 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO in fp0
9835 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9836 1.1 is rts
9837 1.1 is
9838 1.1 is #
9839 1.1 is # Infinity:
9840 1.1 is #
9841 1.1 is fintrz_inf:
9842 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0
9843 1.1 is tst.b SRC_EX(%a0) # is INF negative?
9844 1.1 is bmi.b fintrz_inf_m # yes
9845 1.1 is fintrz_inf_p:
9846 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9847 1.1 is rts
9848 1.1 is fintrz_inf_m:
9849 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9850 1.1 is rts
9851 1.1 is
9852 1.1 is #########################################################################
9853 1.1 is # XDEF **************************************************************** #
9854 1.1 is # fabs(): emulates the fabs instruction #
9855 1.1 is # fsabs(): emulates the fsabs instruction #
9856 1.1 is # fdabs(): emulates the fdabs instruction #
9857 1.1 is # #
9858 1.1 is # XREF **************************************************************** #
9859 1.1 is # norm() - normalize denorm mantissa to provide EXOP #
9860 1.1 is # scale_to_zero_src() - make exponent. = 0; get scale factor #
9861 1.1 is # unf_res() - calculate underflow result #
9862 1.1 is # ovf_res() - calculate overflow result #
9863 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation #
9864 1.1 is # #
9865 1.1 is # INPUT *************************************************************** #
9866 1.1 is # a0 = pointer to extended precision source operand #
9867 1.1 is # d0 = rnd precision/mode #
9868 1.1 is # #
9869 1.1 is # OUTPUT ************************************************************** #
9870 1.1 is # fp0 = result #
9871 1.1 is # fp1 = EXOP (if exception occurred) #
9872 1.1 is # #
9873 1.1 is # ALGORITHM *********************************************************** #
9874 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
9875 1.1 is # norms into extended, single, and double precision. #
9876 1.1 is # Simply clear sign for extended precision norm. Ext prec denorm #
9877 1.1 is # gets an EXOP created for it since it's an underflow. #
9878 1.1 is # Double and single precision can overflow and underflow. First, #
9879 1.1 is # scale the operand such that the exponent is zero. Perform an "fabs" #
9880 1.1 is # using the correct rnd mode/prec. Check to see if the original #
9881 1.1 is # exponent would take an exception. If so, use unf_res() or ovf_res() #
9882 1.1 is # to calculate the default result. Also, create the EXOP for the #
9883 1.1 is # exceptional case. If no exception should occur, insert the correct #
9884 1.1 is # result exponent and return. #
9885 1.1 is # Unnorms don't pass through here. #
9886 1.1 is # #
9887 1.1 is #########################################################################
9888 1.1 is
9889 1.1 is global fsabs
9890 1.1 is fsabs:
9891 1.1 is andi.b &0x30,%d0 # clear rnd prec
9892 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision
9893 1.1 is bra.b fabs
9894 1.1 is
9895 1.1 is global fdabs
9896 1.1 is fdabs:
9897 1.1 is andi.b &0x30,%d0 # clear rnd prec
9898 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision
9899 1.1 is
9900 1.1 is global fabs
9901 1.1 is fabs:
9902 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
9903 1.1 is mov.b STAG(%a6),%d1
9904 1.1 is bne.w fabs_not_norm # optimize on non-norm input
9905 1.1 is
9906 1.1 is #
9907 1.1 is # ABSOLUTE VALUE: norms and denorms ONLY!
9908 1.1 is #
9909 1.1 is fabs_norm:
9910 1.1 is andi.b &0xc0,%d0 # is precision extended?
9911 1.1 is bne.b fabs_not_ext # no; go handle sgl or dbl
9912 1.1 is
9913 1.1 is #
9914 1.1 is # precision selected is extended. so...we can not get an underflow
9915 1.1 is # or overflow because of rounding to the correct precision. so...
9916 1.1 is # skip the scaling and unscaling...
9917 1.1 is #
9918 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9919 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9920 1.1 is mov.w SRC_EX(%a0),%d1
9921 1.1 is bclr &15,%d1 # force absolute value
9922 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert exponent
9923 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9924 1.1 is rts
9925 1.1 is
9926 1.1 is #
9927 1.1 is # for an extended precision DENORM, the UNFL exception bit is set
9928 1.1 is # the accrued bit is NOT set in this instance(no inexactness!)
9929 1.1 is #
9930 1.1 is fabs_denorm:
9931 1.1 is andi.b &0xc0,%d0 # is precision extended?
9932 1.1 is bne.b fabs_not_ext # no
9933 1.1 is
9934 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9935 1.1 is
9936 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9937 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9938 1.1 is mov.w SRC_EX(%a0),%d0
9939 1.1 is bclr &15,%d0 # clear sign
9940 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert exponent
9941 1.1 is
9942 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9943 1.1 is
9944 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9945 1.1 is bne.b fabs_ext_unfl_ena
9946 1.1 is rts
9947 1.1 is
9948 1.1 is #
9949 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR.
9950 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative
9951 1.1 is # exponent and insert back into the operand.
9952 1.1 is #
9953 1.1 is fabs_ext_unfl_ena:
9954 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand
9955 1.1 is bsr.l norm # normalize result
9956 1.1 is neg.w %d0 # new exponent = -(shft val)
9957 1.1 is addi.w &0x6000,%d0 # add new bias to exponent
9958 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
9959 1.1 is andi.w &0x8000,%d1 # keep old sign
9960 1.1 is andi.w &0x7fff,%d0 # clear sign position
9961 1.1 is or.w %d1,%d0 # concat old sign, new exponent
9962 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
9963 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9964 1.1 is rts
9965 1.1 is
9966 1.1 is #
9967 1.1 is # operand is either single or double
9968 1.1 is #
9969 1.1 is fabs_not_ext:
9970 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
9971 1.1 is bne.b fabs_dbl
9972 1.1 is
9973 1.1 is #
9974 1.1 is # operand is to be rounded to single precision
9975 1.1 is #
9976 1.1 is fabs_sgl:
9977 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9978 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9979 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9980 1.1 is bsr.l scale_to_zero_src # calculate scale factor
9981 1.1 is
9982 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
9983 1.1 is bge.w fabs_sd_unfl # yes; go handle underflow
9984 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
9985 1.1 is beq.w fabs_sd_may_ovfl # maybe; go check
9986 1.1 is blt.w fabs_sd_ovfl # yes; go handle overflow
9987 1.1 is
9988 1.1 is #
9989 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file
9990 1.1 is #
9991 1.1 is fabs_sd_normal:
9992 1.1 is fmov.l &0x0,%fpsr # clear FPSR
9993 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
9994 1.1 is
9995 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute
9996 1.1 is
9997 1.1 is fmov.l %fpsr,%d1 # save FPSR
9998 1.1 is fmov.l &0x0,%fpcr # clear FPCR
9999 1.1 is
10000 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10001 1.1 is
10002 1.1 is fabs_sd_normal_exit:
10003 1.1 is mov.l %d2,-(%sp) # save d2
10004 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
10005 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
10006 1.1 is mov.l %d1,%d2 # make a copy
10007 1.1 is andi.l &0x7fff,%d1 # strip sign
10008 1.1 is sub.l %d0,%d1 # add scale factor
10009 1.1 is andi.w &0x8000,%d2 # keep old sign
10010 1.1 is or.w %d1,%d2 # concat old sign,new exp
10011 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
10012 1.1 is mov.l (%sp)+,%d2 # restore d2
10013 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10014 1.1 is rts
10015 1.1 is
10016 1.1 is #
10017 1.1 is # operand is to be rounded to double precision
10018 1.1 is #
10019 1.1 is fabs_dbl:
10020 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10021 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10022 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10023 1.1 is bsr.l scale_to_zero_src # calculate scale factor
10024 1.1 is
10025 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
10026 1.1 is bge.b fabs_sd_unfl # yes; go handle underflow
10027 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
10028 1.1 is beq.w fabs_sd_may_ovfl # maybe; go check
10029 1.1 is blt.w fabs_sd_ovfl # yes; go handle overflow
10030 1.1 is bra.w fabs_sd_normal # no; ho handle normalized op
10031 1.1 is
10032 1.1 is #
10033 1.1 is # operand WILL underflow when moved in to the fp register file
10034 1.1 is #
10035 1.1 is fabs_sd_unfl:
10036 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10037 1.1 is
10038 1.1 is bclr &0x7,FP_SCR0_EX(%a6) # force absolute value
10039 1.1 is
10040 1.1 is # if underflow or inexact is enabled, go calculate EXOP first.
10041 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10042 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10043 1.1 is bne.b fabs_sd_unfl_ena # yes
10044 1.1 is
10045 1.1 is fabs_sd_unfl_dis:
10046 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
10047 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10048 1.1 is bsr.l unf_res # calculate default result
10049 1.1 is or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode
10050 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10051 1.1 is rts
10052 1.1 is
10053 1.1 is #
10054 1.1 is # operand will underflow AND underflow is enabled.
10055 1.1 is # therefore, we must return the result rounded to extended precision.
10056 1.1 is #
10057 1.1 is fabs_sd_unfl_ena:
10058 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
10059 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
10060 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
10061 1.1 is
10062 1.1 is mov.l %d2,-(%sp) # save d2
10063 1.1 is mov.l %d1,%d2 # make a copy
10064 1.1 is andi.l &0x7fff,%d1 # strip sign
10065 1.1 is andi.w &0x8000,%d2 # keep old sign
10066 1.1 is sub.l %d0,%d1 # subtract scale factor
10067 1.1 is addi.l &0x6000,%d1 # add new bias
10068 1.1 is andi.w &0x7fff,%d1
10069 1.1 is or.w %d2,%d1 # concat new sign,new exp
10070 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
10071 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
10072 1.1 is mov.l (%sp)+,%d2 # restore d2
10073 1.1 is bra.b fabs_sd_unfl_dis
10074 1.1 is
10075 1.1 is #
10076 1.1 is # operand WILL overflow.
10077 1.1 is #
10078 1.1 is fabs_sd_ovfl:
10079 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10080 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10081 1.1 is
10082 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute
10083 1.1 is
10084 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10085 1.1 is fmov.l %fpsr,%d1 # save FPSR
10086 1.1 is
10087 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10088 1.1 is
10089 1.1 is fabs_sd_ovfl_tst:
10090 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
10091 1.1 is
10092 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10093 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
10094 1.1 is bne.b fabs_sd_ovfl_ena # yes
10095 1.1 is
10096 1.1 is #
10097 1.1 is # OVFL is not enabled; therefore, we must create the default result by
10098 1.1 is # calling ovf_res().
10099 1.1 is #
10100 1.1 is fabs_sd_ovfl_dis:
10101 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
10102 1.1 is sne %d1 # set sign param accordingly
10103 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode
10104 1.1 is bsr.l ovf_res # calculate default result
10105 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
10106 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
10107 1.1 is rts
10108 1.1 is
10109 1.1 is #
10110 1.1 is # OVFL is enabled.
10111 1.1 is # the INEX2 bit has already been updated by the round to the correct precision.
10112 1.1 is # now, round to extended(and don't alter the FPSR).
10113 1.1 is #
10114 1.1 is fabs_sd_ovfl_ena:
10115 1.1 is mov.l %d2,-(%sp) # save d2
10116 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10117 1.1 is mov.l %d1,%d2 # make a copy
10118 1.1 is andi.l &0x7fff,%d1 # strip sign
10119 1.1 is andi.w &0x8000,%d2 # keep old sign
10120 1.1 is sub.l %d0,%d1 # add scale factor
10121 1.1 is subi.l &0x6000,%d1 # subtract bias
10122 1.1 is andi.w &0x7fff,%d1
10123 1.1 is or.w %d2,%d1 # concat sign,exp
10124 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10125 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10126 1.1 is mov.l (%sp)+,%d2 # restore d2
10127 1.1 is bra.b fabs_sd_ovfl_dis
10128 1.1 is
10129 1.1 is #
10130 1.1 is # the move in MAY underflow. so...
10131 1.1 is #
10132 1.1 is fabs_sd_may_ovfl:
10133 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10134 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10135 1.1 is
10136 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute
10137 1.1 is
10138 1.1 is fmov.l %fpsr,%d1 # save status
10139 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10140 1.1 is
10141 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10142 1.1 is
10143 1.1 is fabs.x %fp0,%fp1 # make a copy of result
10144 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b?
10145 1.1 is fbge.w fabs_sd_ovfl_tst # yes; overflow has occurred
10146 1.1 is
10147 1.1 is # no, it didn't overflow; we have correct result
10148 1.1 is bra.w fabs_sd_normal_exit
10149 1.1 is
10150 1.1 is ##########################################################################
10151 1.1 is
10152 1.1 is #
10153 1.1 is # input is not normalized; what is it?
10154 1.1 is #
10155 1.1 is fabs_not_norm:
10156 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
10157 1.1 is beq.w fabs_denorm
10158 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
10159 1.1 is beq.l res_snan_1op
10160 1.1 is cmpi.b %d1,&QNAN # weed out QNAN
10161 1.1 is beq.l res_qnan_1op
10162 1.1 is
10163 1.1 is fabs.x SRC(%a0),%fp0 # force absolute value
10164 1.1 is
10165 1.1 is cmpi.b %d1,&INF # weed out INF
10166 1.1 is beq.b fabs_inf
10167 1.1 is fabs_zero:
10168 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10169 1.1 is rts
10170 1.1 is fabs_inf:
10171 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
10172 1.1 is rts
10173 1.1 is
10174 1.1 is #########################################################################
10175 1.1 is # XDEF **************************************************************** #
10176 1.1 is # fcmp(): fp compare op routine #
10177 1.1 is # #
10178 1.1 is # XREF **************************************************************** #
10179 1.1 is # res_qnan() - return QNAN result #
10180 1.1 is # res_snan() - return SNAN result #
10181 1.1 is # #
10182 1.1 is # INPUT *************************************************************** #
10183 1.1 is # a0 = pointer to extended precision source operand #
10184 1.1 is # a1 = pointer to extended precision destination operand #
10185 1.1 is # d0 = round prec/mode #
10186 1.1 is # #
10187 1.1 is # OUTPUT ************************************************************** #
10188 1.1 is # None #
10189 1.1 is # #
10190 1.1 is # ALGORITHM *********************************************************** #
10191 1.1 is # Handle NANs and denorms as special cases. For everything else, #
10192 1.1 is # just use the actual fcmp instruction to produce the correct condition #
10193 1.1 is # codes. #
10194 1.1 is # #
10195 1.1 is #########################################################################
10196 1.1 is
10197 1.1 is global fcmp
10198 1.1 is fcmp:
10199 1.1 is clr.w %d1
10200 1.1 is mov.b DTAG(%a6),%d1
10201 1.1 is lsl.b &0x3,%d1
10202 1.1 is or.b STAG(%a6),%d1
10203 1.1 is bne.b fcmp_not_norm # optimize on non-norm input
10204 1.1 is
10205 1.1 is #
10206 1.1 is # COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs
10207 1.1 is #
10208 1.1 is fcmp_norm:
10209 1.1 is fmovm.x DST(%a1),&0x80 # load dst op
10210 1.1 is
10211 1.1 is fcmp.x %fp0,SRC(%a0) # do compare
10212 1.1 is
10213 1.1 is fmov.l %fpsr,%d0 # save FPSR
10214 1.1 is rol.l &0x8,%d0 # extract ccode bits
10215 1.1 is mov.b %d0,FPSR_CC(%a6) # set ccode bits(no exc bits are set)
10216 1.1 is
10217 1.1 is rts
10218 1.1 is
10219 1.1 is #
10220 1.1 is # fcmp: inputs are not both normalized; what are they?
10221 1.1 is #
10222 1.1 is fcmp_not_norm:
10223 1.1 is mov.w (tbl_fcmp_op.b,%pc,%d1.w*2),%d1
10224 1.1 is jmp (tbl_fcmp_op.b,%pc,%d1.w*1)
10225 1.1 is
10226 1.1 is swbeg &48
10227 1.1 is tbl_fcmp_op:
10228 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - NORM
10229 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - ZERO
10230 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - INF
10231 1.1 is short fcmp_res_qnan - tbl_fcmp_op # NORM - QNAN
10232 1.1 is short fcmp_nrm_dnrm - tbl_fcmp_op # NORM - DENORM
10233 1.1 is short fcmp_res_snan - tbl_fcmp_op # NORM - SNAN
10234 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10235 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10236 1.1 is
10237 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - NORM
10238 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - ZERO
10239 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - INF
10240 1.1 is short fcmp_res_qnan - tbl_fcmp_op # ZERO - QNAN
10241 1.1 is short fcmp_dnrm_s - tbl_fcmp_op # ZERO - DENORM
10242 1.1 is short fcmp_res_snan - tbl_fcmp_op # ZERO - SNAN
10243 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10244 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10245 1.1 is
10246 1.1 is short fcmp_norm - tbl_fcmp_op # INF - NORM
10247 1.1 is short fcmp_norm - tbl_fcmp_op # INF - ZERO
10248 1.1 is short fcmp_norm - tbl_fcmp_op # INF - INF
10249 1.1 is short fcmp_res_qnan - tbl_fcmp_op # INF - QNAN
10250 1.1 is short fcmp_dnrm_s - tbl_fcmp_op # INF - DENORM
10251 1.1 is short fcmp_res_snan - tbl_fcmp_op # INF - SNAN
10252 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10253 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10254 1.1 is
10255 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - NORM
10256 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - ZERO
10257 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - INF
10258 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - QNAN
10259 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - DENORM
10260 1.1 is short fcmp_res_snan - tbl_fcmp_op # QNAN - SNAN
10261 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10262 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10263 1.1 is
10264 1.1 is short fcmp_dnrm_nrm - tbl_fcmp_op # DENORM - NORM
10265 1.1 is short fcmp_dnrm_d - tbl_fcmp_op # DENORM - ZERO
10266 1.1 is short fcmp_dnrm_d - tbl_fcmp_op # DENORM - INF
10267 1.1 is short fcmp_res_qnan - tbl_fcmp_op # DENORM - QNAN
10268 1.1 is short fcmp_dnrm_sd - tbl_fcmp_op # DENORM - DENORM
10269 1.1 is short fcmp_res_snan - tbl_fcmp_op # DENORM - SNAN
10270 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10271 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10272 1.1 is
10273 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - NORM
10274 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - ZERO
10275 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - INF
10276 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - QNAN
10277 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - DENORM
10278 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - SNAN
10279 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10280 1.1 is short tbl_fcmp_op - tbl_fcmp_op #
10281 1.1 is
10282 1.1 is # unlike all other functions for QNAN and SNAN, fcmp does NOT set the
10283 1.1 is # 'N' bit for a negative QNAN or SNAN input so we must squelch it here.
10284 1.1 is fcmp_res_qnan:
10285 1.1 is bsr.l res_qnan
10286 1.1 is andi.b &0xf7,FPSR_CC(%a6)
10287 1.1 is rts
10288 1.1 is fcmp_res_snan:
10289 1.1 is bsr.l res_snan
10290 1.1 is andi.b &0xf7,FPSR_CC(%a6)
10291 1.1 is rts
10292 1.1 is
10293 1.1 is #
10294 1.1 is # DENORMs are a little more difficult.
10295 1.1 is # If you have a 2 DENORMs, then you can just force the j-bit to a one
10296 1.1 is # and use the fcmp_norm routine.
10297 1.1 is # If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one
10298 1.1 is # and use the fcmp_norm routine.
10299 1.1 is # If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also.
10300 1.1 is # But with a DENORM and a NORM of the same sign, the neg bit is set if the
10301 1.1 is # (1) signs are (+) and the DENORM is the dst or
10302 1.1 is # (2) signs are (-) and the DENORM is the src
10303 1.1 is #
10304 1.1 is
10305 1.1 is fcmp_dnrm_s:
10306 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10307 1.1 is mov.l SRC_HI(%a0),%d0
10308 1.1 is bset &31,%d0 # DENORM src; make into small norm
10309 1.1 is mov.l %d0,FP_SCR0_HI(%a6)
10310 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10311 1.1 is lea FP_SCR0(%a6),%a0
10312 1.1 is bra.w fcmp_norm
10313 1.1 is
10314 1.1 is fcmp_dnrm_d:
10315 1.1 is mov.l DST_EX(%a1),FP_SCR0_EX(%a6)
10316 1.1 is mov.l DST_HI(%a1),%d0
10317 1.1 is bset &31,%d0 # DENORM src; make into small norm
10318 1.1 is mov.l %d0,FP_SCR0_HI(%a6)
10319 1.1 is mov.l DST_LO(%a1),FP_SCR0_LO(%a6)
10320 1.1 is lea FP_SCR0(%a6),%a1
10321 1.1 is bra.w fcmp_norm
10322 1.1 is
10323 1.1 is fcmp_dnrm_sd:
10324 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10325 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10326 1.1 is mov.l DST_HI(%a1),%d0
10327 1.1 is bset &31,%d0 # DENORM dst; make into small norm
10328 1.1 is mov.l %d0,FP_SCR1_HI(%a6)
10329 1.1 is mov.l SRC_HI(%a0),%d0
10330 1.1 is bset &31,%d0 # DENORM dst; make into small norm
10331 1.1 is mov.l %d0,FP_SCR0_HI(%a6)
10332 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10333 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10334 1.1 is lea FP_SCR1(%a6),%a1
10335 1.1 is lea FP_SCR0(%a6),%a0
10336 1.1 is bra.w fcmp_norm
10337 1.1 is
10338 1.1 is fcmp_nrm_dnrm:
10339 1.1 is mov.b SRC_EX(%a0),%d0 # determine if like signs
10340 1.1 is mov.b DST_EX(%a1),%d1
10341 1.1 is eor.b %d0,%d1
10342 1.1 is bmi.w fcmp_dnrm_s
10343 1.1 is
10344 1.1 is # signs are the same, so must determine the answer ourselves.
10345 1.1 is tst.b %d0 # is src op negative?
10346 1.1 is bmi.b fcmp_nrm_dnrm_m # yes
10347 1.1 is rts
10348 1.1 is fcmp_nrm_dnrm_m:
10349 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10350 1.1 is rts
10351 1.1 is
10352 1.1 is fcmp_dnrm_nrm:
10353 1.1 is mov.b SRC_EX(%a0),%d0 # determine if like signs
10354 1.1 is mov.b DST_EX(%a1),%d1
10355 1.1 is eor.b %d0,%d1
10356 1.1 is bmi.w fcmp_dnrm_d
10357 1.1 is
10358 1.1 is # signs are the same, so must determine the answer ourselves.
10359 1.1 is tst.b %d0 # is src op negative?
10360 1.1 is bpl.b fcmp_dnrm_nrm_m # no
10361 1.1 is rts
10362 1.1 is fcmp_dnrm_nrm_m:
10363 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10364 1.1 is rts
10365 1.1 is
10366 1.1 is #########################################################################
10367 1.1 is # XDEF **************************************************************** #
10368 1.1 is # fsglmul(): emulates the fsglmul instruction #
10369 1.1 is # #
10370 1.1 is # XREF **************************************************************** #
10371 1.1 is # scale_to_zero_src() - scale src exponent to zero #
10372 1.1 is # scale_to_zero_dst() - scale dst exponent to zero #
10373 1.1 is # unf_res4() - return default underflow result for sglop #
10374 1.1 is # ovf_res() - return default overflow result #
10375 1.1 is # res_qnan() - return QNAN result #
10376 1.1 is # res_snan() - return SNAN result #
10377 1.1 is # #
10378 1.1 is # INPUT *************************************************************** #
10379 1.1 is # a0 = pointer to extended precision source operand #
10380 1.1 is # a1 = pointer to extended precision destination operand #
10381 1.1 is # d0 rnd prec,mode #
10382 1.1 is # #
10383 1.1 is # OUTPUT ************************************************************** #
10384 1.1 is # fp0 = result #
10385 1.1 is # fp1 = EXOP (if exception occurred) #
10386 1.1 is # #
10387 1.1 is # ALGORITHM *********************************************************** #
10388 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
10389 1.1 is # norms/denorms into ext/sgl/dbl precision. #
10390 1.1 is # For norms/denorms, scale the exponents such that a multiply #
10391 1.1 is # instruction won't cause an exception. Use the regular fsglmul to #
10392 1.1 is # compute a result. Check if the regular operands would have taken #
10393 1.1 is # an exception. If so, return the default overflow/underflow result #
10394 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the #
10395 1.1 is # result operand to the proper exponent. #
10396 1.1 is # #
10397 1.1 is #########################################################################
10398 1.1 is
10399 1.1 is global fsglmul
10400 1.1 is fsglmul:
10401 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
10402 1.1 is
10403 1.1 is clr.w %d1
10404 1.1 is mov.b DTAG(%a6),%d1
10405 1.1 is lsl.b &0x3,%d1
10406 1.1 is or.b STAG(%a6),%d1
10407 1.1 is
10408 1.1 is bne.w fsglmul_not_norm # optimize on non-norm input
10409 1.1 is
10410 1.1 is fsglmul_norm:
10411 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10412 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
10413 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10414 1.1 is
10415 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10416 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10417 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10418 1.1 is
10419 1.1 is bsr.l scale_to_zero_src # scale exponent
10420 1.1 is mov.l %d0,-(%sp) # save scale factor 1
10421 1.1 is
10422 1.1 is bsr.l scale_to_zero_dst # scale dst exponent
10423 1.1 is
10424 1.1 is add.l (%sp)+,%d0 # SCALE_FACTOR = scale1 + scale2
10425 1.1 is
10426 1.1 is cmpi.l %d0,&0x3fff-0x7ffe # would result ovfl?
10427 1.1 is beq.w fsglmul_may_ovfl # result may rnd to overflow
10428 1.1 is blt.w fsglmul_ovfl # result will overflow
10429 1.1 is
10430 1.1 is cmpi.l %d0,&0x3fff+0x0001 # would result unfl?
10431 1.1 is beq.w fsglmul_may_unfl # result may rnd to no unfl
10432 1.1 is bgt.w fsglmul_unfl # result will underflow
10433 1.1 is
10434 1.1 is fsglmul_normal:
10435 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10436 1.1 is
10437 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10438 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10439 1.1 is
10440 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10441 1.1 is
10442 1.1 is fmov.l %fpsr,%d1 # save status
10443 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10444 1.1 is
10445 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10446 1.1 is
10447 1.1 is fsglmul_normal_exit:
10448 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
10449 1.1 is mov.l %d2,-(%sp) # save d2
10450 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
10451 1.1 is mov.l %d1,%d2 # make a copy
10452 1.1 is andi.l &0x7fff,%d1 # strip sign
10453 1.1 is andi.w &0x8000,%d2 # keep old sign
10454 1.1 is sub.l %d0,%d1 # add scale factor
10455 1.1 is or.w %d2,%d1 # concat old sign,new exp
10456 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10457 1.1 is mov.l (%sp)+,%d2 # restore d2
10458 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10459 1.1 is rts
10460 1.1 is
10461 1.1 is fsglmul_ovfl:
10462 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10463 1.1 is
10464 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10465 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10466 1.1 is
10467 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10468 1.1 is
10469 1.1 is fmov.l %fpsr,%d1 # save status
10470 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10471 1.1 is
10472 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10473 1.1 is
10474 1.1 is fsglmul_ovfl_tst:
10475 1.1 is
10476 1.1 is # save setting this until now because this is where fsglmul_may_ovfl may jump in
10477 1.1 is or.l &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex
10478 1.1 is
10479 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10480 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
10481 1.1 is bne.b fsglmul_ovfl_ena # yes
10482 1.1 is
10483 1.1 is fsglmul_ovfl_dis:
10484 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
10485 1.1 is sne %d1 # set sign param accordingly
10486 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd
10487 1.1 is andi.b &0x30,%d0 # force prec = ext
10488 1.1 is bsr.l ovf_res # calculate default result
10489 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
10490 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
10491 1.1 is rts
10492 1.1 is
10493 1.1 is fsglmul_ovfl_ena:
10494 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
10495 1.1 is
10496 1.1 is mov.l %d2,-(%sp) # save d2
10497 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10498 1.1 is mov.l %d1,%d2 # make a copy
10499 1.1 is andi.l &0x7fff,%d1 # strip sign
10500 1.1 is sub.l %d0,%d1 # add scale factor
10501 1.1 is subi.l &0x6000,%d1 # subtract bias
10502 1.1 is andi.w &0x7fff,%d1
10503 1.1 is andi.w &0x8000,%d2 # keep old sign
10504 1.1 is or.w %d2,%d1 # concat old sign,new exp
10505 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10506 1.1 is mov.l (%sp)+,%d2 # restore d2
10507 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10508 1.1 is bra.b fsglmul_ovfl_dis
10509 1.1 is
10510 1.1 is fsglmul_may_ovfl:
10511 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10512 1.1 is
10513 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10514 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10515 1.1 is
10516 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10517 1.1 is
10518 1.1 is fmov.l %fpsr,%d1 # save status
10519 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10520 1.1 is
10521 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10522 1.1 is
10523 1.1 is fabs.x %fp0,%fp1 # make a copy of result
10524 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b?
10525 1.1 is fbge.w fsglmul_ovfl_tst # yes; overflow has occurred
10526 1.1 is
10527 1.1 is # no, it didn't overflow; we have correct result
10528 1.1 is bra.w fsglmul_normal_exit
10529 1.1 is
10530 1.1 is fsglmul_unfl:
10531 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10532 1.1 is
10533 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10534 1.1 is
10535 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
10536 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10537 1.1 is
10538 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10539 1.1 is
10540 1.1 is fmov.l %fpsr,%d1 # save status
10541 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10542 1.1 is
10543 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10544 1.1 is
10545 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10546 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10547 1.1 is bne.b fsglmul_unfl_ena # yes
10548 1.1 is
10549 1.1 is fsglmul_unfl_dis:
10550 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
10551 1.1 is
10552 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
10553 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10554 1.1 is bsr.l unf_res4 # calculate default result
10555 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
10556 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10557 1.1 is rts
10558 1.1 is
10559 1.1 is #
10560 1.1 is # UNFL is enabled.
10561 1.1 is #
10562 1.1 is fsglmul_unfl_ena:
10563 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op
10564 1.1 is
10565 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10566 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10567 1.1 is
10568 1.1 is fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply
10569 1.1 is
10570 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10571 1.1 is
10572 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
10573 1.1 is mov.l %d2,-(%sp) # save d2
10574 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10575 1.1 is mov.l %d1,%d2 # make a copy
10576 1.1 is andi.l &0x7fff,%d1 # strip sign
10577 1.1 is andi.w &0x8000,%d2 # keep old sign
10578 1.1 is sub.l %d0,%d1 # add scale factor
10579 1.1 is addi.l &0x6000,%d1 # add bias
10580 1.1 is andi.w &0x7fff,%d1
10581 1.1 is or.w %d2,%d1 # concat old sign,new exp
10582 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10583 1.1 is mov.l (%sp)+,%d2 # restore d2
10584 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10585 1.1 is bra.w fsglmul_unfl_dis
10586 1.1 is
10587 1.1 is fsglmul_may_unfl:
10588 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10589 1.1 is
10590 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10591 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10592 1.1 is
10593 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10594 1.1 is
10595 1.1 is fmov.l %fpsr,%d1 # save status
10596 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10597 1.1 is
10598 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10599 1.1 is
10600 1.1 is fabs.x %fp0,%fp1 # make a copy of result
10601 1.1 is fcmp.b %fp1,&0x2 # is |result| > 2.b?
10602 1.1 is fbgt.w fsglmul_normal_exit # no; no underflow occurred
10603 1.1 is fblt.w fsglmul_unfl # yes; underflow occurred
10604 1.1 is
10605 1.1 is #
10606 1.1 is # we still don't know if underflow occurred. result is ~ equal to 2. but,
10607 1.1 is # we don't know if the result was an underflow that rounded up to a 2 or
10608 1.1 is # a normalized number that rounded down to a 2. so, redo the entire operation
10609 1.1 is # using RZ as the rounding mode to see what the pre-rounded result is.
10610 1.1 is # this case should be relatively rare.
10611 1.1 is #
10612 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
10613 1.1 is
10614 1.1 is mov.l L_SCR3(%a6),%d1
10615 1.1 is andi.b &0xc0,%d1 # keep rnd prec
10616 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ
10617 1.1 is
10618 1.1 is fmov.l %d1,%fpcr # set FPCR
10619 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10620 1.1 is
10621 1.1 is fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply
10622 1.1 is
10623 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10624 1.1 is fabs.x %fp1 # make absolute value
10625 1.1 is fcmp.b %fp1,&0x2 # is |result| < 2.b?
10626 1.1 is fbge.w fsglmul_normal_exit # no; no underflow occurred
10627 1.1 is bra.w fsglmul_unfl # yes, underflow occurred
10628 1.1 is
10629 1.1 is ##############################################################################
10630 1.1 is
10631 1.1 is #
10632 1.1 is # Single Precision Multiply: inputs are not both normalized; what are they?
10633 1.1 is #
10634 1.1 is fsglmul_not_norm:
10635 1.1 is mov.w (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1
10636 1.1 is jmp (tbl_fsglmul_op.b,%pc,%d1.w*1)
10637 1.1 is
10638 1.1 is swbeg &48
10639 1.1 is tbl_fsglmul_op:
10640 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x NORM
10641 1.1 is short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO
10642 1.1 is short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF
10643 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN
10644 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM
10645 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN
10646 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10647 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10648 1.1 is
10649 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x NORM
10650 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x ZERO
10651 1.1 is short fsglmul_res_operr - tbl_fsglmul_op # ZERO x INF
10652 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # ZERO x QNAN
10653 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x DENORM
10654 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # ZERO x SNAN
10655 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10656 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10657 1.1 is
10658 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x NORM
10659 1.1 is short fsglmul_res_operr - tbl_fsglmul_op # INF x ZERO
10660 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x INF
10661 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # INF x QNAN
10662 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x DENORM
10663 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # INF x SNAN
10664 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10665 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10666 1.1 is
10667 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x NORM
10668 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x ZERO
10669 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x INF
10670 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x QNAN
10671 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x DENORM
10672 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # QNAN x SNAN
10673 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10674 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10675 1.1 is
10676 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x NORM
10677 1.1 is short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO
10678 1.1 is short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF
10679 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN
10680 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM
10681 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN
10682 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10683 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10684 1.1 is
10685 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x NORM
10686 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x ZERO
10687 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x INF
10688 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x QNAN
10689 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x DENORM
10690 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x SNAN
10691 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10692 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op #
10693 1.1 is
10694 1.1 is fsglmul_res_operr:
10695 1.1 is bra.l res_operr
10696 1.1 is fsglmul_res_snan:
10697 1.1 is bra.l res_snan
10698 1.1 is fsglmul_res_qnan:
10699 1.1 is bra.l res_qnan
10700 1.1 is fsglmul_zero:
10701 1.1 is bra.l fmul_zero
10702 1.1 is fsglmul_inf_src:
10703 1.1 is bra.l fmul_inf_src
10704 1.1 is fsglmul_inf_dst:
10705 1.1 is bra.l fmul_inf_dst
10706 1.1 is
10707 1.1 is #########################################################################
10708 1.1 is # XDEF **************************************************************** #
10709 1.1 is # fsgldiv(): emulates the fsgldiv instruction #
10710 1.1 is # #
10711 1.1 is # XREF **************************************************************** #
10712 1.1 is # scale_to_zero_src() - scale src exponent to zero #
10713 1.1 is # scale_to_zero_dst() - scale dst exponent to zero #
10714 1.1 is # unf_res4() - return default underflow result for sglop #
10715 1.1 is # ovf_res() - return default overflow result #
10716 1.1 is # res_qnan() - return QNAN result #
10717 1.1 is # res_snan() - return SNAN result #
10718 1.1 is # #
10719 1.1 is # INPUT *************************************************************** #
10720 1.1 is # a0 = pointer to extended precision source operand #
10721 1.1 is # a1 = pointer to extended precision destination operand #
10722 1.1 is # d0 rnd prec,mode #
10723 1.1 is # #
10724 1.1 is # OUTPUT ************************************************************** #
10725 1.1 is # fp0 = result #
10726 1.1 is # fp1 = EXOP (if exception occurred) #
10727 1.1 is # #
10728 1.1 is # ALGORITHM *********************************************************** #
10729 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
10730 1.1 is # norms/denorms into ext/sgl/dbl precision. #
10731 1.1 is # For norms/denorms, scale the exponents such that a divide #
10732 1.1 is # instruction won't cause an exception. Use the regular fsgldiv to #
10733 1.1 is # compute a result. Check if the regular operands would have taken #
10734 1.1 is # an exception. If so, return the default overflow/underflow result #
10735 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the #
10736 1.1 is # result operand to the proper exponent. #
10737 1.1 is # #
10738 1.1 is #########################################################################
10739 1.1 is
10740 1.1 is global fsgldiv
10741 1.1 is fsgldiv:
10742 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
10743 1.1 is
10744 1.1 is clr.w %d1
10745 1.1 is mov.b DTAG(%a6),%d1
10746 1.1 is lsl.b &0x3,%d1
10747 1.1 is or.b STAG(%a6),%d1 # combine src tags
10748 1.1 is
10749 1.1 is bne.w fsgldiv_not_norm # optimize on non-norm input
10750 1.1 is
10751 1.1 is #
10752 1.1 is # DIVIDE: NORMs and DENORMs ONLY!
10753 1.1 is #
10754 1.1 is fsgldiv_norm:
10755 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10756 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
10757 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10758 1.1 is
10759 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10760 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10761 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10762 1.1 is
10763 1.1 is bsr.l scale_to_zero_src # calculate scale factor 1
10764 1.1 is mov.l %d0,-(%sp) # save scale factor 1
10765 1.1 is
10766 1.1 is bsr.l scale_to_zero_dst # calculate scale factor 2
10767 1.1 is
10768 1.1 is neg.l (%sp) # S.F. = scale1 - scale2
10769 1.1 is add.l %d0,(%sp)
10770 1.1 is
10771 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision,mode
10772 1.1 is lsr.b &0x6,%d1
10773 1.1 is mov.l (%sp)+,%d0
10774 1.1 is cmpi.l %d0,&0x3fff-0x7ffe
10775 1.1 is ble.w fsgldiv_may_ovfl
10776 1.1 is
10777 1.1 is cmpi.l %d0,&0x3fff-0x0000 # will result underflow?
10778 1.1 is beq.w fsgldiv_may_unfl # maybe
10779 1.1 is bgt.w fsgldiv_unfl # yes; go handle underflow
10780 1.1 is
10781 1.1 is fsgldiv_normal:
10782 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10783 1.1 is
10784 1.1 is fmov.l L_SCR3(%a6),%fpcr # save FPCR
10785 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10786 1.1 is
10787 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # perform sgl divide
10788 1.1 is
10789 1.1 is fmov.l %fpsr,%d1 # save FPSR
10790 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10791 1.1 is
10792 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10793 1.1 is
10794 1.1 is fsgldiv_normal_exit:
10795 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store result on stack
10796 1.1 is mov.l %d2,-(%sp) # save d2
10797 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
10798 1.1 is mov.l %d1,%d2 # make a copy
10799 1.1 is andi.l &0x7fff,%d1 # strip sign
10800 1.1 is andi.w &0x8000,%d2 # keep old sign
10801 1.1 is sub.l %d0,%d1 # add scale factor
10802 1.1 is or.w %d2,%d1 # concat old sign,new exp
10803 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10804 1.1 is mov.l (%sp)+,%d2 # restore d2
10805 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10806 1.1 is rts
10807 1.1 is
10808 1.1 is fsgldiv_may_ovfl:
10809 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10810 1.1 is
10811 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10812 1.1 is fmov.l &0x0,%fpsr # set FPSR
10813 1.1 is
10814 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute divide
10815 1.1 is
10816 1.1 is fmov.l %fpsr,%d1
10817 1.1 is fmov.l &0x0,%fpcr
10818 1.1 is
10819 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX,N
10820 1.1 is
10821 1.1 is fmovm.x &0x01,-(%sp) # save result to stack
10822 1.1 is mov.w (%sp),%d1 # fetch new exponent
10823 1.1 is add.l &0xc,%sp # clear result
10824 1.1 is andi.l &0x7fff,%d1 # strip sign
10825 1.1 is sub.l %d0,%d1 # add scale factor
10826 1.1 is cmp.l %d1,&0x7fff # did divide overflow?
10827 1.1 is blt.b fsgldiv_normal_exit
10828 1.1 is
10829 1.1 is fsgldiv_ovfl_tst:
10830 1.1 is or.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
10831 1.1 is
10832 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10833 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
10834 1.1 is bne.b fsgldiv_ovfl_ena # yes
10835 1.1 is
10836 1.1 is fsgldiv_ovfl_dis:
10837 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative
10838 1.1 is sne %d1 # set sign param accordingly
10839 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd
10840 1.1 is andi.b &0x30,%d0 # kill precision
10841 1.1 is bsr.l ovf_res # calculate default result
10842 1.1 is or.b %d0,FPSR_CC(%a6) # set INF if applicable
10843 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
10844 1.1 is rts
10845 1.1 is
10846 1.1 is fsgldiv_ovfl_ena:
10847 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
10848 1.1 is
10849 1.1 is mov.l %d2,-(%sp) # save d2
10850 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10851 1.1 is mov.l %d1,%d2 # make a copy
10852 1.1 is andi.l &0x7fff,%d1 # strip sign
10853 1.1 is andi.w &0x8000,%d2 # keep old sign
10854 1.1 is sub.l %d0,%d1 # add scale factor
10855 1.1 is subi.l &0x6000,%d1 # subtract new bias
10856 1.1 is andi.w &0x7fff,%d1 # clear ms bit
10857 1.1 is or.w %d2,%d1 # concat old sign,new exp
10858 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10859 1.1 is mov.l (%sp)+,%d2 # restore d2
10860 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10861 1.1 is bra.b fsgldiv_ovfl_dis
10862 1.1 is
10863 1.1 is fsgldiv_unfl:
10864 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10865 1.1 is
10866 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10867 1.1 is
10868 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
10869 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10870 1.1 is
10871 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide
10872 1.1 is
10873 1.1 is fmov.l %fpsr,%d1 # save status
10874 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10875 1.1 is
10876 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10877 1.1 is
10878 1.1 is mov.b FPCR_ENABLE(%a6),%d1
10879 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10880 1.1 is bne.b fsgldiv_unfl_ena # yes
10881 1.1 is
10882 1.1 is fsgldiv_unfl_dis:
10883 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
10884 1.1 is
10885 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
10886 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10887 1.1 is bsr.l unf_res4 # calculate default result
10888 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
10889 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10890 1.1 is rts
10891 1.1 is
10892 1.1 is #
10893 1.1 is # UNFL is enabled.
10894 1.1 is #
10895 1.1 is fsgldiv_unfl_ena:
10896 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op
10897 1.1 is
10898 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10899 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10900 1.1 is
10901 1.1 is fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide
10902 1.1 is
10903 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10904 1.1 is
10905 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
10906 1.1 is mov.l %d2,-(%sp) # save d2
10907 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10908 1.1 is mov.l %d1,%d2 # make a copy
10909 1.1 is andi.l &0x7fff,%d1 # strip sign
10910 1.1 is andi.w &0x8000,%d2 # keep old sign
10911 1.1 is sub.l %d0,%d1 # add scale factor
10912 1.1 is addi.l &0x6000,%d1 # add bias
10913 1.1 is andi.w &0x7fff,%d1 # clear top bit
10914 1.1 is or.w %d2,%d1 # concat old sign, new exp
10915 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10916 1.1 is mov.l (%sp)+,%d2 # restore d2
10917 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10918 1.1 is bra.b fsgldiv_unfl_dis
10919 1.1 is
10920 1.1 is #
10921 1.1 is # the divide operation MAY underflow:
10922 1.1 is #
10923 1.1 is fsgldiv_may_unfl:
10924 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10925 1.1 is
10926 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
10927 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10928 1.1 is
10929 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide
10930 1.1 is
10931 1.1 is fmov.l %fpsr,%d1 # save status
10932 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10933 1.1 is
10934 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
10935 1.1 is
10936 1.1 is fabs.x %fp0,%fp1 # make a copy of result
10937 1.1 is fcmp.b %fp1,&0x1 # is |result| > 1.b?
10938 1.1 is fbgt.w fsgldiv_normal_exit # no; no underflow occurred
10939 1.1 is fblt.w fsgldiv_unfl # yes; underflow occurred
10940 1.1 is
10941 1.1 is #
10942 1.1 is # we still don't know if underflow occurred. result is ~ equal to 1. but,
10943 1.1 is # we don't know if the result was an underflow that rounded up to a 1
10944 1.1 is # or a normalized number that rounded down to a 1. so, redo the entire
10945 1.1 is # operation using RZ as the rounding mode to see what the pre-rounded
10946 1.1 is # result is. this case should be relatively rare.
10947 1.1 is #
10948 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into %fp1
10949 1.1 is
10950 1.1 is clr.l %d1 # clear scratch register
10951 1.1 is ori.b &rz_mode*0x10,%d1 # force RZ rnd mode
10952 1.1 is
10953 1.1 is fmov.l %d1,%fpcr # set FPCR
10954 1.1 is fmov.l &0x0,%fpsr # clear FPSR
10955 1.1 is
10956 1.1 is fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide
10957 1.1 is
10958 1.1 is fmov.l &0x0,%fpcr # clear FPCR
10959 1.1 is fabs.x %fp1 # make absolute value
10960 1.1 is fcmp.b %fp1,&0x1 # is |result| < 1.b?
10961 1.1 is fbge.w fsgldiv_normal_exit # no; no underflow occurred
10962 1.1 is bra.w fsgldiv_unfl # yes; underflow occurred
10963 1.1 is
10964 1.1 is ############################################################################
10965 1.1 is
10966 1.1 is #
10967 1.1 is # Divide: inputs are not both normalized; what are they?
10968 1.1 is #
10969 1.1 is fsgldiv_not_norm:
10970 1.1 is mov.w (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1
10971 1.1 is jmp (tbl_fsgldiv_op.b,%pc,%d1.w*1)
10972 1.1 is
10973 1.1 is swbeg &48
10974 1.1 is tbl_fsgldiv_op:
10975 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # NORM / NORM
10976 1.1 is short fsgldiv_inf_load - tbl_fsgldiv_op # NORM / ZERO
10977 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # NORM / INF
10978 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # NORM / QNAN
10979 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # NORM / DENORM
10980 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # NORM / SNAN
10981 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
10982 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
10983 1.1 is
10984 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / NORM
10985 1.1 is short fsgldiv_res_operr - tbl_fsgldiv_op # ZERO / ZERO
10986 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / INF
10987 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # ZERO / QNAN
10988 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / DENORM
10989 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # ZERO / SNAN
10990 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
10991 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
10992 1.1 is
10993 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / NORM
10994 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / ZERO
10995 1.1 is short fsgldiv_res_operr - tbl_fsgldiv_op # INF / INF
10996 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # INF / QNAN
10997 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / DENORM
10998 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # INF / SNAN
10999 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11000 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11001 1.1 is
11002 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / NORM
11003 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / ZERO
11004 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / INF
11005 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / QNAN
11006 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / DENORM
11007 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # QNAN / SNAN
11008 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11009 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11010 1.1 is
11011 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # DENORM / NORM
11012 1.1 is short fsgldiv_inf_load - tbl_fsgldiv_op # DENORM / ZERO
11013 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # DENORM / INF
11014 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # DENORM / QNAN
11015 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # DENORM / DENORM
11016 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # DENORM / SNAN
11017 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11018 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11019 1.1 is
11020 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / NORM
11021 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / ZERO
11022 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / INF
11023 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / QNAN
11024 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / DENORM
11025 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / SNAN
11026 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11027 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op #
11028 1.1 is
11029 1.1 is fsgldiv_res_qnan:
11030 1.1 is bra.l res_qnan
11031 1.1 is fsgldiv_res_snan:
11032 1.1 is bra.l res_snan
11033 1.1 is fsgldiv_res_operr:
11034 1.1 is bra.l res_operr
11035 1.1 is fsgldiv_inf_load:
11036 1.1 is bra.l fdiv_inf_load
11037 1.1 is fsgldiv_zero_load:
11038 1.1 is bra.l fdiv_zero_load
11039 1.1 is fsgldiv_inf_dst:
11040 1.1 is bra.l fdiv_inf_dst
11041 1.1 is
11042 1.1 is #########################################################################
11043 1.1 is # XDEF **************************************************************** #
11044 1.1 is # fadd(): emulates the fadd instruction #
11045 1.1 is # fsadd(): emulates the fadd instruction #
11046 1.1 is # fdadd(): emulates the fdadd instruction #
11047 1.1 is # #
11048 1.1 is # XREF **************************************************************** #
11049 1.1 is # addsub_scaler2() - scale the operands so they won't take exc #
11050 1.1 is # ovf_res() - return default overflow result #
11051 1.1 is # unf_res() - return default underflow result #
11052 1.1 is # res_qnan() - set QNAN result #
11053 1.1 is # res_snan() - set SNAN result #
11054 1.1 is # res_operr() - set OPERR result #
11055 1.1 is # scale_to_zero_src() - set src operand exponent equal to zero #
11056 1.1 is # scale_to_zero_dst() - set dst operand exponent equal to zero #
11057 1.1 is # #
11058 1.1 is # INPUT *************************************************************** #
11059 1.1 is # a0 = pointer to extended precision source operand #
11060 1.1 is # a1 = pointer to extended precision destination operand #
11061 1.1 is # #
11062 1.1 is # OUTPUT ************************************************************** #
11063 1.1 is # fp0 = result #
11064 1.1 is # fp1 = EXOP (if exception occurred) #
11065 1.1 is # #
11066 1.1 is # ALGORITHM *********************************************************** #
11067 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
11068 1.1 is # norms into extended, single, and double precision. #
11069 1.1 is # Do addition after scaling exponents such that exception won't #
11070 1.1 is # occur. Then, check result exponent to see if exception would have #
11071 1.1 is # occurred. If so, return default result and maybe EXOP. Else, insert #
11072 1.1 is # the correct result exponent and return. Set FPSR bits as appropriate. #
11073 1.1 is # #
11074 1.1 is #########################################################################
11075 1.1 is
11076 1.1 is global fsadd
11077 1.1 is fsadd:
11078 1.1 is andi.b &0x30,%d0 # clear rnd prec
11079 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec
11080 1.1 is bra.b fadd
11081 1.1 is
11082 1.1 is global fdadd
11083 1.1 is fdadd:
11084 1.1 is andi.b &0x30,%d0 # clear rnd prec
11085 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
11086 1.1 is
11087 1.1 is global fadd
11088 1.1 is fadd:
11089 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
11090 1.1 is
11091 1.1 is clr.w %d1
11092 1.1 is mov.b DTAG(%a6),%d1
11093 1.1 is lsl.b &0x3,%d1
11094 1.1 is or.b STAG(%a6),%d1 # combine src tags
11095 1.1 is
11096 1.1 is bne.w fadd_not_norm # optimize on non-norm input
11097 1.1 is
11098 1.1 is #
11099 1.1 is # ADD: norms and denorms
11100 1.1 is #
11101 1.1 is fadd_norm:
11102 1.1 is bsr.l addsub_scaler2 # scale exponents
11103 1.1 is
11104 1.1 is fadd_zero_entry:
11105 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11106 1.1 is
11107 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11108 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
11109 1.1 is
11110 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add
11111 1.1 is
11112 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11113 1.1 is fmov.l %fpsr,%d1 # fetch INEX2,N,Z
11114 1.1 is
11115 1.1 is or.l %d1,USER_FPSR(%a6) # save exc and ccode bits
11116 1.1 is
11117 1.1 is fbeq.w fadd_zero_exit # if result is zero, end now
11118 1.1 is
11119 1.1 is mov.l %d2,-(%sp) # save d2
11120 1.1 is
11121 1.1 is fmovm.x &0x01,-(%sp) # save result to stack
11122 1.1 is
11123 1.1 is mov.w 2+L_SCR3(%a6),%d1
11124 1.1 is lsr.b &0x6,%d1
11125 1.1 is
11126 1.1 is mov.w (%sp),%d2 # fetch new sign, exp
11127 1.1 is andi.l &0x7fff,%d2 # strip sign
11128 1.1 is sub.l %d0,%d2 # add scale factor
11129 1.1 is
11130 1.1 is cmp.l %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11131 1.1 is bge.b fadd_ovfl # yes
11132 1.1 is
11133 1.1 is cmp.l %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow?
11134 1.1 is blt.w fadd_unfl # yes
11135 1.1 is beq.w fadd_may_unfl # maybe; go find out
11136 1.1 is
11137 1.1 is fadd_normal:
11138 1.1 is mov.w (%sp),%d1
11139 1.1 is andi.w &0x8000,%d1 # keep sign
11140 1.1 is or.w %d2,%d1 # concat sign,new exp
11141 1.1 is mov.w %d1,(%sp) # insert new exponent
11142 1.1 is
11143 1.1 is fmovm.x (%sp)+,&0x80 # return result in fp0
11144 1.1 is
11145 1.1 is mov.l (%sp)+,%d2 # restore d2
11146 1.1 is rts
11147 1.1 is
11148 1.1 is fadd_zero_exit:
11149 1.1 is # fmov.s &0x00000000,%fp0 # return zero in fp0
11150 1.1 is rts
11151 1.1 is
11152 1.1 is tbl_fadd_ovfl:
11153 1.1 is long 0x7fff # ext ovfl
11154 1.1 is long 0x407f # sgl ovfl
11155 1.1 is long 0x43ff # dbl ovfl
11156 1.1 is
11157 1.1 is tbl_fadd_unfl:
11158 1.1 is long 0x0000 # ext unfl
11159 1.1 is long 0x3f81 # sgl unfl
11160 1.1 is long 0x3c01 # dbl unfl
11161 1.1 is
11162 1.1 is fadd_ovfl:
11163 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11164 1.1 is
11165 1.1 is mov.b FPCR_ENABLE(%a6),%d1
11166 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
11167 1.1 is bne.b fadd_ovfl_ena # yes
11168 1.1 is
11169 1.1 is add.l &0xc,%sp
11170 1.1 is fadd_ovfl_dis:
11171 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
11172 1.1 is sne %d1 # set sign param accordingly
11173 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd
11174 1.1 is bsr.l ovf_res # calculate default result
11175 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
11176 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
11177 1.1 is mov.l (%sp)+,%d2 # restore d2
11178 1.1 is rts
11179 1.1 is
11180 1.1 is fadd_ovfl_ena:
11181 1.1 is mov.b L_SCR3(%a6),%d1
11182 1.1 is andi.b &0xc0,%d1 # is precision extended?
11183 1.1 is bne.b fadd_ovfl_ena_sd # no; prec = sgl or dbl
11184 1.1 is
11185 1.1 is fadd_ovfl_ena_cont:
11186 1.1 is mov.w (%sp),%d1
11187 1.1 is andi.w &0x8000,%d1 # keep sign
11188 1.1 is subi.l &0x6000,%d2 # add extra bias
11189 1.1 is andi.w &0x7fff,%d2
11190 1.1 is or.w %d2,%d1 # concat sign,new exp
11191 1.1 is mov.w %d1,(%sp) # insert new exponent
11192 1.1 is
11193 1.1 is fmovm.x (%sp)+,&0x40 # return EXOP in fp1
11194 1.1 is bra.b fadd_ovfl_dis
11195 1.1 is
11196 1.1 is fadd_ovfl_ena_sd:
11197 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11198 1.1 is
11199 1.1 is mov.l L_SCR3(%a6),%d1
11200 1.1 is andi.b &0x30,%d1 # keep rnd mode
11201 1.1 is fmov.l %d1,%fpcr # set FPCR
11202 1.1 is
11203 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add
11204 1.1 is
11205 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11206 1.1 is
11207 1.1 is add.l &0xc,%sp
11208 1.1 is fmovm.x &0x01,-(%sp)
11209 1.1 is bra.b fadd_ovfl_ena_cont
11210 1.1 is
11211 1.1 is fadd_unfl:
11212 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11213 1.1 is
11214 1.1 is add.l &0xc,%sp
11215 1.1 is
11216 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11217 1.1 is
11218 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
11219 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11220 1.1 is
11221 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add
11222 1.1 is
11223 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11224 1.1 is fmov.l %fpsr,%d1 # save status
11225 1.1 is
11226 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX,N
11227 1.1 is
11228 1.1 is mov.b FPCR_ENABLE(%a6),%d1
11229 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
11230 1.1 is bne.b fadd_unfl_ena # yes
11231 1.1 is
11232 1.1 is fadd_unfl_dis:
11233 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
11234 1.1 is
11235 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
11236 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
11237 1.1 is bsr.l unf_res # calculate default result
11238 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
11239 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
11240 1.1 is mov.l (%sp)+,%d2 # restore d2
11241 1.1 is rts
11242 1.1 is
11243 1.1 is fadd_unfl_ena:
11244 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op
11245 1.1 is
11246 1.1 is mov.l L_SCR3(%a6),%d1
11247 1.1 is andi.b &0xc0,%d1 # is precision extended?
11248 1.1 is bne.b fadd_unfl_ena_sd # no; sgl or dbl
11249 1.1 is
11250 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
11251 1.1 is
11252 1.1 is fadd_unfl_ena_cont:
11253 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11254 1.1 is
11255 1.1 is fadd.x FP_SCR0(%a6),%fp1 # execute multiply
11256 1.1 is
11257 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11258 1.1 is
11259 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
11260 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
11261 1.1 is mov.l %d1,%d2 # make a copy
11262 1.1 is andi.l &0x7fff,%d1 # strip sign
11263 1.1 is andi.w &0x8000,%d2 # keep old sign
11264 1.1 is sub.l %d0,%d1 # add scale factor
11265 1.1 is addi.l &0x6000,%d1 # add new bias
11266 1.1 is andi.w &0x7fff,%d1 # clear top bit
11267 1.1 is or.w %d2,%d1 # concat sign,new exp
11268 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
11269 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
11270 1.1 is bra.w fadd_unfl_dis
11271 1.1 is
11272 1.1 is fadd_unfl_ena_sd:
11273 1.1 is mov.l L_SCR3(%a6),%d1
11274 1.1 is andi.b &0x30,%d1 # use only rnd mode
11275 1.1 is fmov.l %d1,%fpcr # set FPCR
11276 1.1 is
11277 1.1 is bra.b fadd_unfl_ena_cont
11278 1.1 is
11279 1.1 is #
11280 1.1 is # result is equal to the smallest normalized number in the selected precision
11281 1.1 is # if the precision is extended, this result could not have come from an
11282 1.1 is # underflow that rounded up.
11283 1.1 is #
11284 1.1 is fadd_may_unfl:
11285 1.1 is mov.l L_SCR3(%a6),%d1
11286 1.1 is andi.b &0xc0,%d1
11287 1.1 is beq.w fadd_normal # yes; no underflow occurred
11288 1.1 is
11289 1.1 is mov.l 0x4(%sp),%d1 # extract hi(man)
11290 1.1 is cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000?
11291 1.1 is bne.w fadd_normal # no; no underflow occurred
11292 1.1 is
11293 1.1 is tst.l 0x8(%sp) # is lo(man) = 0x0?
11294 1.1 is bne.w fadd_normal # no; no underflow occurred
11295 1.1 is
11296 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11297 1.1 is beq.w fadd_normal # no; no underflow occurred
11298 1.1 is
11299 1.1 is #
11300 1.1 is # ok, so now the result has a exponent equal to the smallest normalized
11301 1.1 is # exponent for the selected precision. also, the mantissa is equal to
11302 1.1 is # 0x8000000000000000 and this mantissa is the result of rounding non-zero
11303 1.1 is # g,r,s.
11304 1.1 is # now, we must determine whether the pre-rounded result was an underflow
11305 1.1 is # rounded "up" or a normalized number rounded "down".
11306 1.1 is # so, we do this be re-executing the add using RZ as the rounding mode and
11307 1.1 is # seeing if the new result is smaller or equal to the current result.
11308 1.1 is #
11309 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
11310 1.1 is
11311 1.1 is mov.l L_SCR3(%a6),%d1
11312 1.1 is andi.b &0xc0,%d1 # keep rnd prec
11313 1.1 is ori.b &rz_mode*0x10,%d1 # insert rnd mode
11314 1.1 is fmov.l %d1,%fpcr # set FPCR
11315 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11316 1.1 is
11317 1.1 is fadd.x FP_SCR0(%a6),%fp1 # execute add
11318 1.1 is
11319 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11320 1.1 is
11321 1.1 is fabs.x %fp0 # compare absolute values
11322 1.1 is fabs.x %fp1
11323 1.1 is fcmp.x %fp0,%fp1 # is first result > second?
11324 1.1 is
11325 1.1 is fbgt.w fadd_unfl # yes; it's an underflow
11326 1.1 is bra.w fadd_normal # no; it's not an underflow
11327 1.1 is
11328 1.1 is ##########################################################################
11329 1.1 is
11330 1.1 is #
11331 1.1 is # Add: inputs are not both normalized; what are they?
11332 1.1 is #
11333 1.1 is fadd_not_norm:
11334 1.1 is mov.w (tbl_fadd_op.b,%pc,%d1.w*2),%d1
11335 1.1 is jmp (tbl_fadd_op.b,%pc,%d1.w*1)
11336 1.1 is
11337 1.1 is swbeg &48
11338 1.1 is tbl_fadd_op:
11339 1.1 is short fadd_norm - tbl_fadd_op # NORM + NORM
11340 1.1 is short fadd_zero_src - tbl_fadd_op # NORM + ZERO
11341 1.1 is short fadd_inf_src - tbl_fadd_op # NORM + INF
11342 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11343 1.1 is short fadd_norm - tbl_fadd_op # NORM + DENORM
11344 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11345 1.1 is short tbl_fadd_op - tbl_fadd_op #
11346 1.1 is short tbl_fadd_op - tbl_fadd_op #
11347 1.1 is
11348 1.1 is short fadd_zero_dst - tbl_fadd_op # ZERO + NORM
11349 1.1 is short fadd_zero_2 - tbl_fadd_op # ZERO + ZERO
11350 1.1 is short fadd_inf_src - tbl_fadd_op # ZERO + INF
11351 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11352 1.1 is short fadd_zero_dst - tbl_fadd_op # ZERO + DENORM
11353 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11354 1.1 is short tbl_fadd_op - tbl_fadd_op #
11355 1.1 is short tbl_fadd_op - tbl_fadd_op #
11356 1.1 is
11357 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + NORM
11358 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + ZERO
11359 1.1 is short fadd_inf_2 - tbl_fadd_op # INF + INF
11360 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11361 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + DENORM
11362 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11363 1.1 is short tbl_fadd_op - tbl_fadd_op #
11364 1.1 is short tbl_fadd_op - tbl_fadd_op #
11365 1.1 is
11366 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + NORM
11367 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + ZERO
11368 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + INF
11369 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + QNAN
11370 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + DENORM
11371 1.1 is short fadd_res_snan - tbl_fadd_op # QNAN + SNAN
11372 1.1 is short tbl_fadd_op - tbl_fadd_op #
11373 1.1 is short tbl_fadd_op - tbl_fadd_op #
11374 1.1 is
11375 1.1 is short fadd_norm - tbl_fadd_op # DENORM + NORM
11376 1.1 is short fadd_zero_src - tbl_fadd_op # DENORM + ZERO
11377 1.1 is short fadd_inf_src - tbl_fadd_op # DENORM + INF
11378 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11379 1.1 is short fadd_norm - tbl_fadd_op # DENORM + DENORM
11380 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11381 1.1 is short tbl_fadd_op - tbl_fadd_op #
11382 1.1 is short tbl_fadd_op - tbl_fadd_op #
11383 1.1 is
11384 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + NORM
11385 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + ZERO
11386 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + INF
11387 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + QNAN
11388 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + DENORM
11389 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + SNAN
11390 1.1 is short tbl_fadd_op - tbl_fadd_op #
11391 1.1 is short tbl_fadd_op - tbl_fadd_op #
11392 1.1 is
11393 1.1 is fadd_res_qnan:
11394 1.1 is bra.l res_qnan
11395 1.1 is fadd_res_snan:
11396 1.1 is bra.l res_snan
11397 1.1 is
11398 1.1 is #
11399 1.1 is # both operands are ZEROes
11400 1.1 is #
11401 1.1 is fadd_zero_2:
11402 1.1 is mov.b SRC_EX(%a0),%d0 # are the signs opposite
11403 1.1 is mov.b DST_EX(%a1),%d1
11404 1.1 is eor.b %d0,%d1
11405 1.1 is bmi.w fadd_zero_2_chk_rm # weed out (-ZERO)+(+ZERO)
11406 1.1 is
11407 1.1 is # the signs are the same. so determine whether they are positive or negative
11408 1.1 is # and return the appropriately signed zero.
11409 1.1 is tst.b %d0 # are ZEROes positive or negative?
11410 1.1 is bmi.b fadd_zero_rm # negative
11411 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO
11412 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
11413 1.1 is rts
11414 1.1 is
11415 1.1 is #
11416 1.1 is # the ZEROes have opposite signs:
11417 1.1 is # - therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
11418 1.1 is # - -ZERO is returned in the case of RM.
11419 1.1 is #
11420 1.1 is fadd_zero_2_chk_rm:
11421 1.1 is mov.b 3+L_SCR3(%a6),%d1
11422 1.1 is andi.b &0x30,%d1 # extract rnd mode
11423 1.1 is cmpi.b %d1,&rm_mode*0x10 # is rnd mode == RM?
11424 1.1 is beq.b fadd_zero_rm # yes
11425 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO
11426 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
11427 1.1 is rts
11428 1.1 is
11429 1.1 is fadd_zero_rm:
11430 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO
11431 1.1 is mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z
11432 1.1 is rts
11433 1.1 is
11434 1.1 is #
11435 1.1 is # one operand is a ZERO and the other is a DENORM or NORM. scale
11436 1.1 is # the DENORM or NORM and jump to the regular fadd routine.
11437 1.1 is #
11438 1.1 is fadd_zero_dst:
11439 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
11440 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
11441 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
11442 1.1 is bsr.l scale_to_zero_src # scale the operand
11443 1.1 is clr.w FP_SCR1_EX(%a6)
11444 1.1 is clr.l FP_SCR1_HI(%a6)
11445 1.1 is clr.l FP_SCR1_LO(%a6)
11446 1.1 is bra.w fadd_zero_entry # go execute fadd
11447 1.1 is
11448 1.1 is fadd_zero_src:
11449 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
11450 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
11451 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
11452 1.1 is bsr.l scale_to_zero_dst # scale the operand
11453 1.1 is clr.w FP_SCR0_EX(%a6)
11454 1.1 is clr.l FP_SCR0_HI(%a6)
11455 1.1 is clr.l FP_SCR0_LO(%a6)
11456 1.1 is bra.w fadd_zero_entry # go execute fadd
11457 1.1 is
11458 1.1 is #
11459 1.1 is # both operands are INFs. an OPERR will result if the INFs have
11460 1.1 is # different signs. else, an INF of the same sign is returned
11461 1.1 is #
11462 1.1 is fadd_inf_2:
11463 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs
11464 1.1 is mov.b DST_EX(%a1),%d1
11465 1.1 is eor.b %d1,%d0
11466 1.1 is bmi.l res_operr # weed out (-INF)+(+INF)
11467 1.1 is
11468 1.1 is # ok, so it's not an OPERR. but, we do have to remember to return the
11469 1.1 is # src INF since that's where the 881/882 gets the j-bit from...
11470 1.1 is
11471 1.1 is #
11472 1.1 is # operands are INF and one of {ZERO, INF, DENORM, NORM}
11473 1.1 is #
11474 1.1 is fadd_inf_src:
11475 1.1 is fmovm.x SRC(%a0),&0x80 # return src INF
11476 1.1 is tst.b SRC_EX(%a0) # is INF positive?
11477 1.1 is bpl.b fadd_inf_done # yes; we're done
11478 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11479 1.1 is rts
11480 1.1 is
11481 1.1 is #
11482 1.1 is # operands are INF and one of {ZERO, INF, DENORM, NORM}
11483 1.1 is #
11484 1.1 is fadd_inf_dst:
11485 1.1 is fmovm.x DST(%a1),&0x80 # return dst INF
11486 1.1 is tst.b DST_EX(%a1) # is INF positive?
11487 1.1 is bpl.b fadd_inf_done # yes; we're done
11488 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11489 1.1 is rts
11490 1.1 is
11491 1.1 is fadd_inf_done:
11492 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF
11493 1.1 is rts
11494 1.1 is
11495 1.1 is #########################################################################
11496 1.1 is # XDEF **************************************************************** #
11497 1.1 is # fsub(): emulates the fsub instruction #
11498 1.1 is # fssub(): emulates the fssub instruction #
11499 1.1 is # fdsub(): emulates the fdsub instruction #
11500 1.1 is # #
11501 1.1 is # XREF **************************************************************** #
11502 1.1 is # addsub_scaler2() - scale the operands so they won't take exc #
11503 1.1 is # ovf_res() - return default overflow result #
11504 1.1 is # unf_res() - return default underflow result #
11505 1.1 is # res_qnan() - set QNAN result #
11506 1.1 is # res_snan() - set SNAN result #
11507 1.1 is # res_operr() - set OPERR result #
11508 1.1 is # scale_to_zero_src() - set src operand exponent equal to zero #
11509 1.1 is # scale_to_zero_dst() - set dst operand exponent equal to zero #
11510 1.1 is # #
11511 1.1 is # INPUT *************************************************************** #
11512 1.1 is # a0 = pointer to extended precision source operand #
11513 1.1 is # a1 = pointer to extended precision destination operand #
11514 1.1 is # #
11515 1.1 is # OUTPUT ************************************************************** #
11516 1.1 is # fp0 = result #
11517 1.1 is # fp1 = EXOP (if exception occurred) #
11518 1.1 is # #
11519 1.1 is # ALGORITHM *********************************************************** #
11520 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
11521 1.1 is # norms into extended, single, and double precision. #
11522 1.1 is # Do subtraction after scaling exponents such that exception won't#
11523 1.1 is # occur. Then, check result exponent to see if exception would have #
11524 1.1 is # occurred. If so, return default result and maybe EXOP. Else, insert #
11525 1.1 is # the correct result exponent and return. Set FPSR bits as appropriate. #
11526 1.1 is # #
11527 1.1 is #########################################################################
11528 1.1 is
11529 1.1 is global fssub
11530 1.1 is fssub:
11531 1.1 is andi.b &0x30,%d0 # clear rnd prec
11532 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec
11533 1.1 is bra.b fsub
11534 1.1 is
11535 1.1 is global fdsub
11536 1.1 is fdsub:
11537 1.1 is andi.b &0x30,%d0 # clear rnd prec
11538 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec
11539 1.1 is
11540 1.1 is global fsub
11541 1.1 is fsub:
11542 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
11543 1.1 is
11544 1.1 is clr.w %d1
11545 1.1 is mov.b DTAG(%a6),%d1
11546 1.1 is lsl.b &0x3,%d1
11547 1.1 is or.b STAG(%a6),%d1 # combine src tags
11548 1.1 is
11549 1.1 is bne.w fsub_not_norm # optimize on non-norm input
11550 1.1 is
11551 1.1 is #
11552 1.1 is # SUB: norms and denorms
11553 1.1 is #
11554 1.1 is fsub_norm:
11555 1.1 is bsr.l addsub_scaler2 # scale exponents
11556 1.1 is
11557 1.1 is fsub_zero_entry:
11558 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11559 1.1 is
11560 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11561 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
11562 1.1 is
11563 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11564 1.1 is
11565 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11566 1.1 is fmov.l %fpsr,%d1 # fetch INEX2, N, Z
11567 1.1 is
11568 1.1 is or.l %d1,USER_FPSR(%a6) # save exc and ccode bits
11569 1.1 is
11570 1.1 is fbeq.w fsub_zero_exit # if result zero, end now
11571 1.1 is
11572 1.1 is mov.l %d2,-(%sp) # save d2
11573 1.1 is
11574 1.1 is fmovm.x &0x01,-(%sp) # save result to stack
11575 1.1 is
11576 1.1 is mov.w 2+L_SCR3(%a6),%d1
11577 1.1 is lsr.b &0x6,%d1
11578 1.1 is
11579 1.1 is mov.w (%sp),%d2 # fetch new exponent
11580 1.1 is andi.l &0x7fff,%d2 # strip sign
11581 1.1 is sub.l %d0,%d2 # add scale factor
11582 1.1 is
11583 1.1 is cmp.l %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11584 1.1 is bge.b fsub_ovfl # yes
11585 1.1 is
11586 1.1 is cmp.l %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow?
11587 1.1 is blt.w fsub_unfl # yes
11588 1.1 is beq.w fsub_may_unfl # maybe; go find out
11589 1.1 is
11590 1.1 is fsub_normal:
11591 1.1 is mov.w (%sp),%d1
11592 1.1 is andi.w &0x8000,%d1 # keep sign
11593 1.1 is or.w %d2,%d1 # insert new exponent
11594 1.1 is mov.w %d1,(%sp) # insert new exponent
11595 1.1 is
11596 1.1 is fmovm.x (%sp)+,&0x80 # return result in fp0
11597 1.1 is
11598 1.1 is mov.l (%sp)+,%d2 # restore d2
11599 1.1 is rts
11600 1.1 is
11601 1.1 is fsub_zero_exit:
11602 1.1 is # fmov.s &0x00000000,%fp0 # return zero in fp0
11603 1.1 is rts
11604 1.1 is
11605 1.1 is tbl_fsub_ovfl:
11606 1.1 is long 0x7fff # ext ovfl
11607 1.1 is long 0x407f # sgl ovfl
11608 1.1 is long 0x43ff # dbl ovfl
11609 1.1 is
11610 1.1 is tbl_fsub_unfl:
11611 1.1 is long 0x0000 # ext unfl
11612 1.1 is long 0x3f81 # sgl unfl
11613 1.1 is long 0x3c01 # dbl unfl
11614 1.1 is
11615 1.1 is fsub_ovfl:
11616 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11617 1.1 is
11618 1.1 is mov.b FPCR_ENABLE(%a6),%d1
11619 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
11620 1.1 is bne.b fsub_ovfl_ena # yes
11621 1.1 is
11622 1.1 is add.l &0xc,%sp
11623 1.1 is fsub_ovfl_dis:
11624 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
11625 1.1 is sne %d1 # set sign param accordingly
11626 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd
11627 1.1 is bsr.l ovf_res # calculate default result
11628 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
11629 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
11630 1.1 is mov.l (%sp)+,%d2 # restore d2
11631 1.1 is rts
11632 1.1 is
11633 1.1 is fsub_ovfl_ena:
11634 1.1 is mov.b L_SCR3(%a6),%d1
11635 1.1 is andi.b &0xc0,%d1 # is precision extended?
11636 1.1 is bne.b fsub_ovfl_ena_sd # no
11637 1.1 is
11638 1.1 is fsub_ovfl_ena_cont:
11639 1.1 is mov.w (%sp),%d1 # fetch {sgn,exp}
11640 1.1 is andi.w &0x8000,%d1 # keep sign
11641 1.1 is subi.l &0x6000,%d2 # subtract new bias
11642 1.1 is andi.w &0x7fff,%d2 # clear top bit
11643 1.1 is or.w %d2,%d1 # concat sign,exp
11644 1.1 is mov.w %d1,(%sp) # insert new exponent
11645 1.1 is
11646 1.1 is fmovm.x (%sp)+,&0x40 # return EXOP in fp1
11647 1.1 is bra.b fsub_ovfl_dis
11648 1.1 is
11649 1.1 is fsub_ovfl_ena_sd:
11650 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11651 1.1 is
11652 1.1 is mov.l L_SCR3(%a6),%d1
11653 1.1 is andi.b &0x30,%d1 # clear rnd prec
11654 1.1 is fmov.l %d1,%fpcr # set FPCR
11655 1.1 is
11656 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11657 1.1 is
11658 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11659 1.1 is
11660 1.1 is add.l &0xc,%sp
11661 1.1 is fmovm.x &0x01,-(%sp)
11662 1.1 is bra.b fsub_ovfl_ena_cont
11663 1.1 is
11664 1.1 is fsub_unfl:
11665 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11666 1.1 is
11667 1.1 is add.l &0xc,%sp
11668 1.1 is
11669 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11670 1.1 is
11671 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
11672 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11673 1.1 is
11674 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11675 1.1 is
11676 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11677 1.1 is fmov.l %fpsr,%d1 # save status
11678 1.1 is
11679 1.1 is or.l %d1,USER_FPSR(%a6)
11680 1.1 is
11681 1.1 is mov.b FPCR_ENABLE(%a6),%d1
11682 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
11683 1.1 is bne.b fsub_unfl_ena # yes
11684 1.1 is
11685 1.1 is fsub_unfl_dis:
11686 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
11687 1.1 is
11688 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
11689 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
11690 1.1 is bsr.l unf_res # calculate default result
11691 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' may have been set
11692 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
11693 1.1 is mov.l (%sp)+,%d2 # restore d2
11694 1.1 is rts
11695 1.1 is
11696 1.1 is fsub_unfl_ena:
11697 1.1 is fmovm.x FP_SCR1(%a6),&0x40
11698 1.1 is
11699 1.1 is mov.l L_SCR3(%a6),%d1
11700 1.1 is andi.b &0xc0,%d1 # is precision extended?
11701 1.1 is bne.b fsub_unfl_ena_sd # no
11702 1.1 is
11703 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
11704 1.1 is
11705 1.1 is fsub_unfl_ena_cont:
11706 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11707 1.1 is
11708 1.1 is fsub.x FP_SCR0(%a6),%fp1 # execute subtract
11709 1.1 is
11710 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11711 1.1 is
11712 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # store result to stack
11713 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
11714 1.1 is mov.l %d1,%d2 # make a copy
11715 1.1 is andi.l &0x7fff,%d1 # strip sign
11716 1.1 is andi.w &0x8000,%d2 # keep old sign
11717 1.1 is sub.l %d0,%d1 # add scale factor
11718 1.1 is addi.l &0x6000,%d1 # subtract new bias
11719 1.1 is andi.w &0x7fff,%d1 # clear top bit
11720 1.1 is or.w %d2,%d1 # concat sgn,exp
11721 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
11722 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
11723 1.1 is bra.w fsub_unfl_dis
11724 1.1 is
11725 1.1 is fsub_unfl_ena_sd:
11726 1.1 is mov.l L_SCR3(%a6),%d1
11727 1.1 is andi.b &0x30,%d1 # clear rnd prec
11728 1.1 is fmov.l %d1,%fpcr # set FPCR
11729 1.1 is
11730 1.1 is bra.b fsub_unfl_ena_cont
11731 1.1 is
11732 1.1 is #
11733 1.1 is # result is equal to the smallest normalized number in the selected precision
11734 1.1 is # if the precision is extended, this result could not have come from an
11735 1.1 is # underflow that rounded up.
11736 1.1 is #
11737 1.1 is fsub_may_unfl:
11738 1.1 is mov.l L_SCR3(%a6),%d1
11739 1.1 is andi.b &0xc0,%d1 # fetch rnd prec
11740 1.1 is beq.w fsub_normal # yes; no underflow occurred
11741 1.1 is
11742 1.1 is mov.l 0x4(%sp),%d1
11743 1.1 is cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000?
11744 1.1 is bne.w fsub_normal # no; no underflow occurred
11745 1.1 is
11746 1.1 is tst.l 0x8(%sp) # is lo(man) = 0x0?
11747 1.1 is bne.w fsub_normal # no; no underflow occurred
11748 1.1 is
11749 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11750 1.1 is beq.w fsub_normal # no; no underflow occurred
11751 1.1 is
11752 1.1 is #
11753 1.1 is # ok, so now the result has a exponent equal to the smallest normalized
11754 1.1 is # exponent for the selected precision. also, the mantissa is equal to
11755 1.1 is # 0x8000000000000000 and this mantissa is the result of rounding non-zero
11756 1.1 is # g,r,s.
11757 1.1 is # now, we must determine whether the pre-rounded result was an underflow
11758 1.1 is # rounded "up" or a normalized number rounded "down".
11759 1.1 is # so, we do this be re-executing the add using RZ as the rounding mode and
11760 1.1 is # seeing if the new result is smaller or equal to the current result.
11761 1.1 is #
11762 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
11763 1.1 is
11764 1.1 is mov.l L_SCR3(%a6),%d1
11765 1.1 is andi.b &0xc0,%d1 # keep rnd prec
11766 1.1 is ori.b &rz_mode*0x10,%d1 # insert rnd mode
11767 1.1 is fmov.l %d1,%fpcr # set FPCR
11768 1.1 is fmov.l &0x0,%fpsr # clear FPSR
11769 1.1 is
11770 1.1 is fsub.x FP_SCR0(%a6),%fp1 # execute subtract
11771 1.1 is
11772 1.1 is fmov.l &0x0,%fpcr # clear FPCR
11773 1.1 is
11774 1.1 is fabs.x %fp0 # compare absolute values
11775 1.1 is fabs.x %fp1
11776 1.1 is fcmp.x %fp0,%fp1 # is first result > second?
11777 1.1 is
11778 1.1 is fbgt.w fsub_unfl # yes; it's an underflow
11779 1.1 is bra.w fsub_normal # no; it's not an underflow
11780 1.1 is
11781 1.1 is ##########################################################################
11782 1.1 is
11783 1.1 is #
11784 1.1 is # Sub: inputs are not both normalized; what are they?
11785 1.1 is #
11786 1.1 is fsub_not_norm:
11787 1.1 is mov.w (tbl_fsub_op.b,%pc,%d1.w*2),%d1
11788 1.1 is jmp (tbl_fsub_op.b,%pc,%d1.w*1)
11789 1.1 is
11790 1.1 is swbeg &48
11791 1.1 is tbl_fsub_op:
11792 1.1 is short fsub_norm - tbl_fsub_op # NORM - NORM
11793 1.1 is short fsub_zero_src - tbl_fsub_op # NORM - ZERO
11794 1.1 is short fsub_inf_src - tbl_fsub_op # NORM - INF
11795 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11796 1.1 is short fsub_norm - tbl_fsub_op # NORM - DENORM
11797 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11798 1.1 is short tbl_fsub_op - tbl_fsub_op #
11799 1.1 is short tbl_fsub_op - tbl_fsub_op #
11800 1.1 is
11801 1.1 is short fsub_zero_dst - tbl_fsub_op # ZERO - NORM
11802 1.1 is short fsub_zero_2 - tbl_fsub_op # ZERO - ZERO
11803 1.1 is short fsub_inf_src - tbl_fsub_op # ZERO - INF
11804 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11805 1.1 is short fsub_zero_dst - tbl_fsub_op # ZERO - DENORM
11806 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11807 1.1 is short tbl_fsub_op - tbl_fsub_op #
11808 1.1 is short tbl_fsub_op - tbl_fsub_op #
11809 1.1 is
11810 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - NORM
11811 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - ZERO
11812 1.1 is short fsub_inf_2 - tbl_fsub_op # INF - INF
11813 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11814 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - DENORM
11815 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11816 1.1 is short tbl_fsub_op - tbl_fsub_op #
11817 1.1 is short tbl_fsub_op - tbl_fsub_op #
11818 1.1 is
11819 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - NORM
11820 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - ZERO
11821 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - INF
11822 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - QNAN
11823 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - DENORM
11824 1.1 is short fsub_res_snan - tbl_fsub_op # QNAN - SNAN
11825 1.1 is short tbl_fsub_op - tbl_fsub_op #
11826 1.1 is short tbl_fsub_op - tbl_fsub_op #
11827 1.1 is
11828 1.1 is short fsub_norm - tbl_fsub_op # DENORM - NORM
11829 1.1 is short fsub_zero_src - tbl_fsub_op # DENORM - ZERO
11830 1.1 is short fsub_inf_src - tbl_fsub_op # DENORM - INF
11831 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11832 1.1 is short fsub_norm - tbl_fsub_op # DENORM - DENORM
11833 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11834 1.1 is short tbl_fsub_op - tbl_fsub_op #
11835 1.1 is short tbl_fsub_op - tbl_fsub_op #
11836 1.1 is
11837 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - NORM
11838 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - ZERO
11839 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - INF
11840 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - QNAN
11841 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - DENORM
11842 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - SNAN
11843 1.1 is short tbl_fsub_op - tbl_fsub_op #
11844 1.1 is short tbl_fsub_op - tbl_fsub_op #
11845 1.1 is
11846 1.1 is fsub_res_qnan:
11847 1.1 is bra.l res_qnan
11848 1.1 is fsub_res_snan:
11849 1.1 is bra.l res_snan
11850 1.1 is
11851 1.1 is #
11852 1.1 is # both operands are ZEROes
11853 1.1 is #
11854 1.1 is fsub_zero_2:
11855 1.1 is mov.b SRC_EX(%a0),%d0
11856 1.1 is mov.b DST_EX(%a1),%d1
11857 1.1 is eor.b %d1,%d0
11858 1.1 is bpl.b fsub_zero_2_chk_rm
11859 1.1 is
11860 1.1 is # the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO
11861 1.1 is tst.b %d0 # is dst negative?
11862 1.1 is bmi.b fsub_zero_2_rm # yes
11863 1.1 is fmov.s &0x00000000,%fp0 # no; return +ZERO
11864 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
11865 1.1 is rts
11866 1.1 is
11867 1.1 is #
11868 1.1 is # the ZEROes have the same signs:
11869 1.1 is # - therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
11870 1.1 is # - -ZERO is returned in the case of RM.
11871 1.1 is #
11872 1.1 is fsub_zero_2_chk_rm:
11873 1.1 is mov.b 3+L_SCR3(%a6),%d1
11874 1.1 is andi.b &0x30,%d1 # extract rnd mode
11875 1.1 is cmpi.b %d1,&rm_mode*0x10 # is rnd mode = RM?
11876 1.1 is beq.b fsub_zero_2_rm # yes
11877 1.1 is fmov.s &0x00000000,%fp0 # no; return +ZERO
11878 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z
11879 1.1 is rts
11880 1.1 is
11881 1.1 is fsub_zero_2_rm:
11882 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO
11883 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG
11884 1.1 is rts
11885 1.1 is
11886 1.1 is #
11887 1.1 is # one operand is a ZERO and the other is a DENORM or a NORM.
11888 1.1 is # scale the DENORM or NORM and jump to the regular fsub routine.
11889 1.1 is #
11890 1.1 is fsub_zero_dst:
11891 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
11892 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
11893 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
11894 1.1 is bsr.l scale_to_zero_src # scale the operand
11895 1.1 is clr.w FP_SCR1_EX(%a6)
11896 1.1 is clr.l FP_SCR1_HI(%a6)
11897 1.1 is clr.l FP_SCR1_LO(%a6)
11898 1.1 is bra.w fsub_zero_entry # go execute fsub
11899 1.1 is
11900 1.1 is fsub_zero_src:
11901 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
11902 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
11903 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
11904 1.1 is bsr.l scale_to_zero_dst # scale the operand
11905 1.1 is clr.w FP_SCR0_EX(%a6)
11906 1.1 is clr.l FP_SCR0_HI(%a6)
11907 1.1 is clr.l FP_SCR0_LO(%a6)
11908 1.1 is bra.w fsub_zero_entry # go execute fsub
11909 1.1 is
11910 1.1 is #
11911 1.1 is # both operands are INFs. an OPERR will result if the INFs have the
11912 1.1 is # same signs. else,
11913 1.1 is #
11914 1.1 is fsub_inf_2:
11915 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs
11916 1.1 is mov.b DST_EX(%a1),%d1
11917 1.1 is eor.b %d1,%d0
11918 1.1 is bpl.l res_operr # weed out (-INF)+(+INF)
11919 1.1 is
11920 1.1 is # ok, so it's not an OPERR. but we do have to remember to return
11921 1.1 is # the src INF since that's where the 881/882 gets the j-bit.
11922 1.1 is
11923 1.1 is fsub_inf_src:
11924 1.1 is fmovm.x SRC(%a0),&0x80 # return src INF
11925 1.1 is fneg.x %fp0 # invert sign
11926 1.1 is fbge.w fsub_inf_done # sign is now positive
11927 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11928 1.1 is rts
11929 1.1 is
11930 1.1 is fsub_inf_dst:
11931 1.1 is fmovm.x DST(%a1),&0x80 # return dst INF
11932 1.1 is tst.b DST_EX(%a1) # is INF negative?
11933 1.1 is bpl.b fsub_inf_done # no
11934 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11935 1.1 is rts
11936 1.1 is
11937 1.1 is fsub_inf_done:
11938 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF
11939 1.1 is rts
11940 1.1 is
11941 1.1 is #########################################################################
11942 1.1 is # XDEF **************************************************************** #
11943 1.1 is # fsqrt(): emulates the fsqrt instruction #
11944 1.1 is # fssqrt(): emulates the fssqrt instruction #
11945 1.1 is # fdsqrt(): emulates the fdsqrt instruction #
11946 1.1 is # #
11947 1.1 is # XREF **************************************************************** #
11948 1.1 is # scale_sqrt() - scale the source operand #
11949 1.1 is # unf_res() - return default underflow result #
11950 1.1 is # ovf_res() - return default overflow result #
11951 1.1 is # res_qnan_1op() - return QNAN result #
11952 1.1 is # res_snan_1op() - return SNAN result #
11953 1.1 is # #
11954 1.1 is # INPUT *************************************************************** #
11955 1.1 is # a0 = pointer to extended precision source operand #
11956 1.1 is # d0 rnd prec,mode #
11957 1.1 is # #
11958 1.1 is # OUTPUT ************************************************************** #
11959 1.1 is # fp0 = result #
11960 1.1 is # fp1 = EXOP (if exception occurred) #
11961 1.1 is # #
11962 1.1 is # ALGORITHM *********************************************************** #
11963 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide #
11964 1.1 is # norms/denorms into ext/sgl/dbl precision. #
11965 1.1 is # For norms/denorms, scale the exponents such that a sqrt #
11966 1.1 is # instruction won't cause an exception. Use the regular fsqrt to #
11967 1.1 is # compute a result. Check if the regular operands would have taken #
11968 1.1 is # an exception. If so, return the default overflow/underflow result #
11969 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the #
11970 1.1 is # result operand to the proper exponent. #
11971 1.1 is # #
11972 1.1 is #########################################################################
11973 1.1 is
11974 1.1 is global fssqrt
11975 1.1 is fssqrt:
11976 1.1 is andi.b &0x30,%d0 # clear rnd prec
11977 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision
11978 1.1 is bra.b fsqrt
11979 1.1 is
11980 1.1 is global fdsqrt
11981 1.1 is fdsqrt:
11982 1.1 is andi.b &0x30,%d0 # clear rnd prec
11983 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision
11984 1.1 is
11985 1.1 is global fsqrt
11986 1.1 is fsqrt:
11987 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info
11988 1.1 is clr.w %d1
11989 1.1 is mov.b STAG(%a6),%d1
11990 1.1 is bne.w fsqrt_not_norm # optimize on non-norm input
11991 1.1 is
11992 1.1 is #
11993 1.1 is # SQUARE ROOT: norms and denorms ONLY!
11994 1.1 is #
11995 1.1 is fsqrt_norm:
11996 1.1 is tst.b SRC_EX(%a0) # is operand negative?
11997 1.1 is bmi.l res_operr # yes
11998 1.1 is
11999 1.1 is andi.b &0xc0,%d0 # is precision extended?
12000 1.1 is bne.b fsqrt_not_ext # no; go handle sgl or dbl
12001 1.1 is
12002 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
12003 1.1 is fmov.l &0x0,%fpsr # clear FPSR
12004 1.1 is
12005 1.1 is fsqrt.x (%a0),%fp0 # execute square root
12006 1.1 is
12007 1.1 is fmov.l %fpsr,%d1
12008 1.1 is or.l %d1,USER_FPSR(%a6) # set N,INEX
12009 1.1 is
12010 1.1 is rts
12011 1.1 is
12012 1.1 is fsqrt_denorm:
12013 1.1 is tst.b SRC_EX(%a0) # is operand negative?
12014 1.1 is bmi.l res_operr # yes
12015 1.1 is
12016 1.1 is andi.b &0xc0,%d0 # is precision extended?
12017 1.1 is bne.b fsqrt_not_ext # no; go handle sgl or dbl
12018 1.1 is
12019 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12020 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12021 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12022 1.1 is
12023 1.1 is bsr.l scale_sqrt # calculate scale factor
12024 1.1 is
12025 1.1 is bra.w fsqrt_sd_normal
12026 1.1 is
12027 1.1 is #
12028 1.1 is # operand is either single or double
12029 1.1 is #
12030 1.1 is fsqrt_not_ext:
12031 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
12032 1.1 is bne.w fsqrt_dbl
12033 1.1 is
12034 1.1 is #
12035 1.1 is # operand is to be rounded to single precision
12036 1.1 is #
12037 1.1 is fsqrt_sgl:
12038 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12039 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12040 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12041 1.1 is
12042 1.1 is bsr.l scale_sqrt # calculate scale factor
12043 1.1 is
12044 1.1 is cmpi.l %d0,&0x3fff-0x3f81 # will move in underflow?
12045 1.1 is beq.w fsqrt_sd_may_unfl
12046 1.1 is bgt.w fsqrt_sd_unfl # yes; go handle underflow
12047 1.1 is cmpi.l %d0,&0x3fff-0x407f # will move in overflow?
12048 1.1 is beq.w fsqrt_sd_may_ovfl # maybe; go check
12049 1.1 is blt.w fsqrt_sd_ovfl # yes; go handle overflow
12050 1.1 is
12051 1.1 is #
12052 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file
12053 1.1 is #
12054 1.1 is fsqrt_sd_normal:
12055 1.1 is fmov.l &0x0,%fpsr # clear FPSR
12056 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
12057 1.1 is
12058 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute
12059 1.1 is
12060 1.1 is fmov.l %fpsr,%d1 # save FPSR
12061 1.1 is fmov.l &0x0,%fpcr # clear FPCR
12062 1.1 is
12063 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
12064 1.1 is
12065 1.1 is fsqrt_sd_normal_exit:
12066 1.1 is mov.l %d2,-(%sp) # save d2
12067 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
12068 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
12069 1.1 is mov.l %d1,%d2 # make a copy
12070 1.1 is andi.l &0x7fff,%d1 # strip sign
12071 1.1 is sub.l %d0,%d1 # add scale factor
12072 1.1 is andi.w &0x8000,%d2 # keep old sign
12073 1.1 is or.w %d1,%d2 # concat old sign,new exp
12074 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
12075 1.1 is mov.l (%sp)+,%d2 # restore d2
12076 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
12077 1.1 is rts
12078 1.1 is
12079 1.1 is #
12080 1.1 is # operand is to be rounded to double precision
12081 1.1 is #
12082 1.1 is fsqrt_dbl:
12083 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12084 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12085 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12086 1.1 is
12087 1.1 is bsr.l scale_sqrt # calculate scale factor
12088 1.1 is
12089 1.1 is cmpi.l %d0,&0x3fff-0x3c01 # will move in underflow?
12090 1.1 is beq.w fsqrt_sd_may_unfl
12091 1.1 is bgt.b fsqrt_sd_unfl # yes; go handle underflow
12092 1.1 is cmpi.l %d0,&0x3fff-0x43ff # will move in overflow?
12093 1.1 is beq.w fsqrt_sd_may_ovfl # maybe; go check
12094 1.1 is blt.w fsqrt_sd_ovfl # yes; go handle overflow
12095 1.1 is bra.w fsqrt_sd_normal # no; ho handle normalized op
12096 1.1 is
12097 1.1 is # we're on the line here and the distinguising characteristic is whether
12098 1.1 is # the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number
12099 1.1 is # elsewise fall through to underflow.
12100 1.1 is fsqrt_sd_may_unfl:
12101 1.1 is btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff?
12102 1.1 is bne.w fsqrt_sd_normal # yes, so no underflow
12103 1.1 is
12104 1.1 is #
12105 1.1 is # operand WILL underflow when moved in to the fp register file
12106 1.1 is #
12107 1.1 is fsqrt_sd_unfl:
12108 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12109 1.1 is
12110 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR
12111 1.1 is fmov.l &0x0,%fpsr # clear FPSR
12112 1.1 is
12113 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # execute square root
12114 1.1 is
12115 1.1 is fmov.l %fpsr,%d1 # save status
12116 1.1 is fmov.l &0x0,%fpcr # clear FPCR
12117 1.1 is
12118 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
12119 1.1 is
12120 1.1 is # if underflow or inexact is enabled, go calculate EXOP first.
12121 1.1 is mov.b FPCR_ENABLE(%a6),%d1
12122 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled?
12123 1.1 is bne.b fsqrt_sd_unfl_ena # yes
12124 1.1 is
12125 1.1 is fsqrt_sd_unfl_dis:
12126 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result
12127 1.1 is
12128 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr
12129 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
12130 1.1 is bsr.l unf_res # calculate default result
12131 1.1 is or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode
12132 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
12133 1.1 is rts
12134 1.1 is
12135 1.1 is #
12136 1.1 is # operand will underflow AND underflow is enabled.
12137 1.1 is # therefore, we must return the result rounded to extended precision.
12138 1.1 is #
12139 1.1 is fsqrt_sd_unfl_ena:
12140 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
12141 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
12142 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
12143 1.1 is
12144 1.1 is mov.l %d2,-(%sp) # save d2
12145 1.1 is mov.l %d1,%d2 # make a copy
12146 1.1 is andi.l &0x7fff,%d1 # strip sign
12147 1.1 is andi.w &0x8000,%d2 # keep old sign
12148 1.1 is sub.l %d0,%d1 # subtract scale factor
12149 1.1 is addi.l &0x6000,%d1 # add new bias
12150 1.1 is andi.w &0x7fff,%d1
12151 1.1 is or.w %d2,%d1 # concat new sign,new exp
12152 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
12153 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
12154 1.1 is mov.l (%sp)+,%d2 # restore d2
12155 1.1 is bra.b fsqrt_sd_unfl_dis
12156 1.1 is
12157 1.1 is #
12158 1.1 is # operand WILL overflow.
12159 1.1 is #
12160 1.1 is fsqrt_sd_ovfl:
12161 1.1 is fmov.l &0x0,%fpsr # clear FPSR
12162 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
12163 1.1 is
12164 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform square root
12165 1.1 is
12166 1.1 is fmov.l &0x0,%fpcr # clear FPCR
12167 1.1 is fmov.l %fpsr,%d1 # save FPSR
12168 1.1 is
12169 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
12170 1.1 is
12171 1.1 is fsqrt_sd_ovfl_tst:
12172 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12173 1.1 is
12174 1.1 is mov.b FPCR_ENABLE(%a6),%d1
12175 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled?
12176 1.1 is bne.b fsqrt_sd_ovfl_ena # yes
12177 1.1 is
12178 1.1 is #
12179 1.1 is # OVFL is not enabled; therefore, we must create the default result by
12180 1.1 is # calling ovf_res().
12181 1.1 is #
12182 1.1 is fsqrt_sd_ovfl_dis:
12183 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative?
12184 1.1 is sne %d1 # set sign param accordingly
12185 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode
12186 1.1 is bsr.l ovf_res # calculate default result
12187 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
12188 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0
12189 1.1 is rts
12190 1.1 is
12191 1.1 is #
12192 1.1 is # OVFL is enabled.
12193 1.1 is # the INEX2 bit has already been updated by the round to the correct precision.
12194 1.1 is # now, round to extended(and don't alter the FPSR).
12195 1.1 is #
12196 1.1 is fsqrt_sd_ovfl_ena:
12197 1.1 is mov.l %d2,-(%sp) # save d2
12198 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
12199 1.1 is mov.l %d1,%d2 # make a copy
12200 1.1 is andi.l &0x7fff,%d1 # strip sign
12201 1.1 is andi.w &0x8000,%d2 # keep old sign
12202 1.1 is sub.l %d0,%d1 # add scale factor
12203 1.1 is subi.l &0x6000,%d1 # subtract bias
12204 1.1 is andi.w &0x7fff,%d1
12205 1.1 is or.w %d2,%d1 # concat sign,exp
12206 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
12207 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
12208 1.1 is mov.l (%sp)+,%d2 # restore d2
12209 1.1 is bra.b fsqrt_sd_ovfl_dis
12210 1.1 is
12211 1.1 is #
12212 1.1 is # the move in MAY underflow. so...
12213 1.1 is #
12214 1.1 is fsqrt_sd_may_ovfl:
12215 1.1 is btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff?
12216 1.1 is bne.w fsqrt_sd_ovfl # yes, so overflow
12217 1.1 is
12218 1.1 is fmov.l &0x0,%fpsr # clear FPSR
12219 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR
12220 1.1 is
12221 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute
12222 1.1 is
12223 1.1 is fmov.l %fpsr,%d1 # save status
12224 1.1 is fmov.l &0x0,%fpcr # clear FPCR
12225 1.1 is
12226 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N
12227 1.1 is
12228 1.1 is fmov.x %fp0,%fp1 # make a copy of result
12229 1.1 is fcmp.b %fp1,&0x1 # is |result| >= 1.b?
12230 1.1 is fbge.w fsqrt_sd_ovfl_tst # yes; overflow has occurred
12231 1.1 is
12232 1.1 is # no, it didn't overflow; we have correct result
12233 1.1 is bra.w fsqrt_sd_normal_exit
12234 1.1 is
12235 1.1 is ##########################################################################
12236 1.1 is
12237 1.1 is #
12238 1.1 is # input is not normalized; what is it?
12239 1.1 is #
12240 1.1 is fsqrt_not_norm:
12241 1.1 is cmpi.b %d1,&DENORM # weed out DENORM
12242 1.1 is beq.w fsqrt_denorm
12243 1.1 is cmpi.b %d1,&ZERO # weed out ZERO
12244 1.1 is beq.b fsqrt_zero
12245 1.1 is cmpi.b %d1,&INF # weed out INF
12246 1.1 is beq.b fsqrt_inf
12247 1.1 is cmpi.b %d1,&SNAN # weed out SNAN
12248 1.1 is beq.l res_snan_1op
12249 1.1 is bra.l res_qnan_1op
12250 1.1 is
12251 1.1 is #
12252 1.1 is # fsqrt(+0) = +0
12253 1.1 is # fsqrt(-0) = -0
12254 1.1 is # fsqrt(+INF) = +INF
12255 1.1 is # fsqrt(-INF) = OPERR
12256 1.1 is #
12257 1.1 is fsqrt_zero:
12258 1.1 is tst.b SRC_EX(%a0) # is ZERO positive or negative?
12259 1.1 is bmi.b fsqrt_zero_m # negative
12260 1.1 is fsqrt_zero_p:
12261 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO
12262 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
12263 1.1 is rts
12264 1.1 is fsqrt_zero_m:
12265 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO
12266 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
12267 1.1 is rts
12268 1.1 is
12269 1.1 is fsqrt_inf:
12270 1.1 is tst.b SRC_EX(%a0) # is INF positive or negative?
12271 1.1 is bmi.l res_operr # negative
12272 1.1 is fsqrt_inf_p:
12273 1.1 is fmovm.x SRC(%a0),&0x80 # return +INF in fp0
12274 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
12275 1.1 is rts
12276 1.1 is
12277 1.1 is #########################################################################
12278 1.1 is # XDEF **************************************************************** #
12279 1.1 is # fetch_dreg(): fetch register according to index in d1 #
12280 1.1 is # #
12281 1.1 is # XREF **************************************************************** #
12282 1.1 is # None #
12283 1.1 is # #
12284 1.1 is # INPUT *************************************************************** #
12285 1.1 is # d1 = index of register to fetch from #
12286 1.1 is # #
12287 1.1 is # OUTPUT ************************************************************** #
12288 1.1 is # d0 = value of register fetched #
12289 1.1 is # #
12290 1.1 is # ALGORITHM *********************************************************** #
12291 1.1 is # According to the index value in d1 which can range from zero #
12292 1.1 is # to fifteen, load the corresponding register file value (where #
12293 1.1 is # address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the #
12294 1.1 is # stack. The rest should still be in their original places. #
12295 1.1 is # #
12296 1.1 is #########################################################################
12297 1.1 is
12298 1.1 is # this routine leaves d1 intact for subsequent store_dreg calls.
12299 1.1 is global fetch_dreg
12300 1.1 is fetch_dreg:
12301 1.1 is mov.w (tbl_fdreg.b,%pc,%d1.w*2),%d0
12302 1.1 is jmp (tbl_fdreg.b,%pc,%d0.w*1)
12303 1.1 is
12304 1.1 is tbl_fdreg:
12305 1.1 is short fdreg0 - tbl_fdreg
12306 1.1 is short fdreg1 - tbl_fdreg
12307 1.1 is short fdreg2 - tbl_fdreg
12308 1.1 is short fdreg3 - tbl_fdreg
12309 1.1 is short fdreg4 - tbl_fdreg
12310 1.1 is short fdreg5 - tbl_fdreg
12311 1.1 is short fdreg6 - tbl_fdreg
12312 1.1 is short fdreg7 - tbl_fdreg
12313 1.1 is short fdreg8 - tbl_fdreg
12314 1.1 is short fdreg9 - tbl_fdreg
12315 1.1 is short fdrega - tbl_fdreg
12316 1.1 is short fdregb - tbl_fdreg
12317 1.1 is short fdregc - tbl_fdreg
12318 1.1 is short fdregd - tbl_fdreg
12319 1.1 is short fdrege - tbl_fdreg
12320 1.1 is short fdregf - tbl_fdreg
12321 1.1 is
12322 1.1 is fdreg0:
12323 1.1 is mov.l EXC_DREGS+0x0(%a6),%d0
12324 1.1 is rts
12325 1.1 is fdreg1:
12326 1.1 is mov.l EXC_DREGS+0x4(%a6),%d0
12327 1.1 is rts
12328 1.1 is fdreg2:
12329 1.1 is mov.l %d2,%d0
12330 1.1 is rts
12331 1.1 is fdreg3:
12332 1.1 is mov.l %d3,%d0
12333 1.1 is rts
12334 1.1 is fdreg4:
12335 1.1 is mov.l %d4,%d0
12336 1.1 is rts
12337 1.1 is fdreg5:
12338 1.1 is mov.l %d5,%d0
12339 1.1 is rts
12340 1.1 is fdreg6:
12341 1.1 is mov.l %d6,%d0
12342 1.1 is rts
12343 1.1 is fdreg7:
12344 1.1 is mov.l %d7,%d0
12345 1.1 is rts
12346 1.1 is fdreg8:
12347 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0
12348 1.1 is rts
12349 1.1 is fdreg9:
12350 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0
12351 1.1 is rts
12352 1.1 is fdrega:
12353 1.1 is mov.l %a2,%d0
12354 1.1 is rts
12355 1.1 is fdregb:
12356 1.1 is mov.l %a3,%d0
12357 1.1 is rts
12358 1.1 is fdregc:
12359 1.1 is mov.l %a4,%d0
12360 1.1 is rts
12361 1.1 is fdregd:
12362 1.1 is mov.l %a5,%d0
12363 1.1 is rts
12364 1.1 is fdrege:
12365 1.1 is mov.l (%a6),%d0
12366 1.1 is rts
12367 1.1 is fdregf:
12368 1.1 is mov.l EXC_A7(%a6),%d0
12369 1.1 is rts
12370 1.1 is
12371 1.1 is #########################################################################
12372 1.1 is # XDEF **************************************************************** #
12373 1.1 is # store_dreg_l(): store longword to data register specified by d1 #
12374 1.1 is # #
12375 1.1 is # XREF **************************************************************** #
12376 1.1 is # None #
12377 1.1 is # #
12378 1.1 is # INPUT *************************************************************** #
12379 1.1 is # d0 = longowrd value to store #
12380 1.1 is # d1 = index of register to fetch from #
12381 1.1 is # #
12382 1.1 is # OUTPUT ************************************************************** #
12383 1.1 is # (data register is updated) #
12384 1.1 is # #
12385 1.1 is # ALGORITHM *********************************************************** #
12386 1.1 is # According to the index value in d1, store the longword value #
12387 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack #
12388 1.1 is # while the rest are in their initial places. #
12389 1.1 is # #
12390 1.1 is #########################################################################
12391 1.1 is
12392 1.1 is global store_dreg_l
12393 1.1 is store_dreg_l:
12394 1.1 is mov.w (tbl_sdregl.b,%pc,%d1.w*2),%d1
12395 1.1 is jmp (tbl_sdregl.b,%pc,%d1.w*1)
12396 1.1 is
12397 1.1 is tbl_sdregl:
12398 1.1 is short sdregl0 - tbl_sdregl
12399 1.1 is short sdregl1 - tbl_sdregl
12400 1.1 is short sdregl2 - tbl_sdregl
12401 1.1 is short sdregl3 - tbl_sdregl
12402 1.1 is short sdregl4 - tbl_sdregl
12403 1.1 is short sdregl5 - tbl_sdregl
12404 1.1 is short sdregl6 - tbl_sdregl
12405 1.1 is short sdregl7 - tbl_sdregl
12406 1.1 is
12407 1.1 is sdregl0:
12408 1.1 is mov.l %d0,EXC_DREGS+0x0(%a6)
12409 1.1 is rts
12410 1.1 is sdregl1:
12411 1.1 is mov.l %d0,EXC_DREGS+0x4(%a6)
12412 1.1 is rts
12413 1.1 is sdregl2:
12414 1.1 is mov.l %d0,%d2
12415 1.1 is rts
12416 1.1 is sdregl3:
12417 1.1 is mov.l %d0,%d3
12418 1.1 is rts
12419 1.1 is sdregl4:
12420 1.1 is mov.l %d0,%d4
12421 1.1 is rts
12422 1.1 is sdregl5:
12423 1.1 is mov.l %d0,%d5
12424 1.1 is rts
12425 1.1 is sdregl6:
12426 1.1 is mov.l %d0,%d6
12427 1.1 is rts
12428 1.1 is sdregl7:
12429 1.1 is mov.l %d0,%d7
12430 1.1 is rts
12431 1.1 is
12432 1.1 is #########################################################################
12433 1.1 is # XDEF **************************************************************** #
12434 1.1 is # store_dreg_w(): store word to data register specified by d1 #
12435 1.1 is # #
12436 1.1 is # XREF **************************************************************** #
12437 1.1 is # None #
12438 1.1 is # #
12439 1.1 is # INPUT *************************************************************** #
12440 1.1 is # d0 = word value to store #
12441 1.1 is # d1 = index of register to fetch from #
12442 1.1 is # #
12443 1.1 is # OUTPUT ************************************************************** #
12444 1.1 is # (data register is updated) #
12445 1.1 is # #
12446 1.1 is # ALGORITHM *********************************************************** #
12447 1.1 is # According to the index value in d1, store the word value #
12448 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack #
12449 1.1 is # while the rest are in their initial places. #
12450 1.1 is # #
12451 1.1 is #########################################################################
12452 1.1 is
12453 1.1 is global store_dreg_w
12454 1.1 is store_dreg_w:
12455 1.1 is mov.w (tbl_sdregw.b,%pc,%d1.w*2),%d1
12456 1.1 is jmp (tbl_sdregw.b,%pc,%d1.w*1)
12457 1.1 is
12458 1.1 is tbl_sdregw:
12459 1.1 is short sdregw0 - tbl_sdregw
12460 1.1 is short sdregw1 - tbl_sdregw
12461 1.1 is short sdregw2 - tbl_sdregw
12462 1.1 is short sdregw3 - tbl_sdregw
12463 1.1 is short sdregw4 - tbl_sdregw
12464 1.1 is short sdregw5 - tbl_sdregw
12465 1.1 is short sdregw6 - tbl_sdregw
12466 1.1 is short sdregw7 - tbl_sdregw
12467 1.1 is
12468 1.1 is sdregw0:
12469 1.1 is mov.w %d0,2+EXC_DREGS+0x0(%a6)
12470 1.1 is rts
12471 1.1 is sdregw1:
12472 1.1 is mov.w %d0,2+EXC_DREGS+0x4(%a6)
12473 1.1 is rts
12474 1.1 is sdregw2:
12475 1.1 is mov.w %d0,%d2
12476 1.1 is rts
12477 1.1 is sdregw3:
12478 1.1 is mov.w %d0,%d3
12479 1.1 is rts
12480 1.1 is sdregw4:
12481 1.1 is mov.w %d0,%d4
12482 1.1 is rts
12483 1.1 is sdregw5:
12484 1.1 is mov.w %d0,%d5
12485 1.1 is rts
12486 1.1 is sdregw6:
12487 1.1 is mov.w %d0,%d6
12488 1.1 is rts
12489 1.1 is sdregw7:
12490 1.1 is mov.w %d0,%d7
12491 1.1 is rts
12492 1.1 is
12493 1.1 is #########################################################################
12494 1.1 is # XDEF **************************************************************** #
12495 1.1 is # store_dreg_b(): store byte to data register specified by d1 #
12496 1.1 is # #
12497 1.1 is # XREF **************************************************************** #
12498 1.1 is # None #
12499 1.1 is # #
12500 1.1 is # INPUT *************************************************************** #
12501 1.1 is # d0 = byte value to store #
12502 1.1 is # d1 = index of register to fetch from #
12503 1.1 is # #
12504 1.1 is # OUTPUT ************************************************************** #
12505 1.1 is # (data register is updated) #
12506 1.1 is # #
12507 1.1 is # ALGORITHM *********************************************************** #
12508 1.1 is # According to the index value in d1, store the byte value #
12509 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack #
12510 1.1 is # while the rest are in their initial places. #
12511 1.1 is # #
12512 1.1 is #########################################################################
12513 1.1 is
12514 1.1 is global store_dreg_b
12515 1.1 is store_dreg_b:
12516 1.1 is mov.w (tbl_sdregb.b,%pc,%d1.w*2),%d1
12517 1.1 is jmp (tbl_sdregb.b,%pc,%d1.w*1)
12518 1.1 is
12519 1.1 is tbl_sdregb:
12520 1.1 is short sdregb0 - tbl_sdregb
12521 1.1 is short sdregb1 - tbl_sdregb
12522 1.1 is short sdregb2 - tbl_sdregb
12523 1.1 is short sdregb3 - tbl_sdregb
12524 1.1 is short sdregb4 - tbl_sdregb
12525 1.1 is short sdregb5 - tbl_sdregb
12526 1.1 is short sdregb6 - tbl_sdregb
12527 1.1 is short sdregb7 - tbl_sdregb
12528 1.1 is
12529 1.1 is sdregb0:
12530 1.1 is mov.b %d0,3+EXC_DREGS+0x0(%a6)
12531 1.1 is rts
12532 1.1 is sdregb1:
12533 1.1 is mov.b %d0,3+EXC_DREGS+0x4(%a6)
12534 1.1 is rts
12535 1.1 is sdregb2:
12536 1.1 is mov.b %d0,%d2
12537 1.1 is rts
12538 1.1 is sdregb3:
12539 1.1 is mov.b %d0,%d3
12540 1.1 is rts
12541 1.1 is sdregb4:
12542 1.1 is mov.b %d0,%d4
12543 1.1 is rts
12544 1.1 is sdregb5:
12545 1.1 is mov.b %d0,%d5
12546 1.1 is rts
12547 1.1 is sdregb6:
12548 1.1 is mov.b %d0,%d6
12549 1.1 is rts
12550 1.1 is sdregb7:
12551 1.1 is mov.b %d0,%d7
12552 1.1 is rts
12553 1.1 is
12554 1.1 is #########################################################################
12555 1.1 is # XDEF **************************************************************** #
12556 1.1 is # inc_areg(): increment an address register by the value in d0 #
12557 1.1 is # #
12558 1.1 is # XREF **************************************************************** #
12559 1.1 is # None #
12560 1.1 is # #
12561 1.1 is # INPUT *************************************************************** #
12562 1.1 is # d0 = amount to increment by #
12563 1.1 is # d1 = index of address register to increment #
12564 1.1 is # #
12565 1.1 is # OUTPUT ************************************************************** #
12566 1.1 is # (address register is updated) #
12567 1.1 is # #
12568 1.1 is # ALGORITHM *********************************************************** #
12569 1.1 is # Typically used for an instruction w/ a post-increment <ea>, #
12570 1.1 is # this routine adds the increment value in d0 to the address register #
12571 1.1 is # specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside #
12572 1.1 is # in their original places. #
12573 1.1 is # For a7, if the increment amount is one, then we have to #
12574 1.1 is # increment by two. For any a7 update, set the mia7_flag so that if #
12575 1.1 is # an access error exception occurs later in emulation, this address #
12576 1.1 is # register update can be undone. #
12577 1.1 is # #
12578 1.1 is #########################################################################
12579 1.1 is
12580 1.1 is global inc_areg
12581 1.1 is inc_areg:
12582 1.1 is mov.w (tbl_iareg.b,%pc,%d1.w*2),%d1
12583 1.1 is jmp (tbl_iareg.b,%pc,%d1.w*1)
12584 1.1 is
12585 1.1 is tbl_iareg:
12586 1.1 is short iareg0 - tbl_iareg
12587 1.1 is short iareg1 - tbl_iareg
12588 1.1 is short iareg2 - tbl_iareg
12589 1.1 is short iareg3 - tbl_iareg
12590 1.1 is short iareg4 - tbl_iareg
12591 1.1 is short iareg5 - tbl_iareg
12592 1.1 is short iareg6 - tbl_iareg
12593 1.1 is short iareg7 - tbl_iareg
12594 1.1 is
12595 1.1 is iareg0: add.l %d0,EXC_DREGS+0x8(%a6)
12596 1.1 is rts
12597 1.1 is iareg1: add.l %d0,EXC_DREGS+0xc(%a6)
12598 1.1 is rts
12599 1.1 is iareg2: add.l %d0,%a2
12600 1.1 is rts
12601 1.1 is iareg3: add.l %d0,%a3
12602 1.1 is rts
12603 1.1 is iareg4: add.l %d0,%a4
12604 1.1 is rts
12605 1.1 is iareg5: add.l %d0,%a5
12606 1.1 is rts
12607 1.1 is iareg6: add.l %d0,(%a6)
12608 1.1 is rts
12609 1.1 is iareg7: mov.b &mia7_flg,SPCOND_FLG(%a6)
12610 1.1 is cmpi.b %d0,&0x1
12611 1.1 is beq.b iareg7b
12612 1.1 is add.l %d0,EXC_A7(%a6)
12613 1.1 is rts
12614 1.1 is iareg7b:
12615 1.1 is addq.l &0x2,EXC_A7(%a6)
12616 1.1 is rts
12617 1.1 is
12618 1.1 is #########################################################################
12619 1.1 is # XDEF **************************************************************** #
12620 1.1 is # dec_areg(): decrement an address register by the value in d0 #
12621 1.1 is # #
12622 1.1 is # XREF **************************************************************** #
12623 1.1 is # None #
12624 1.1 is # #
12625 1.1 is # INPUT *************************************************************** #
12626 1.1 is # d0 = amount to decrement by #
12627 1.1 is # d1 = index of address register to decrement #
12628 1.1 is # #
12629 1.1 is # OUTPUT ************************************************************** #
12630 1.1 is # (address register is updated) #
12631 1.1 is # #
12632 1.1 is # ALGORITHM *********************************************************** #
12633 1.1 is # Typically used for an instruction w/ a pre-decrement <ea>, #
12634 1.1 is # this routine adds the decrement value in d0 to the address register #
12635 1.1 is # specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside #
12636 1.1 is # in their original places. #
12637 1.1 is # For a7, if the decrement amount is one, then we have to #
12638 1.1 is # decrement by two. For any a7 update, set the mda7_flag so that if #
12639 1.1 is # an access error exception occurs later in emulation, this address #
12640 1.1 is # register update can be undone. #
12641 1.1 is # #
12642 1.1 is #########################################################################
12643 1.1 is
12644 1.1 is global dec_areg
12645 1.1 is dec_areg:
12646 1.1 is mov.w (tbl_dareg.b,%pc,%d1.w*2),%d1
12647 1.1 is jmp (tbl_dareg.b,%pc,%d1.w*1)
12648 1.1 is
12649 1.1 is tbl_dareg:
12650 1.1 is short dareg0 - tbl_dareg
12651 1.1 is short dareg1 - tbl_dareg
12652 1.1 is short dareg2 - tbl_dareg
12653 1.1 is short dareg3 - tbl_dareg
12654 1.1 is short dareg4 - tbl_dareg
12655 1.1 is short dareg5 - tbl_dareg
12656 1.1 is short dareg6 - tbl_dareg
12657 1.1 is short dareg7 - tbl_dareg
12658 1.1 is
12659 1.1 is dareg0: sub.l %d0,EXC_DREGS+0x8(%a6)
12660 1.1 is rts
12661 1.1 is dareg1: sub.l %d0,EXC_DREGS+0xc(%a6)
12662 1.1 is rts
12663 1.1 is dareg2: sub.l %d0,%a2
12664 1.1 is rts
12665 1.1 is dareg3: sub.l %d0,%a3
12666 1.1 is rts
12667 1.1 is dareg4: sub.l %d0,%a4
12668 1.1 is rts
12669 1.1 is dareg5: sub.l %d0,%a5
12670 1.1 is rts
12671 1.1 is dareg6: sub.l %d0,(%a6)
12672 1.1 is rts
12673 1.1 is dareg7: mov.b &mda7_flg,SPCOND_FLG(%a6)
12674 1.1 is cmpi.b %d0,&0x1
12675 1.1 is beq.b dareg7b
12676 1.1 is sub.l %d0,EXC_A7(%a6)
12677 1.1 is rts
12678 1.1 is dareg7b:
12679 1.1 is subq.l &0x2,EXC_A7(%a6)
12680 1.1 is rts
12681 1.1 is
12682 1.1 is ##############################################################################
12683 1.1 is
12684 1.1 is #########################################################################
12685 1.1 is # XDEF **************************************************************** #
12686 1.1 is # load_fpn1(): load FP register value into FP_SRC(a6). #
12687 1.1 is # #
12688 1.1 is # XREF **************************************************************** #
12689 1.1 is # None #
12690 1.1 is # #
12691 1.1 is # INPUT *************************************************************** #
12692 1.1 is # d0 = index of FP register to load #
12693 1.1 is # #
12694 1.1 is # OUTPUT ************************************************************** #
12695 1.1 is # FP_SRC(a6) = value loaded from FP register file #
12696 1.1 is # #
12697 1.1 is # ALGORITHM *********************************************************** #
12698 1.1 is # Using the index in d0, load FP_SRC(a6) with a number from the #
12699 1.1 is # FP register file. #
12700 1.1 is # #
12701 1.1 is #########################################################################
12702 1.1 is
12703 1.1 is global load_fpn1
12704 1.1 is load_fpn1:
12705 1.1 is mov.w (tbl_load_fpn1.b,%pc,%d0.w*2), %d0
12706 1.1 is jmp (tbl_load_fpn1.b,%pc,%d0.w*1)
12707 1.1 is
12708 1.1 is tbl_load_fpn1:
12709 1.1 is short load_fpn1_0 - tbl_load_fpn1
12710 1.1 is short load_fpn1_1 - tbl_load_fpn1
12711 1.1 is short load_fpn1_2 - tbl_load_fpn1
12712 1.1 is short load_fpn1_3 - tbl_load_fpn1
12713 1.1 is short load_fpn1_4 - tbl_load_fpn1
12714 1.1 is short load_fpn1_5 - tbl_load_fpn1
12715 1.1 is short load_fpn1_6 - tbl_load_fpn1
12716 1.1 is short load_fpn1_7 - tbl_load_fpn1
12717 1.1 is
12718 1.1 is load_fpn1_0:
12719 1.1 is mov.l 0+EXC_FP0(%a6), 0+FP_SRC(%a6)
12720 1.1 is mov.l 4+EXC_FP0(%a6), 4+FP_SRC(%a6)
12721 1.1 is mov.l 8+EXC_FP0(%a6), 8+FP_SRC(%a6)
12722 1.1 is lea FP_SRC(%a6), %a0
12723 1.1 is rts
12724 1.1 is load_fpn1_1:
12725 1.1 is mov.l 0+EXC_FP1(%a6), 0+FP_SRC(%a6)
12726 1.1 is mov.l 4+EXC_FP1(%a6), 4+FP_SRC(%a6)
12727 1.1 is mov.l 8+EXC_FP1(%a6), 8+FP_SRC(%a6)
12728 1.1 is lea FP_SRC(%a6), %a0
12729 1.1 is rts
12730 1.1 is load_fpn1_2:
12731 1.1 is fmovm.x &0x20, FP_SRC(%a6)
12732 1.1 is lea FP_SRC(%a6), %a0
12733 1.1 is rts
12734 1.1 is load_fpn1_3:
12735 1.1 is fmovm.x &0x10, FP_SRC(%a6)
12736 1.1 is lea FP_SRC(%a6), %a0
12737 1.1 is rts
12738 1.1 is load_fpn1_4:
12739 1.1 is fmovm.x &0x08, FP_SRC(%a6)
12740 1.1 is lea FP_SRC(%a6), %a0
12741 1.1 is rts
12742 1.1 is load_fpn1_5:
12743 1.1 is fmovm.x &0x04, FP_SRC(%a6)
12744 1.1 is lea FP_SRC(%a6), %a0
12745 1.1 is rts
12746 1.1 is load_fpn1_6:
12747 1.1 is fmovm.x &0x02, FP_SRC(%a6)
12748 1.1 is lea FP_SRC(%a6), %a0
12749 1.1 is rts
12750 1.1 is load_fpn1_7:
12751 1.1 is fmovm.x &0x01, FP_SRC(%a6)
12752 1.1 is lea FP_SRC(%a6), %a0
12753 1.1 is rts
12754 1.1 is
12755 1.1 is #############################################################################
12756 1.1 is
12757 1.1 is #########################################################################
12758 1.1 is # XDEF **************************************************************** #
12759 1.1 is # load_fpn2(): load FP register value into FP_DST(a6). #
12760 1.1 is # #
12761 1.1 is # XREF **************************************************************** #
12762 1.1 is # None #
12763 1.1 is # #
12764 1.1 is # INPUT *************************************************************** #
12765 1.1 is # d0 = index of FP register to load #
12766 1.1 is # #
12767 1.1 is # OUTPUT ************************************************************** #
12768 1.1 is # FP_DST(a6) = value loaded from FP register file #
12769 1.1 is # #
12770 1.1 is # ALGORITHM *********************************************************** #
12771 1.1 is # Using the index in d0, load FP_DST(a6) with a number from the #
12772 1.1 is # FP register file. #
12773 1.1 is # #
12774 1.1 is #########################################################################
12775 1.1 is
12776 1.1 is global load_fpn2
12777 1.1 is load_fpn2:
12778 1.1 is mov.w (tbl_load_fpn2.b,%pc,%d0.w*2), %d0
12779 1.1 is jmp (tbl_load_fpn2.b,%pc,%d0.w*1)
12780 1.1 is
12781 1.1 is tbl_load_fpn2:
12782 1.1 is short load_fpn2_0 - tbl_load_fpn2
12783 1.1 is short load_fpn2_1 - tbl_load_fpn2
12784 1.1 is short load_fpn2_2 - tbl_load_fpn2
12785 1.1 is short load_fpn2_3 - tbl_load_fpn2
12786 1.1 is short load_fpn2_4 - tbl_load_fpn2
12787 1.1 is short load_fpn2_5 - tbl_load_fpn2
12788 1.1 is short load_fpn2_6 - tbl_load_fpn2
12789 1.1 is short load_fpn2_7 - tbl_load_fpn2
12790 1.1 is
12791 1.1 is load_fpn2_0:
12792 1.1 is mov.l 0+EXC_FP0(%a6), 0+FP_DST(%a6)
12793 1.1 is mov.l 4+EXC_FP0(%a6), 4+FP_DST(%a6)
12794 1.1 is mov.l 8+EXC_FP0(%a6), 8+FP_DST(%a6)
12795 1.1 is lea FP_DST(%a6), %a0
12796 1.1 is rts
12797 1.1 is load_fpn2_1:
12798 1.1 is mov.l 0+EXC_FP1(%a6), 0+FP_DST(%a6)
12799 1.1 is mov.l 4+EXC_FP1(%a6), 4+FP_DST(%a6)
12800 1.1 is mov.l 8+EXC_FP1(%a6), 8+FP_DST(%a6)
12801 1.1 is lea FP_DST(%a6), %a0
12802 1.1 is rts
12803 1.1 is load_fpn2_2:
12804 1.1 is fmovm.x &0x20, FP_DST(%a6)
12805 1.1 is lea FP_DST(%a6), %a0
12806 1.1 is rts
12807 1.1 is load_fpn2_3:
12808 1.1 is fmovm.x &0x10, FP_DST(%a6)
12809 1.1 is lea FP_DST(%a6), %a0
12810 1.1 is rts
12811 1.1 is load_fpn2_4:
12812 1.1 is fmovm.x &0x08, FP_DST(%a6)
12813 1.1 is lea FP_DST(%a6), %a0
12814 1.1 is rts
12815 1.1 is load_fpn2_5:
12816 1.1 is fmovm.x &0x04, FP_DST(%a6)
12817 1.1 is lea FP_DST(%a6), %a0
12818 1.1 is rts
12819 1.1 is load_fpn2_6:
12820 1.1 is fmovm.x &0x02, FP_DST(%a6)
12821 1.1 is lea FP_DST(%a6), %a0
12822 1.1 is rts
12823 1.1 is load_fpn2_7:
12824 1.1 is fmovm.x &0x01, FP_DST(%a6)
12825 1.1 is lea FP_DST(%a6), %a0
12826 1.1 is rts
12827 1.1 is
12828 1.1 is #############################################################################
12829 1.1 is
12830 1.1 is #########################################################################
12831 1.1 is # XDEF **************************************************************** #
12832 1.1 is # store_fpreg(): store an fp value to the fpreg designated d0. #
12833 1.1 is # #
12834 1.1 is # XREF **************************************************************** #
12835 1.1 is # None #
12836 1.1 is # #
12837 1.1 is # INPUT *************************************************************** #
12838 1.1 is # fp0 = extended precision value to store #
12839 1.1 is # d0 = index of floating-point register #
12840 1.1 is # #
12841 1.1 is # OUTPUT ************************************************************** #
12842 1.1 is # None #
12843 1.1 is # #
12844 1.1 is # ALGORITHM *********************************************************** #
12845 1.1 is # Store the value in fp0 to the FP register designated by the #
12846 1.1 is # value in d0. The FP number can be DENORM or SNAN so we have to be #
12847 1.1 is # careful that we don't take an exception here. #
12848 1.1 is # #
12849 1.1 is #########################################################################
12850 1.1 is
12851 1.1 is global store_fpreg
12852 1.1 is store_fpreg:
12853 1.1 is mov.w (tbl_store_fpreg.b,%pc,%d0.w*2), %d0
12854 1.1 is jmp (tbl_store_fpreg.b,%pc,%d0.w*1)
12855 1.1 is
12856 1.1 is tbl_store_fpreg:
12857 1.1 is short store_fpreg_0 - tbl_store_fpreg
12858 1.1 is short store_fpreg_1 - tbl_store_fpreg
12859 1.1 is short store_fpreg_2 - tbl_store_fpreg
12860 1.1 is short store_fpreg_3 - tbl_store_fpreg
12861 1.1 is short store_fpreg_4 - tbl_store_fpreg
12862 1.1 is short store_fpreg_5 - tbl_store_fpreg
12863 1.1 is short store_fpreg_6 - tbl_store_fpreg
12864 1.1 is short store_fpreg_7 - tbl_store_fpreg
12865 1.1 is
12866 1.1 is store_fpreg_0:
12867 1.1 is fmovm.x &0x80, EXC_FP0(%a6)
12868 1.1 is rts
12869 1.1 is store_fpreg_1:
12870 1.1 is fmovm.x &0x80, EXC_FP1(%a6)
12871 1.1 is rts
12872 1.1 is store_fpreg_2:
12873 1.1 is fmovm.x &0x01, -(%sp)
12874 1.1 is fmovm.x (%sp)+, &0x20
12875 1.1 is rts
12876 1.1 is store_fpreg_3:
12877 1.1 is fmovm.x &0x01, -(%sp)
12878 1.1 is fmovm.x (%sp)+, &0x10
12879 1.1 is rts
12880 1.1 is store_fpreg_4:
12881 1.1 is fmovm.x &0x01, -(%sp)
12882 1.1 is fmovm.x (%sp)+, &0x08
12883 1.1 is rts
12884 1.1 is store_fpreg_5:
12885 1.1 is fmovm.x &0x01, -(%sp)
12886 1.1 is fmovm.x (%sp)+, &0x04
12887 1.1 is rts
12888 1.1 is store_fpreg_6:
12889 1.1 is fmovm.x &0x01, -(%sp)
12890 1.1 is fmovm.x (%sp)+, &0x02
12891 1.1 is rts
12892 1.1 is store_fpreg_7:
12893 1.1 is fmovm.x &0x01, -(%sp)
12894 1.1 is fmovm.x (%sp)+, &0x01
12895 1.1 is rts
12896 1.1 is
12897 1.1 is #########################################################################
12898 1.1 is # XDEF **************************************************************** #
12899 1.1 is # get_packed(): fetch a packed operand from memory and then #
12900 1.1 is # convert it to a floating-point binary number. #
12901 1.1 is # #
12902 1.1 is # XREF **************************************************************** #
12903 1.1 is # _dcalc_ea() - calculate the correct <ea> #
12904 1.1 is # _mem_read() - fetch the packed operand from memory #
12905 1.1 is # facc_in_x() - the fetch failed so jump to special exit code #
12906 1.1 is # decbin() - convert packed to binary extended precision #
12907 1.1 is # #
12908 1.1 is # INPUT *************************************************************** #
12909 1.1 is # None #
12910 1.1 is # #
12911 1.1 is # OUTPUT ************************************************************** #
12912 1.1 is # If no failure on _mem_read(): #
12913 1.1 is # FP_SRC(a6) = packed operand now as a binary FP number #
12914 1.1 is # #
12915 1.1 is # ALGORITHM *********************************************************** #
12916 1.1 is # Get the correct <ea> whihc is the value on the exception stack #
12917 1.1 is # frame w/ maybe a correction factor if the <ea> is -(an) or (an)+. #
12918 1.1 is # Then, fetch the operand from memory. If the fetch fails, exit #
12919 1.1 is # through facc_in_x(). #
12920 1.1 is # If the packed operand is a ZERO,NAN, or INF, convert it to #
12921 1.1 is # its binary representation here. Else, call decbin() which will #
12922 1.1 is # convert the packed value to an extended precision binary value. #
12923 1.1 is # #
12924 1.1 is #########################################################################
12925 1.1 is
12926 1.1 is # the stacked <ea> for packed is correct except for -(An).
12927 1.1 is # the base reg must be updated for both -(An) and (An)+.
12928 1.1 is global get_packed
12929 1.1 is get_packed:
12930 1.1 is mov.l &0xc,%d0 # packed is 12 bytes
12931 1.1 is bsr.l _dcalc_ea # fetch <ea>; correct An
12932 1.1 is
12933 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super dst
12934 1.1 is mov.l &0xc,%d0 # pass: 12 bytes
12935 1.1 is bsr.l _dmem_read # read packed operand
12936 1.1 is
12937 1.1 is tst.l %d1 # did dfetch fail?
12938 1.1 is bne.l facc_in_x # yes
12939 1.1 is
12940 1.1 is # The packed operand is an INF or a NAN if the exponent field is all ones.
12941 1.1 is bfextu FP_SRC(%a6){&1:&15},%d0 # get exp
12942 1.1 is cmpi.w %d0,&0x7fff # INF or NAN?
12943 1.1 is bne.b gp_try_zero # no
12944 1.1 is rts # operand is an INF or NAN
12945 1.1 is
12946 1.1 is # The packed operand is a zero if the mantissa is all zero, else it's
12947 1.1 is # a normal packed op.
12948 1.1 is gp_try_zero:
12949 1.1 is mov.b 3+FP_SRC(%a6),%d0 # get byte 4
12950 1.1 is andi.b &0x0f,%d0 # clear all but last nybble
12951 1.1 is bne.b gp_not_spec # not a zero
12952 1.1 is tst.l FP_SRC_HI(%a6) # is lw 2 zero?
12953 1.1 is bne.b gp_not_spec # not a zero
12954 1.1 is tst.l FP_SRC_LO(%a6) # is lw 3 zero?
12955 1.1 is bne.b gp_not_spec # not a zero
12956 1.1 is rts # operand is a ZERO
12957 1.1 is gp_not_spec:
12958 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to packed op
12959 1.1 is bsr.l decbin # convert to extended
12960 1.1 is fmovm.x &0x80,FP_SRC(%a6) # make this the srcop
12961 1.1 is rts
12962 1.1 is
12963 1.1 is #########################################################################
12964 1.1 is # decbin(): Converts normalized packed bcd value pointed to by register #
12965 1.1 is # a0 to extended-precision value in fp0. #
12966 1.1 is # #
12967 1.1 is # INPUT *************************************************************** #
12968 1.1 is # a0 = pointer to normalized packed bcd value #
12969 1.1 is # #
12970 1.1 is # OUTPUT ************************************************************** #
12971 1.1 is # fp0 = exact fp representation of the packed bcd value. #
12972 1.1 is # #
12973 1.1 is # ALGORITHM *********************************************************** #
12974 1.1 is # Expected is a normal bcd (i.e. non-exceptional; all inf, zero, #
12975 1.1 is # and NaN operands are dispatched without entering this routine) #
12976 1.1 is # value in 68881/882 format at location (a0). #
12977 1.1 is # #
12978 1.1 is # A1. Convert the bcd exponent to binary by successive adds and #
12979 1.1 is # muls. Set the sign according to SE. Subtract 16 to compensate #
12980 1.1 is # for the mantissa which is to be interpreted as 17 integer #
12981 1.1 is # digits, rather than 1 integer and 16 fraction digits. #
12982 1.1 is # Note: this operation can never overflow. #
12983 1.1 is # #
12984 1.1 is # A2. Convert the bcd mantissa to binary by successive #
12985 1.1 is # adds and muls in FP0. Set the sign according to SM. #
12986 1.1 is # The mantissa digits will be converted with the decimal point #
12987 1.1 is # assumed following the least-significant digit. #
12988 1.1 is # Note: this operation can never overflow. #
12989 1.1 is # #
12990 1.1 is # A3. Count the number of leading/trailing zeros in the #
12991 1.1 is # bcd string. If SE is positive, count the leading zeros; #
12992 1.1 is # if negative, count the trailing zeros. Set the adjusted #
12993 1.1 is # exponent equal to the exponent from A1 and the zero count #
12994 1.1 is # added if SM = 1 and subtracted if SM = 0. Scale the #
12995 1.1 is # mantissa the equivalent of forcing in the bcd value: #
12996 1.1 is # #
12997 1.1 is # SM = 0 a non-zero digit in the integer position #
12998 1.1 is # SM = 1 a non-zero digit in Mant0, lsd of the fraction #
12999 1.1 is # #
13000 1.1 is # this will insure that any value, regardless of its #
13001 1.1 is # representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted #
13002 1.1 is # consistently. #
13003 1.1 is # #
13004 1.1 is # A4. Calculate the factor 10^exp in FP1 using a table of #
13005 1.1 is # 10^(2^n) values. To reduce the error in forming factors #
13006 1.1 is # greater than 10^27, a directed rounding scheme is used with #
13007 1.1 is # tables rounded to RN, RM, and RP, according to the table #
13008 1.1 is # in the comments of the pwrten section. #
13009 1.1 is # #
13010 1.1 is # A5. Form the final binary number by scaling the mantissa by #
13011 1.1 is # the exponent factor. This is done by multiplying the #
13012 1.1 is # mantissa in FP0 by the factor in FP1 if the adjusted #
13013 1.1 is # exponent sign is positive, and dividing FP0 by FP1 if #
13014 1.1 is # it is negative. #
13015 1.1 is # #
13016 1.1 is # Clean up and return. Check if the final mul or div was inexact. #
13017 1.1 is # If so, set INEX1 in USER_FPSR. #
13018 1.1 is # #
13019 1.1 is #########################################################################
13020 1.1 is
13021 1.1 is #
13022 1.1 is # PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
13023 1.1 is # to nearest, minus, and plus, respectively. The tables include
13024 1.1 is # 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}. No rounding
13025 1.1 is # is required until the power is greater than 27, however, all
13026 1.1 is # tables include the first 5 for ease of indexing.
13027 1.1 is #
13028 1.1 is RTABLE:
13029 1.1 is byte 0,0,0,0
13030 1.1 is byte 2,3,2,3
13031 1.1 is byte 2,3,3,2
13032 1.1 is byte 3,2,2,3
13033 1.1 is
13034 1.1 is set FNIBS,7
13035 1.1 is set FSTRT,0
13036 1.1 is
13037 1.1 is set ESTRT,4
13038 1.1 is set EDIGITS,2
13039 1.1 is
13040 1.1 is global decbin
13041 1.1 is decbin:
13042 1.1 is mov.l 0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input
13043 1.1 is mov.l 0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it
13044 1.1 is mov.l 0x8(%a0),FP_SCR0_LO(%a6)
13045 1.1 is
13046 1.1 is lea FP_SCR0(%a6),%a0
13047 1.1 is
13048 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5
13049 1.1 is fmovm.x &0x1,-(%sp) # save fp1
13050 1.1 is #
13051 1.1 is # Calculate exponent:
13052 1.1 is # 1. Copy bcd value in memory for use as a working copy.
13053 1.1 is # 2. Calculate absolute value of exponent in d1 by mul and add.
13054 1.1 is # 3. Correct for exponent sign.
13055 1.1 is # 4. Subtract 16 to compensate for interpreting the mant as all integer digits.
13056 1.1 is # (i.e., all digits assumed left of the decimal point.)
13057 1.1 is #
13058 1.1 is # Register usage:
13059 1.1 is #
13060 1.1 is # calc_e:
13061 1.1 is # (*) d0: temp digit storage
13062 1.1 is # (*) d1: accumulator for binary exponent
13063 1.1 is # (*) d2: digit count
13064 1.1 is # (*) d3: offset pointer
13065 1.1 is # ( ) d4: first word of bcd
13066 1.1 is # ( ) a0: pointer to working bcd value
13067 1.1 is # ( ) a6: pointer to original bcd value
13068 1.1 is # (*) FP_SCR1: working copy of original bcd value
13069 1.1 is # (*) L_SCR1: copy of original exponent word
13070 1.1 is #
13071 1.1 is calc_e:
13072 1.1 is mov.l &EDIGITS,%d2 # # of nibbles (digits) in fraction part
13073 1.1 is mov.l &ESTRT,%d3 # counter to pick up digits
13074 1.1 is mov.l (%a0),%d4 # get first word of bcd
13075 1.1 is clr.l %d1 # zero d1 for accumulator
13076 1.1 is e_gd:
13077 1.1 is mulu.l &0xa,%d1 # mul partial product by one digit place
13078 1.1 is bfextu %d4{%d3:&4},%d0 # get the digit and zero extend into d0
13079 1.1 is add.l %d0,%d1 # d1 = d1 + d0
13080 1.1 is addq.b &4,%d3 # advance d3 to the next digit
13081 1.1 is dbf.w %d2,e_gd # if we have used all 3 digits, exit loop
13082 1.1 is btst &30,%d4 # get SE
13083 1.1 is beq.b e_pos # don't negate if pos
13084 1.1 is neg.l %d1 # negate before subtracting
13085 1.1 is e_pos:
13086 1.1 is sub.l &16,%d1 # sub to compensate for shift of mant
13087 1.1 is bge.b e_save # if still pos, do not neg
13088 1.1 is neg.l %d1 # now negative, make pos and set SE
13089 1.1 is or.l &0x40000000,%d4 # set SE in d4,
13090 1.1 is or.l &0x40000000,(%a0) # and in working bcd
13091 1.1 is e_save:
13092 1.1 is mov.l %d1,-(%sp) # save exp on stack
13093 1.1 is #
13094 1.1 is #
13095 1.1 is # Calculate mantissa:
13096 1.1 is # 1. Calculate absolute value of mantissa in fp0 by mul and add.
13097 1.1 is # 2. Correct for mantissa sign.
13098 1.1 is # (i.e., all digits assumed left of the decimal point.)
13099 1.1 is #
13100 1.1 is # Register usage:
13101 1.1 is #
13102 1.1 is # calc_m:
13103 1.1 is # (*) d0: temp digit storage
13104 1.1 is # (*) d1: lword counter
13105 1.1 is # (*) d2: digit count
13106 1.1 is # (*) d3: offset pointer
13107 1.1 is # ( ) d4: words 2 and 3 of bcd
13108 1.1 is # ( ) a0: pointer to working bcd value
13109 1.1 is # ( ) a6: pointer to original bcd value
13110 1.1 is # (*) fp0: mantissa accumulator
13111 1.1 is # ( ) FP_SCR1: working copy of original bcd value
13112 1.1 is # ( ) L_SCR1: copy of original exponent word
13113 1.1 is #
13114 1.1 is calc_m:
13115 1.1 is mov.l &1,%d1 # word counter, init to 1
13116 1.1 is fmov.s &0x00000000,%fp0 # accumulator
13117 1.1 is #
13118 1.1 is #
13119 1.1 is # Since the packed number has a long word between the first & second parts,
13120 1.1 is # get the integer digit then skip down & get the rest of the
13121 1.1 is # mantissa. We will unroll the loop once.
13122 1.1 is #
13123 1.1 is bfextu (%a0){&28:&4},%d0 # integer part is ls digit in long word
13124 1.1 is fadd.b %d0,%fp0 # add digit to sum in fp0
13125 1.1 is #
13126 1.1 is #
13127 1.1 is # Get the rest of the mantissa.
13128 1.1 is #
13129 1.1 is loadlw:
13130 1.1 is mov.l (%a0,%d1.L*4),%d4 # load mantissa lonqword into d4
13131 1.1 is mov.l &FSTRT,%d3 # counter to pick up digits
13132 1.1 is mov.l &FNIBS,%d2 # reset number of digits per a0 ptr
13133 1.1 is md2b:
13134 1.1 is fmul.s &0x41200000,%fp0 # fp0 = fp0 * 10
13135 1.1 is bfextu %d4{%d3:&4},%d0 # get the digit and zero extend
13136 1.1 is fadd.b %d0,%fp0 # fp0 = fp0 + digit
13137 1.1 is #
13138 1.1 is #
13139 1.1 is # If all the digits (8) in that long word have been converted (d2=0),
13140 1.1 is # then inc d1 (=2) to point to the next long word and reset d3 to 0
13141 1.1 is # to initialize the digit offset, and set d2 to 7 for the digit count;
13142 1.1 is # else continue with this long word.
13143 1.1 is #
13144 1.1 is addq.b &4,%d3 # advance d3 to the next digit
13145 1.1 is dbf.w %d2,md2b # check for last digit in this lw
13146 1.1 is nextlw:
13147 1.1 is addq.l &1,%d1 # inc lw pointer in mantissa
13148 1.1 is cmp.l %d1,&2 # test for last lw
13149 1.1 is ble.b loadlw # if not, get last one
13150 1.1 is #
13151 1.1 is # Check the sign of the mant and make the value in fp0 the same sign.
13152 1.1 is #
13153 1.1 is m_sign:
13154 1.1 is btst &31,(%a0) # test sign of the mantissa
13155 1.1 is beq.b ap_st_z # if clear, go to append/strip zeros
13156 1.1 is fneg.x %fp0 # if set, negate fp0
13157 1.1 is #
13158 1.1 is # Append/strip zeros:
13159 1.1 is #
13160 1.1 is # For adjusted exponents which have an absolute value greater than 27*,
13161 1.1 is # this routine calculates the amount needed to normalize the mantissa
13162 1.1 is # for the adjusted exponent. That number is subtracted from the exp
13163 1.1 is # if the exp was positive, and added if it was negative. The purpose
13164 1.1 is # of this is to reduce the value of the exponent and the possibility
13165 1.1 is # of error in calculation of pwrten.
13166 1.1 is #
13167 1.1 is # 1. Branch on the sign of the adjusted exponent.
13168 1.1 is # 2p.(positive exp)
13169 1.1 is # 2. Check M16 and the digits in lwords 2 and 3 in decending order.
13170 1.1 is # 3. Add one for each zero encountered until a non-zero digit.
13171 1.1 is # 4. Subtract the count from the exp.
13172 1.1 is # 5. Check if the exp has crossed zero in #3 above; make the exp abs
13173 1.1 is # and set SE.
13174 1.1 is # 6. Multiply the mantissa by 10**count.
13175 1.1 is # 2n.(negative exp)
13176 1.1 is # 2. Check the digits in lwords 3 and 2 in decending order.
13177 1.1 is # 3. Add one for each zero encountered until a non-zero digit.
13178 1.1 is # 4. Add the count to the exp.
13179 1.1 is # 5. Check if the exp has crossed zero in #3 above; clear SE.
13180 1.1 is # 6. Divide the mantissa by 10**count.
13181 1.1 is #
13182 1.1 is # *Why 27? If the adjusted exponent is within -28 < expA < 28, than
13183 1.1 is # any adjustment due to append/strip zeros will drive the resultane
13184 1.1 is # exponent towards zero. Since all pwrten constants with a power
13185 1.1 is # of 27 or less are exact, there is no need to use this routine to
13186 1.1 is # attempt to lessen the resultant exponent.
13187 1.1 is #
13188 1.1 is # Register usage:
13189 1.1 is #
13190 1.1 is # ap_st_z:
13191 1.1 is # (*) d0: temp digit storage
13192 1.1 is # (*) d1: zero count
13193 1.1 is # (*) d2: digit count
13194 1.1 is # (*) d3: offset pointer
13195 1.1 is # ( ) d4: first word of bcd
13196 1.1 is # (*) d5: lword counter
13197 1.1 is # ( ) a0: pointer to working bcd value
13198 1.1 is # ( ) FP_SCR1: working copy of original bcd value
13199 1.1 is # ( ) L_SCR1: copy of original exponent word
13200 1.1 is #
13201 1.1 is #
13202 1.1 is # First check the absolute value of the exponent to see if this
13203 1.1 is # routine is necessary. If so, then check the sign of the exponent
13204 1.1 is # and do append (+) or strip (-) zeros accordingly.
13205 1.1 is # This section handles a positive adjusted exponent.
13206 1.1 is #
13207 1.1 is ap_st_z:
13208 1.1 is mov.l (%sp),%d1 # load expA for range test
13209 1.1 is cmp.l %d1,&27 # test is with 27
13210 1.1 is ble.w pwrten # if abs(expA) <28, skip ap/st zeros
13211 1.1 is btst &30,(%a0) # check sign of exp
13212 1.1 is bne.b ap_st_n # if neg, go to neg side
13213 1.1 is clr.l %d1 # zero count reg
13214 1.1 is mov.l (%a0),%d4 # load lword 1 to d4
13215 1.1 is bfextu %d4{&28:&4},%d0 # get M16 in d0
13216 1.1 is bne.b ap_p_fx # if M16 is non-zero, go fix exp
13217 1.1 is addq.l &1,%d1 # inc zero count
13218 1.1 is mov.l &1,%d5 # init lword counter
13219 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 2 to d4
13220 1.1 is bne.b ap_p_cl # if lw 2 is zero, skip it
13221 1.1 is addq.l &8,%d1 # and inc count by 8
13222 1.1 is addq.l &1,%d5 # inc lword counter
13223 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 3 to d4
13224 1.1 is ap_p_cl:
13225 1.1 is clr.l %d3 # init offset reg
13226 1.1 is mov.l &7,%d2 # init digit counter
13227 1.1 is ap_p_gd:
13228 1.1 is bfextu %d4{%d3:&4},%d0 # get digit
13229 1.1 is bne.b ap_p_fx # if non-zero, go to fix exp
13230 1.1 is addq.l &4,%d3 # point to next digit
13231 1.1 is addq.l &1,%d1 # inc digit counter
13232 1.1 is dbf.w %d2,ap_p_gd # get next digit
13233 1.1 is ap_p_fx:
13234 1.1 is mov.l %d1,%d0 # copy counter to d2
13235 1.1 is mov.l (%sp),%d1 # get adjusted exp from memory
13236 1.1 is sub.l %d0,%d1 # subtract count from exp
13237 1.1 is bge.b ap_p_fm # if still pos, go to pwrten
13238 1.1 is neg.l %d1 # now its neg; get abs
13239 1.1 is mov.l (%a0),%d4 # load lword 1 to d4
13240 1.1 is or.l &0x40000000,%d4 # and set SE in d4
13241 1.1 is or.l &0x40000000,(%a0) # and in memory
13242 1.1 is #
13243 1.1 is # Calculate the mantissa multiplier to compensate for the striping of
13244 1.1 is # zeros from the mantissa.
13245 1.1 is #
13246 1.1 is ap_p_fm:
13247 1.1 is lea.l PTENRN(%pc),%a1 # get address of power-of-ten table
13248 1.1 is clr.l %d3 # init table index
13249 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1
13250 1.1 is mov.l &3,%d2 # init d2 to count bits in counter
13251 1.1 is ap_p_el:
13252 1.1 is asr.l &1,%d0 # shift lsb into carry
13253 1.1 is bcc.b ap_p_en # if 1, mul fp1 by pwrten factor
13254 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13255 1.1 is ap_p_en:
13256 1.1 is add.l &12,%d3 # inc d3 to next rtable entry
13257 1.1 is tst.l %d0 # check if d0 is zero
13258 1.1 is bne.b ap_p_el # if not, get next bit
13259 1.1 is fmul.x %fp1,%fp0 # mul mantissa by 10**(no_bits_shifted)
13260 1.1 is bra.b pwrten # go calc pwrten
13261 1.1 is #
13262 1.1 is # This section handles a negative adjusted exponent.
13263 1.1 is #
13264 1.1 is ap_st_n:
13265 1.1 is clr.l %d1 # clr counter
13266 1.1 is mov.l &2,%d5 # set up d5 to point to lword 3
13267 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 3
13268 1.1 is bne.b ap_n_cl # if not zero, check digits
13269 1.1 is sub.l &1,%d5 # dec d5 to point to lword 2
13270 1.1 is addq.l &8,%d1 # inc counter by 8
13271 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 2
13272 1.1 is ap_n_cl:
13273 1.1 is mov.l &28,%d3 # point to last digit
13274 1.1 is mov.l &7,%d2 # init digit counter
13275 1.1 is ap_n_gd:
13276 1.1 is bfextu %d4{%d3:&4},%d0 # get digit
13277 1.1 is bne.b ap_n_fx # if non-zero, go to exp fix
13278 1.1 is subq.l &4,%d3 # point to previous digit
13279 1.1 is addq.l &1,%d1 # inc digit counter
13280 1.1 is dbf.w %d2,ap_n_gd # get next digit
13281 1.1 is ap_n_fx:
13282 1.1 is mov.l %d1,%d0 # copy counter to d0
13283 1.1 is mov.l (%sp),%d1 # get adjusted exp from memory
13284 1.1 is sub.l %d0,%d1 # subtract count from exp
13285 1.1 is bgt.b ap_n_fm # if still pos, go fix mantissa
13286 1.1 is neg.l %d1 # take abs of exp and clr SE
13287 1.1 is mov.l (%a0),%d4 # load lword 1 to d4
13288 1.1 is and.l &0xbfffffff,%d4 # and clr SE in d4
13289 1.1 is and.l &0xbfffffff,(%a0) # and in memory
13290 1.1 is #
13291 1.1 is # Calculate the mantissa multiplier to compensate for the appending of
13292 1.1 is # zeros to the mantissa.
13293 1.1 is #
13294 1.1 is ap_n_fm:
13295 1.1 is lea.l PTENRN(%pc),%a1 # get address of power-of-ten table
13296 1.1 is clr.l %d3 # init table index
13297 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1
13298 1.1 is mov.l &3,%d2 # init d2 to count bits in counter
13299 1.1 is ap_n_el:
13300 1.1 is asr.l &1,%d0 # shift lsb into carry
13301 1.1 is bcc.b ap_n_en # if 1, mul fp1 by pwrten factor
13302 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13303 1.1 is ap_n_en:
13304 1.1 is add.l &12,%d3 # inc d3 to next rtable entry
13305 1.1 is tst.l %d0 # check if d0 is zero
13306 1.1 is bne.b ap_n_el # if not, get next bit
13307 1.1 is fdiv.x %fp1,%fp0 # div mantissa by 10**(no_bits_shifted)
13308 1.1 is #
13309 1.1 is #
13310 1.1 is # Calculate power-of-ten factor from adjusted and shifted exponent.
13311 1.1 is #
13312 1.1 is # Register usage:
13313 1.1 is #
13314 1.1 is # pwrten:
13315 1.1 is # (*) d0: temp
13316 1.1 is # ( ) d1: exponent
13317 1.1 is # (*) d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
13318 1.1 is # (*) d3: FPCR work copy
13319 1.1 is # ( ) d4: first word of bcd
13320 1.1 is # (*) a1: RTABLE pointer
13321 1.1 is # calc_p:
13322 1.1 is # (*) d0: temp
13323 1.1 is # ( ) d1: exponent
13324 1.1 is # (*) d3: PWRTxx table index
13325 1.1 is # ( ) a0: pointer to working copy of bcd
13326 1.1 is # (*) a1: PWRTxx pointer
13327 1.1 is # (*) fp1: power-of-ten accumulator
13328 1.1 is #
13329 1.1 is # Pwrten calculates the exponent factor in the selected rounding mode
13330 1.1 is # according to the following table:
13331 1.1 is #
13332 1.1 is # Sign of Mant Sign of Exp Rounding Mode PWRTEN Rounding Mode
13333 1.1 is #
13334 1.1 is # ANY ANY RN RN
13335 1.1 is #
13336 1.1 is # + + RP RP
13337 1.1 is # - + RP RM
13338 1.1 is # + - RP RM
13339 1.1 is # - - RP RP
13340 1.1 is #
13341 1.1 is # + + RM RM
13342 1.1 is # - + RM RP
13343 1.1 is # + - RM RP
13344 1.1 is # - - RM RM
13345 1.1 is #
13346 1.1 is # + + RZ RM
13347 1.1 is # - + RZ RM
13348 1.1 is # + - RZ RP
13349 1.1 is # - - RZ RP
13350 1.1 is #
13351 1.1 is #
13352 1.1 is pwrten:
13353 1.1 is mov.l USER_FPCR(%a6),%d3 # get user's FPCR
13354 1.1 is bfextu %d3{&26:&2},%d2 # isolate rounding mode bits
13355 1.1 is mov.l (%a0),%d4 # reload 1st bcd word to d4
13356 1.1 is asl.l &2,%d2 # format d2 to be
13357 1.1 is bfextu %d4{&0:&2},%d0 # {FPCR[6],FPCR[5],SM,SE}
13358 1.1 is add.l %d0,%d2 # in d2 as index into RTABLE
13359 1.1 is lea.l RTABLE(%pc),%a1 # load rtable base
13360 1.1 is mov.b (%a1,%d2),%d0 # load new rounding bits from table
13361 1.1 is clr.l %d3 # clear d3 to force no exc and extended
13362 1.1 is bfins %d0,%d3{&26:&2} # stuff new rounding bits in FPCR
13363 1.1 is fmov.l %d3,%fpcr # write new FPCR
13364 1.1 is asr.l &1,%d0 # write correct PTENxx table
13365 1.1 is bcc.b not_rp # to a1
13366 1.1 is lea.l PTENRP(%pc),%a1 # it is RP
13367 1.1 is bra.b calc_p # go to init section
13368 1.1 is not_rp:
13369 1.1 is asr.l &1,%d0 # keep checking
13370 1.1 is bcc.b not_rm
13371 1.1 is lea.l PTENRM(%pc),%a1 # it is RM
13372 1.1 is bra.b calc_p # go to init section
13373 1.1 is not_rm:
13374 1.1 is lea.l PTENRN(%pc),%a1 # it is RN
13375 1.1 is calc_p:
13376 1.1 is mov.l %d1,%d0 # copy exp to d0;use d0
13377 1.1 is bpl.b no_neg # if exp is negative,
13378 1.1 is neg.l %d0 # invert it
13379 1.1 is or.l &0x40000000,(%a0) # and set SE bit
13380 1.1 is no_neg:
13381 1.1 is clr.l %d3 # table index
13382 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1
13383 1.1 is e_loop:
13384 1.1 is asr.l &1,%d0 # shift next bit into carry
13385 1.1 is bcc.b e_next # if zero, skip the mul
13386 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13387 1.1 is e_next:
13388 1.1 is add.l &12,%d3 # inc d3 to next rtable entry
13389 1.1 is tst.l %d0 # check if d0 is zero
13390 1.1 is bne.b e_loop # not zero, continue shifting
13391 1.1 is #
13392 1.1 is #
13393 1.1 is # Check the sign of the adjusted exp and make the value in fp0 the
13394 1.1 is # same sign. If the exp was pos then multiply fp1*fp0;
13395 1.1 is # else divide fp0/fp1.
13396 1.1 is #
13397 1.1 is # Register Usage:
13398 1.1 is # norm:
13399 1.1 is # ( ) a0: pointer to working bcd value
13400 1.1 is # (*) fp0: mantissa accumulator
13401 1.1 is # ( ) fp1: scaling factor - 10**(abs(exp))
13402 1.1 is #
13403 1.1 is pnorm:
13404 1.1 is btst &30,(%a0) # test the sign of the exponent
13405 1.1 is beq.b mul # if clear, go to multiply
13406 1.1 is div:
13407 1.1 is fdiv.x %fp1,%fp0 # exp is negative, so divide mant by exp
13408 1.1 is bra.b end_dec
13409 1.1 is mul:
13410 1.1 is fmul.x %fp1,%fp0 # exp is positive, so multiply by exp
13411 1.1 is #
13412 1.1 is #
13413 1.1 is # Clean up and return with result in fp0.
13414 1.1 is #
13415 1.1 is # If the final mul/div in decbin incurred an inex exception,
13416 1.1 is # it will be inex2, but will be reported as inex1 by get_op.
13417 1.1 is #
13418 1.1 is end_dec:
13419 1.1 is fmov.l %fpsr,%d0 # get status register
13420 1.1 is bclr &inex2_bit+8,%d0 # test for inex2 and clear it
13421 1.1 is beq.b no_exc # skip this if no exc
13422 1.1 is ori.w &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX
13423 1.1 is no_exc:
13424 1.1 is add.l &0x4,%sp # clear 1 lw param
13425 1.1 is fmovm.x (%sp)+,&0x40 # restore fp1
13426 1.1 is movm.l (%sp)+,&0x3c # restore d2-d5
13427 1.1 is fmov.l &0x0,%fpcr
13428 1.1 is fmov.l &0x0,%fpsr
13429 1.1 is rts
13430 1.1 is
13431 1.1 is #########################################################################
13432 1.1 is # bindec(): Converts an input in extended precision format to bcd format#
13433 1.1 is # #
13434 1.1 is # INPUT *************************************************************** #
13435 1.1 is # a0 = pointer to the input extended precision value in memory. #
13436 1.1 is # the input may be either normalized, unnormalized, or #
13437 1.1 is # denormalized. #
13438 1.1 is # d0 = contains the k-factor sign-extended to 32-bits. #
13439 1.1 is # #
13440 1.1 is # OUTPUT ************************************************************** #
13441 1.1 is # FP_SCR0(a6) = bcd format result on the stack. #
13442 1.1 is # #
13443 1.1 is # ALGORITHM *********************************************************** #
13444 1.1 is # #
13445 1.1 is # A1. Set RM and size ext; Set SIGMA = sign of input. #
13446 1.1 is # The k-factor is saved for use in d7. Clear the #
13447 1.1 is # BINDEC_FLG for separating normalized/denormalized #
13448 1.1 is # input. If input is unnormalized or denormalized, #
13449 1.1 is # normalize it. #
13450 1.1 is # #
13451 1.1 is # A2. Set X = abs(input). #
13452 1.1 is # #
13453 1.1 is # A3. Compute ILOG. #
13454 1.1 is # ILOG is the log base 10 of the input value. It is #
13455 1.1 is # approximated by adding e + 0.f when the original #
13456 1.1 is # value is viewed as 2^^e * 1.f in extended precision. #
13457 1.1 is # This value is stored in d6. #
13458 1.1 is # #
13459 1.1 is # A4. Clr INEX bit. #
13460 1.1 is # The operation in A3 above may have set INEX2. #
13461 1.1 is # #
13462 1.1 is # A5. Set ICTR = 0; #
13463 1.1 is # ICTR is a flag used in A13. It must be set before the #
13464 1.1 is # loop entry A6. #
13465 1.1 is # #
13466 1.1 is # A6. Calculate LEN. #
13467 1.1 is # LEN is the number of digits to be displayed. The #
13468 1.1 is # k-factor can dictate either the total number of digits, #
13469 1.1 is # if it is a positive number, or the number of digits #
13470 1.1 is # after the decimal point which are to be included as #
13471 1.1 is # significant. See the 68882 manual for examples. #
13472 1.1 is # If LEN is computed to be greater than 17, set OPERR in #
13473 1.1 is # USER_FPSR. LEN is stored in d4. #
13474 1.1 is # #
13475 1.1 is # A7. Calculate SCALE. #
13476 1.1 is # SCALE is equal to 10^ISCALE, where ISCALE is the number #
13477 1.1 is # of decimal places needed to insure LEN integer digits #
13478 1.1 is # in the output before conversion to bcd. LAMBDA is the #
13479 1.1 is # sign of ISCALE, used in A9. Fp1 contains #
13480 1.1 is # 10^^(abs(ISCALE)) using a rounding mode which is a #
13481 1.1 is # function of the original rounding mode and the signs #
13482 1.1 is # of ISCALE and X. A table is given in the code. #
13483 1.1 is # #
13484 1.1 is # A8. Clr INEX; Force RZ. #
13485 1.1 is # The operation in A3 above may have set INEX2. #
13486 1.1 is # RZ mode is forced for the scaling operation to insure #
13487 1.1 is # only one rounding error. The grs bits are collected in #
13488 1.1 is # the INEX flag for use in A10. #
13489 1.1 is # #
13490 1.1 is # A9. Scale X -> Y. #
13491 1.1 is # The mantissa is scaled to the desired number of #
13492 1.1 is # significant digits. The excess digits are collected #
13493 1.1 is # in INEX2. #
13494 1.1 is # #
13495 1.1 is # A10. Or in INEX. #
13496 1.2 wiz # If INEX is set, round error occurred. This is #
13497 1.1 is # compensated for by 'or-ing' in the INEX2 flag to #
13498 1.1 is # the lsb of Y. #
13499 1.1 is # #
13500 1.1 is # A11. Restore original FPCR; set size ext. #
13501 1.1 is # Perform FINT operation in the user's rounding mode. #
13502 1.1 is # Keep the size to extended. #
13503 1.1 is # #
13504 1.1 is # A12. Calculate YINT = FINT(Y) according to user's rounding #
13505 1.1 is # mode. The FPSP routine sintd0 is used. The output #
13506 1.1 is # is in fp0. #
13507 1.1 is # #
13508 1.1 is # A13. Check for LEN digits. #
13509 1.1 is # If the int operation results in more than LEN digits, #
13510 1.1 is # or less than LEN -1 digits, adjust ILOG and repeat from #
13511 1.1 is # A6. This test occurs only on the first pass. If the #
13512 1.1 is # result is exactly 10^LEN, decrement ILOG and divide #
13513 1.1 is # the mantissa by 10. #
13514 1.1 is # #
13515 1.1 is # A14. Convert the mantissa to bcd. #
13516 1.1 is # The binstr routine is used to convert the LEN digit #
13517 1.1 is # mantissa to bcd in memory. The input to binstr is #
13518 1.1 is # to be a fraction; i.e. (mantissa)/10^LEN and adjusted #
13519 1.1 is # such that the decimal point is to the left of bit 63. #
13520 1.1 is # The bcd digits are stored in the correct position in #
13521 1.1 is # the final string area in memory. #
13522 1.1 is # #
13523 1.1 is # A15. Convert the exponent to bcd. #
13524 1.1 is # As in A14 above, the exp is converted to bcd and the #
13525 1.1 is # digits are stored in the final string. #
13526 1.1 is # Test the length of the final exponent string. If the #
13527 1.1 is # length is 4, set operr. #
13528 1.1 is # #
13529 1.1 is # A16. Write sign bits to final string. #
13530 1.1 is # #
13531 1.1 is #########################################################################
13532 1.1 is
13533 1.1 is set BINDEC_FLG, EXC_TEMP # DENORM flag
13534 1.1 is
13535 1.1 is # Constants in extended precision
13536 1.1 is PLOG2:
13537 1.1 is long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
13538 1.1 is PLOG2UP1:
13539 1.1 is long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
13540 1.1 is
13541 1.1 is # Constants in single precision
13542 1.1 is FONE:
13543 1.1 is long 0x3F800000,0x00000000,0x00000000,0x00000000
13544 1.1 is FTWO:
13545 1.1 is long 0x40000000,0x00000000,0x00000000,0x00000000
13546 1.1 is FTEN:
13547 1.1 is long 0x41200000,0x00000000,0x00000000,0x00000000
13548 1.1 is F4933:
13549 1.1 is long 0x459A2800,0x00000000,0x00000000,0x00000000
13550 1.1 is
13551 1.1 is RBDTBL:
13552 1.1 is byte 0,0,0,0
13553 1.1 is byte 3,3,2,2
13554 1.1 is byte 3,2,2,3
13555 1.1 is byte 2,3,3,2
13556 1.1 is
13557 1.1 is # Implementation Notes:
13558 1.1 is #
13559 1.1 is # The registers are used as follows:
13560 1.1 is #
13561 1.1 is # d0: scratch; LEN input to binstr
13562 1.1 is # d1: scratch
13563 1.1 is # d2: upper 32-bits of mantissa for binstr
13564 1.1 is # d3: scratch;lower 32-bits of mantissa for binstr
13565 1.1 is # d4: LEN
13566 1.1 is # d5: LAMBDA/ICTR
13567 1.1 is # d6: ILOG
13568 1.1 is # d7: k-factor
13569 1.1 is # a0: ptr for original operand/final result
13570 1.1 is # a1: scratch pointer
13571 1.1 is # a2: pointer to FP_X; abs(original value) in ext
13572 1.1 is # fp0: scratch
13573 1.1 is # fp1: scratch
13574 1.1 is # fp2: scratch
13575 1.1 is # F_SCR1:
13576 1.1 is # F_SCR2:
13577 1.1 is # L_SCR1:
13578 1.1 is # L_SCR2:
13579 1.1 is
13580 1.1 is global bindec
13581 1.1 is bindec:
13582 1.1 is movm.l &0x3f20,-(%sp) # {%d2-%d7/%a2}
13583 1.1 is fmovm.x &0x7,-(%sp) # {%fp0-%fp2}
13584 1.1 is
13585 1.1 is # A1. Set RM and size ext. Set SIGMA = sign input;
13586 1.1 is # The k-factor is saved for use in d7. Clear BINDEC_FLG for
13587 1.1 is # separating normalized/denormalized input. If the input
13588 1.1 is # is a denormalized number, set the BINDEC_FLG memory word
13589 1.1 is # to signal denorm. If the input is unnormalized, normalize
13590 1.1 is # the input and test for denormalized result.
13591 1.1 is #
13592 1.1 is fmov.l &rm_mode*0x10,%fpcr # set RM and ext
13593 1.1 is mov.l (%a0),L_SCR2(%a6) # save exponent for sign check
13594 1.1 is mov.l %d0,%d7 # move k-factor to d7
13595 1.1 is
13596 1.1 is clr.b BINDEC_FLG(%a6) # clr norm/denorm flag
13597 1.1 is cmpi.b STAG(%a6),&DENORM # is input a DENORM?
13598 1.1 is bne.w A2_str # no; input is a NORM
13599 1.1 is
13600 1.1 is #
13601 1.1 is # Normalize the denorm
13602 1.1 is #
13603 1.1 is un_de_norm:
13604 1.1 is mov.w (%a0),%d0
13605 1.1 is and.w &0x7fff,%d0 # strip sign of normalized exp
13606 1.1 is mov.l 4(%a0),%d1
13607 1.1 is mov.l 8(%a0),%d2
13608 1.1 is norm_loop:
13609 1.1 is sub.w &1,%d0
13610 1.1 is lsl.l &1,%d2
13611 1.1 is roxl.l &1,%d1
13612 1.1 is tst.l %d1
13613 1.1 is bge.b norm_loop
13614 1.1 is #
13615 1.1 is # Test if the normalized input is denormalized
13616 1.1 is #
13617 1.1 is tst.w %d0
13618 1.1 is bgt.b pos_exp # if greater than zero, it is a norm
13619 1.1 is st BINDEC_FLG(%a6) # set flag for denorm
13620 1.1 is pos_exp:
13621 1.1 is and.w &0x7fff,%d0 # strip sign of normalized exp
13622 1.1 is mov.w %d0,(%a0)
13623 1.1 is mov.l %d1,4(%a0)
13624 1.1 is mov.l %d2,8(%a0)
13625 1.1 is
13626 1.1 is # A2. Set X = abs(input).
13627 1.1 is #
13628 1.1 is A2_str:
13629 1.1 is mov.l (%a0),FP_SCR1(%a6) # move input to work space
13630 1.1 is mov.l 4(%a0),FP_SCR1+4(%a6) # move input to work space
13631 1.1 is mov.l 8(%a0),FP_SCR1+8(%a6) # move input to work space
13632 1.1 is and.l &0x7fffffff,FP_SCR1(%a6) # create abs(X)
13633 1.1 is
13634 1.1 is # A3. Compute ILOG.
13635 1.1 is # ILOG is the log base 10 of the input value. It is approx-
13636 1.1 is # imated by adding e + 0.f when the original value is viewed
13637 1.1 is # as 2^^e * 1.f in extended precision. This value is stored
13638 1.1 is # in d6.
13639 1.1 is #
13640 1.1 is # Register usage:
13641 1.1 is # Input/Output
13642 1.1 is # d0: k-factor/exponent
13643 1.1 is # d2: x/x
13644 1.1 is # d3: x/x
13645 1.1 is # d4: x/x
13646 1.1 is # d5: x/x
13647 1.1 is # d6: x/ILOG
13648 1.1 is # d7: k-factor/Unchanged
13649 1.1 is # a0: ptr for original operand/final result
13650 1.1 is # a1: x/x
13651 1.1 is # a2: x/x
13652 1.1 is # fp0: x/float(ILOG)
13653 1.1 is # fp1: x/x
13654 1.1 is # fp2: x/x
13655 1.1 is # F_SCR1:x/x
13656 1.1 is # F_SCR2:Abs(X)/Abs(X) with $3fff exponent
13657 1.1 is # L_SCR1:x/x
13658 1.1 is # L_SCR2:first word of X packed/Unchanged
13659 1.1 is
13660 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm
13661 1.1 is beq.b A3_cont # if clr, continue with norm
13662 1.1 is mov.l &-4933,%d6 # force ILOG = -4933
13663 1.1 is bra.b A4_str
13664 1.1 is A3_cont:
13665 1.1 is mov.w FP_SCR1(%a6),%d0 # move exp to d0
13666 1.1 is mov.w &0x3fff,FP_SCR1(%a6) # replace exponent with 0x3fff
13667 1.1 is fmov.x FP_SCR1(%a6),%fp0 # now fp0 has 1.f
13668 1.1 is sub.w &0x3fff,%d0 # strip off bias
13669 1.1 is fadd.w %d0,%fp0 # add in exp
13670 1.1 is fsub.s FONE(%pc),%fp0 # subtract off 1.0
13671 1.1 is fbge.w pos_res # if pos, branch
13672 1.1 is fmul.x PLOG2UP1(%pc),%fp0 # if neg, mul by LOG2UP1
13673 1.1 is fmov.l %fp0,%d6 # put ILOG in d6 as a lword
13674 1.1 is bra.b A4_str # go move out ILOG
13675 1.1 is pos_res:
13676 1.1 is fmul.x PLOG2(%pc),%fp0 # if pos, mul by LOG2
13677 1.1 is fmov.l %fp0,%d6 # put ILOG in d6 as a lword
13678 1.1 is
13679 1.1 is
13680 1.1 is # A4. Clr INEX bit.
13681 1.1 is # The operation in A3 above may have set INEX2.
13682 1.1 is
13683 1.1 is A4_str:
13684 1.1 is fmov.l &0,%fpsr # zero all of fpsr - nothing needed
13685 1.1 is
13686 1.1 is
13687 1.1 is # A5. Set ICTR = 0;
13688 1.1 is # ICTR is a flag used in A13. It must be set before the
13689 1.1 is # loop entry A6. The lower word of d5 is used for ICTR.
13690 1.1 is
13691 1.1 is clr.w %d5 # clear ICTR
13692 1.1 is
13693 1.1 is # A6. Calculate LEN.
13694 1.1 is # LEN is the number of digits to be displayed. The k-factor
13695 1.1 is # can dictate either the total number of digits, if it is
13696 1.1 is # a positive number, or the number of digits after the
13697 1.1 is # original decimal point which are to be included as
13698 1.1 is # significant. See the 68882 manual for examples.
13699 1.1 is # If LEN is computed to be greater than 17, set OPERR in
13700 1.1 is # USER_FPSR. LEN is stored in d4.
13701 1.1 is #
13702 1.1 is # Register usage:
13703 1.1 is # Input/Output
13704 1.1 is # d0: exponent/Unchanged
13705 1.1 is # d2: x/x/scratch
13706 1.1 is # d3: x/x
13707 1.1 is # d4: exc picture/LEN
13708 1.1 is # d5: ICTR/Unchanged
13709 1.1 is # d6: ILOG/Unchanged
13710 1.1 is # d7: k-factor/Unchanged
13711 1.1 is # a0: ptr for original operand/final result
13712 1.1 is # a1: x/x
13713 1.1 is # a2: x/x
13714 1.1 is # fp0: float(ILOG)/Unchanged
13715 1.1 is # fp1: x/x
13716 1.1 is # fp2: x/x
13717 1.1 is # F_SCR1:x/x
13718 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged
13719 1.1 is # L_SCR1:x/x
13720 1.1 is # L_SCR2:first word of X packed/Unchanged
13721 1.1 is
13722 1.1 is A6_str:
13723 1.1 is tst.l %d7 # branch on sign of k
13724 1.1 is ble.b k_neg # if k <= 0, LEN = ILOG + 1 - k
13725 1.1 is mov.l %d7,%d4 # if k > 0, LEN = k
13726 1.1 is bra.b len_ck # skip to LEN check
13727 1.1 is k_neg:
13728 1.1 is mov.l %d6,%d4 # first load ILOG to d4
13729 1.1 is sub.l %d7,%d4 # subtract off k
13730 1.1 is addq.l &1,%d4 # add in the 1
13731 1.1 is len_ck:
13732 1.1 is tst.l %d4 # LEN check: branch on sign of LEN
13733 1.1 is ble.b LEN_ng # if neg, set LEN = 1
13734 1.1 is cmp.l %d4,&17 # test if LEN > 17
13735 1.1 is ble.b A7_str # if not, forget it
13736 1.1 is mov.l &17,%d4 # set max LEN = 17
13737 1.1 is tst.l %d7 # if negative, never set OPERR
13738 1.1 is ble.b A7_str # if positive, continue
13739 1.1 is or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR
13740 1.1 is bra.b A7_str # finished here
13741 1.1 is LEN_ng:
13742 1.1 is mov.l &1,%d4 # min LEN is 1
13743 1.1 is
13744 1.1 is
13745 1.1 is # A7. Calculate SCALE.
13746 1.1 is # SCALE is equal to 10^ISCALE, where ISCALE is the number
13747 1.1 is # of decimal places needed to insure LEN integer digits
13748 1.1 is # in the output before conversion to bcd. LAMBDA is the sign
13749 1.1 is # of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using
13750 1.1 is # the rounding mode as given in the following table (see
13751 1.1 is # Coonen, p. 7.23 as ref.; however, the SCALE variable is
13752 1.1 is # of opposite sign in bindec.sa from Coonen).
13753 1.1 is #
13754 1.1 is # Initial USE
13755 1.1 is # FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5]
13756 1.1 is # ----------------------------------------------
13757 1.1 is # RN 00 0 0 00/0 RN
13758 1.1 is # RN 00 0 1 00/0 RN
13759 1.1 is # RN 00 1 0 00/0 RN
13760 1.1 is # RN 00 1 1 00/0 RN
13761 1.1 is # RZ 01 0 0 11/3 RP
13762 1.1 is # RZ 01 0 1 11/3 RP
13763 1.1 is # RZ 01 1 0 10/2 RM
13764 1.1 is # RZ 01 1 1 10/2 RM
13765 1.1 is # RM 10 0 0 11/3 RP
13766 1.1 is # RM 10 0 1 10/2 RM
13767 1.1 is # RM 10 1 0 10/2 RM
13768 1.1 is # RM 10 1 1 11/3 RP
13769 1.1 is # RP 11 0 0 10/2 RM
13770 1.1 is # RP 11 0 1 11/3 RP
13771 1.1 is # RP 11 1 0 11/3 RP
13772 1.1 is # RP 11 1 1 10/2 RM
13773 1.1 is #
13774 1.1 is # Register usage:
13775 1.1 is # Input/Output
13776 1.1 is # d0: exponent/scratch - final is 0
13777 1.1 is # d2: x/0 or 24 for A9
13778 1.1 is # d3: x/scratch - offset ptr into PTENRM array
13779 1.1 is # d4: LEN/Unchanged
13780 1.1 is # d5: 0/ICTR:LAMBDA
13781 1.1 is # d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
13782 1.1 is # d7: k-factor/Unchanged
13783 1.1 is # a0: ptr for original operand/final result
13784 1.1 is # a1: x/ptr to PTENRM array
13785 1.1 is # a2: x/x
13786 1.1 is # fp0: float(ILOG)/Unchanged
13787 1.1 is # fp1: x/10^ISCALE
13788 1.1 is # fp2: x/x
13789 1.1 is # F_SCR1:x/x
13790 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged
13791 1.1 is # L_SCR1:x/x
13792 1.1 is # L_SCR2:first word of X packed/Unchanged
13793 1.1 is
13794 1.1 is A7_str:
13795 1.1 is tst.l %d7 # test sign of k
13796 1.1 is bgt.b k_pos # if pos and > 0, skip this
13797 1.1 is cmp.l %d7,%d6 # test k - ILOG
13798 1.1 is blt.b k_pos # if ILOG >= k, skip this
13799 1.1 is mov.l %d7,%d6 # if ((k<0) & (ILOG < k)) ILOG = k
13800 1.1 is k_pos:
13801 1.1 is mov.l %d6,%d0 # calc ILOG + 1 - LEN in d0
13802 1.1 is addq.l &1,%d0 # add the 1
13803 1.1 is sub.l %d4,%d0 # sub off LEN
13804 1.1 is swap %d5 # use upper word of d5 for LAMBDA
13805 1.1 is clr.w %d5 # set it zero initially
13806 1.1 is clr.w %d2 # set up d2 for very small case
13807 1.1 is tst.l %d0 # test sign of ISCALE
13808 1.1 is bge.b iscale # if pos, skip next inst
13809 1.1 is addq.w &1,%d5 # if neg, set LAMBDA true
13810 1.1 is cmp.l %d0,&0xffffecd4 # test iscale <= -4908
13811 1.1 is bgt.b no_inf # if false, skip rest
13812 1.1 is add.l &24,%d0 # add in 24 to iscale
13813 1.1 is mov.l &24,%d2 # put 24 in d2 for A9
13814 1.1 is no_inf:
13815 1.1 is neg.l %d0 # and take abs of ISCALE
13816 1.1 is iscale:
13817 1.1 is fmov.s FONE(%pc),%fp1 # init fp1 to 1
13818 1.1 is bfextu USER_FPCR(%a6){&26:&2},%d1 # get initial rmode bits
13819 1.1 is lsl.w &1,%d1 # put them in bits 2:1
13820 1.1 is add.w %d5,%d1 # add in LAMBDA
13821 1.1 is lsl.w &1,%d1 # put them in bits 3:1
13822 1.1 is tst.l L_SCR2(%a6) # test sign of original x
13823 1.1 is bge.b x_pos # if pos, don't set bit 0
13824 1.1 is addq.l &1,%d1 # if neg, set bit 0
13825 1.1 is x_pos:
13826 1.1 is lea.l RBDTBL(%pc),%a2 # load rbdtbl base
13827 1.1 is mov.b (%a2,%d1),%d3 # load d3 with new rmode
13828 1.1 is lsl.l &4,%d3 # put bits in proper position
13829 1.1 is fmov.l %d3,%fpcr # load bits into fpu
13830 1.1 is lsr.l &4,%d3 # put bits in proper position
13831 1.1 is tst.b %d3 # decode new rmode for pten table
13832 1.1 is bne.b not_rn # if zero, it is RN
13833 1.1 is lea.l PTENRN(%pc),%a1 # load a1 with RN table base
13834 1.1 is bra.b rmode # exit decode
13835 1.1 is not_rn:
13836 1.1 is lsr.b &1,%d3 # get lsb in carry
13837 1.1 is bcc.b not_rp2 # if carry clear, it is RM
13838 1.1 is lea.l PTENRP(%pc),%a1 # load a1 with RP table base
13839 1.1 is bra.b rmode # exit decode
13840 1.1 is not_rp2:
13841 1.1 is lea.l PTENRM(%pc),%a1 # load a1 with RM table base
13842 1.1 is rmode:
13843 1.1 is clr.l %d3 # clr table index
13844 1.1 is e_loop2:
13845 1.1 is lsr.l &1,%d0 # shift next bit into carry
13846 1.1 is bcc.b e_next2 # if zero, skip the mul
13847 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13848 1.1 is e_next2:
13849 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry
13850 1.1 is tst.l %d0 # test if ISCALE is zero
13851 1.1 is bne.b e_loop2 # if not, loop
13852 1.1 is
13853 1.1 is # A8. Clr INEX; Force RZ.
13854 1.1 is # The operation in A3 above may have set INEX2.
13855 1.1 is # RZ mode is forced for the scaling operation to insure
13856 1.1 is # only one rounding error. The grs bits are collected in
13857 1.1 is # the INEX flag for use in A10.
13858 1.1 is #
13859 1.1 is # Register usage:
13860 1.1 is # Input/Output
13861 1.1 is
13862 1.1 is fmov.l &0,%fpsr # clr INEX
13863 1.1 is fmov.l &rz_mode*0x10,%fpcr # set RZ rounding mode
13864 1.1 is
13865 1.1 is # A9. Scale X -> Y.
13866 1.1 is # The mantissa is scaled to the desired number of significant
13867 1.1 is # digits. The excess digits are collected in INEX2. If mul,
13868 1.1 is # Check d2 for excess 10 exponential value. If not zero,
13869 1.1 is # the iscale value would have caused the pwrten calculation
13870 1.1 is # to overflow. Only a negative iscale can cause this, so
13871 1.1 is # multiply by 10^(d2), which is now only allowed to be 24,
13872 1.1 is # with a multiply by 10^8 and 10^16, which is exact since
13873 1.1 is # 10^24 is exact. If the input was denormalized, we must
13874 1.1 is # create a busy stack frame with the mul command and the
13875 1.1 is # two operands, and allow the fpu to complete the multiply.
13876 1.1 is #
13877 1.1 is # Register usage:
13878 1.1 is # Input/Output
13879 1.1 is # d0: FPCR with RZ mode/Unchanged
13880 1.1 is # d2: 0 or 24/unchanged
13881 1.1 is # d3: x/x
13882 1.1 is # d4: LEN/Unchanged
13883 1.1 is # d5: ICTR:LAMBDA
13884 1.1 is # d6: ILOG/Unchanged
13885 1.1 is # d7: k-factor/Unchanged
13886 1.1 is # a0: ptr for original operand/final result
13887 1.1 is # a1: ptr to PTENRM array/Unchanged
13888 1.1 is # a2: x/x
13889 1.1 is # fp0: float(ILOG)/X adjusted for SCALE (Y)
13890 1.1 is # fp1: 10^ISCALE/Unchanged
13891 1.1 is # fp2: x/x
13892 1.1 is # F_SCR1:x/x
13893 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged
13894 1.1 is # L_SCR1:x/x
13895 1.1 is # L_SCR2:first word of X packed/Unchanged
13896 1.1 is
13897 1.1 is A9_str:
13898 1.1 is fmov.x (%a0),%fp0 # load X from memory
13899 1.1 is fabs.x %fp0 # use abs(X)
13900 1.1 is tst.w %d5 # LAMBDA is in lower word of d5
13901 1.1 is bne.b sc_mul # if neg (LAMBDA = 1), scale by mul
13902 1.1 is fdiv.x %fp1,%fp0 # calculate X / SCALE -> Y to fp0
13903 1.1 is bra.w A10_st # branch to A10
13904 1.1 is
13905 1.1 is sc_mul:
13906 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm
13907 1.1 is beq.w A9_norm # if norm, continue with mul
13908 1.1 is
13909 1.1 is # for DENORM, we must calculate:
13910 1.1 is # fp0 = input_op * 10^ISCALE * 10^24
13911 1.1 is # since the input operand is a DENORM, we can't multiply it directly.
13912 1.1 is # so, we do the multiplication of the exponents and mantissas separately.
13913 1.1 is # in this way, we avoid underflow on intermediate stages of the
13914 1.1 is # multiplication and guarantee a result without exception.
13915 1.1 is fmovm.x &0x2,-(%sp) # save 10^ISCALE to stack
13916 1.1 is
13917 1.1 is mov.w (%sp),%d3 # grab exponent
13918 1.1 is andi.w &0x7fff,%d3 # clear sign
13919 1.1 is ori.w &0x8000,(%a0) # make DENORM exp negative
13920 1.1 is add.w (%a0),%d3 # add DENORM exp to 10^ISCALE exp
13921 1.1 is subi.w &0x3fff,%d3 # subtract BIAS
13922 1.1 is add.w 36(%a1),%d3
13923 1.1 is subi.w &0x3fff,%d3 # subtract BIAS
13924 1.1 is add.w 48(%a1),%d3
13925 1.1 is subi.w &0x3fff,%d3 # subtract BIAS
13926 1.1 is
13927 1.1 is bmi.w sc_mul_err # is result is DENORM, punt!!!
13928 1.1 is
13929 1.1 is andi.w &0x8000,(%sp) # keep sign
13930 1.1 is or.w %d3,(%sp) # insert new exponent
13931 1.1 is andi.w &0x7fff,(%a0) # clear sign bit on DENORM again
13932 1.1 is mov.l 0x8(%a0),-(%sp) # put input op mantissa on stk
13933 1.1 is mov.l 0x4(%a0),-(%sp)
13934 1.1 is mov.l &0x3fff0000,-(%sp) # force exp to zero
13935 1.1 is fmovm.x (%sp)+,&0x80 # load normalized DENORM into fp0
13936 1.1 is fmul.x (%sp)+,%fp0
13937 1.1 is
13938 1.1 is # fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8
13939 1.1 is # fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16
13940 1.1 is mov.l 36+8(%a1),-(%sp) # get 10^8 mantissa
13941 1.1 is mov.l 36+4(%a1),-(%sp)
13942 1.1 is mov.l &0x3fff0000,-(%sp) # force exp to zero
13943 1.1 is mov.l 48+8(%a1),-(%sp) # get 10^16 mantissa
13944 1.1 is mov.l 48+4(%a1),-(%sp)
13945 1.1 is mov.l &0x3fff0000,-(%sp)# force exp to zero
13946 1.1 is fmul.x (%sp)+,%fp0 # multiply fp0 by 10^8
13947 1.1 is fmul.x (%sp)+,%fp0 # multiply fp0 by 10^16
13948 1.1 is bra.b A10_st
13949 1.1 is
13950 1.1 is sc_mul_err:
13951 1.1 is bra.b sc_mul_err
13952 1.1 is
13953 1.1 is A9_norm:
13954 1.1 is tst.w %d2 # test for small exp case
13955 1.1 is beq.b A9_con # if zero, continue as normal
13956 1.1 is fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8
13957 1.1 is fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16
13958 1.1 is A9_con:
13959 1.1 is fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0
13960 1.1 is
13961 1.1 is # A10. Or in INEX.
13962 1.2 wiz # If INEX is set, round error occurred. This is compensated
13963 1.1 is # for by 'or-ing' in the INEX2 flag to the lsb of Y.
13964 1.1 is #
13965 1.1 is # Register usage:
13966 1.1 is # Input/Output
13967 1.1 is # d0: FPCR with RZ mode/FPSR with INEX2 isolated
13968 1.1 is # d2: x/x
13969 1.1 is # d3: x/x
13970 1.1 is # d4: LEN/Unchanged
13971 1.1 is # d5: ICTR:LAMBDA
13972 1.1 is # d6: ILOG/Unchanged
13973 1.1 is # d7: k-factor/Unchanged
13974 1.1 is # a0: ptr for original operand/final result
13975 1.1 is # a1: ptr to PTENxx array/Unchanged
13976 1.1 is # a2: x/ptr to FP_SCR1(a6)
13977 1.1 is # fp0: Y/Y with lsb adjusted
13978 1.1 is # fp1: 10^ISCALE/Unchanged
13979 1.1 is # fp2: x/x
13980 1.1 is
13981 1.1 is A10_st:
13982 1.1 is fmov.l %fpsr,%d0 # get FPSR
13983 1.1 is fmov.x %fp0,FP_SCR1(%a6) # move Y to memory
13984 1.1 is lea.l FP_SCR1(%a6),%a2 # load a2 with ptr to FP_SCR1
13985 1.1 is btst &9,%d0 # check if INEX2 set
13986 1.1 is beq.b A11_st # if clear, skip rest
13987 1.1 is or.l &1,8(%a2) # or in 1 to lsb of mantissa
13988 1.1 is fmov.x FP_SCR1(%a6),%fp0 # write adjusted Y back to fpu
13989 1.1 is
13990 1.1 is
13991 1.1 is # A11. Restore original FPCR; set size ext.
13992 1.1 is # Perform FINT operation in the user's rounding mode. Keep
13993 1.1 is # the size to extended. The sintdo entry point in the sint
13994 1.1 is # routine expects the FPCR value to be in USER_FPCR for
13995 1.1 is # mode and precision. The original FPCR is saved in L_SCR1.
13996 1.1 is
13997 1.1 is A11_st:
13998 1.1 is mov.l USER_FPCR(%a6),L_SCR1(%a6) # save it for later
13999 1.1 is and.l &0x00000030,USER_FPCR(%a6) # set size to ext,
14000 1.1 is # ;block exceptions
14001 1.1 is
14002 1.1 is
14003 1.1 is # A12. Calculate YINT = FINT(Y) according to user's rounding mode.
14004 1.1 is # The FPSP routine sintd0 is used. The output is in fp0.
14005 1.1 is #
14006 1.1 is # Register usage:
14007 1.1 is # Input/Output
14008 1.1 is # d0: FPSR with AINEX cleared/FPCR with size set to ext
14009 1.1 is # d2: x/x/scratch
14010 1.1 is # d3: x/x
14011 1.1 is # d4: LEN/Unchanged
14012 1.1 is # d5: ICTR:LAMBDA/Unchanged
14013 1.1 is # d6: ILOG/Unchanged
14014 1.1 is # d7: k-factor/Unchanged
14015 1.1 is # a0: ptr for original operand/src ptr for sintdo
14016 1.1 is # a1: ptr to PTENxx array/Unchanged
14017 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged
14018 1.1 is # a6: temp pointer to FP_SCR1(a6) - orig value saved and restored
14019 1.1 is # fp0: Y/YINT
14020 1.1 is # fp1: 10^ISCALE/Unchanged
14021 1.1 is # fp2: x/x
14022 1.1 is # F_SCR1:x/x
14023 1.1 is # F_SCR2:Y adjusted for inex/Y with original exponent
14024 1.1 is # L_SCR1:x/original USER_FPCR
14025 1.1 is # L_SCR2:first word of X packed/Unchanged
14026 1.1 is
14027 1.1 is A12_st:
14028 1.1 is movm.l &0xc0c0,-(%sp) # save regs used by sintd0 {%d0-%d1/%a0-%a1}
14029 1.1 is mov.l L_SCR1(%a6),-(%sp)
14030 1.1 is mov.l L_SCR2(%a6),-(%sp)
14031 1.1 is
14032 1.1 is lea.l FP_SCR1(%a6),%a0 # a0 is ptr to FP_SCR1(a6)
14033 1.1 is fmov.x %fp0,(%a0) # move Y to memory at FP_SCR1(a6)
14034 1.1 is tst.l L_SCR2(%a6) # test sign of original operand
14035 1.1 is bge.b do_fint12 # if pos, use Y
14036 1.1 is or.l &0x80000000,(%a0) # if neg, use -Y
14037 1.1 is do_fint12:
14038 1.1 is mov.l USER_FPSR(%a6),-(%sp)
14039 1.1 is # bsr sintdo # sint routine returns int in fp0
14040 1.1 is
14041 1.1 is fmov.l USER_FPCR(%a6),%fpcr
14042 1.1 is fmov.l &0x0,%fpsr # clear the AEXC bits!!!
14043 1.1 is ## mov.l USER_FPCR(%a6),%d0 # ext prec/keep rnd mode
14044 1.1 is ## andi.l &0x00000030,%d0
14045 1.1 is ## fmov.l %d0,%fpcr
14046 1.1 is fint.x FP_SCR1(%a6),%fp0 # do fint()
14047 1.1 is fmov.l %fpsr,%d0
14048 1.1 is or.w %d0,FPSR_EXCEPT(%a6)
14049 1.1 is ## fmov.l &0x0,%fpcr
14050 1.1 is ## fmov.l %fpsr,%d0 # don't keep ccodes
14051 1.1 is ## or.w %d0,FPSR_EXCEPT(%a6)
14052 1.1 is
14053 1.1 is mov.b (%sp),USER_FPSR(%a6)
14054 1.1 is add.l &4,%sp
14055 1.1 is
14056 1.1 is mov.l (%sp)+,L_SCR2(%a6)
14057 1.1 is mov.l (%sp)+,L_SCR1(%a6)
14058 1.1 is movm.l (%sp)+,&0x303 # restore regs used by sint {%d0-%d1/%a0-%a1}
14059 1.1 is
14060 1.1 is mov.l L_SCR2(%a6),FP_SCR1(%a6) # restore original exponent
14061 1.1 is mov.l L_SCR1(%a6),USER_FPCR(%a6) # restore user's FPCR
14062 1.1 is
14063 1.1 is # A13. Check for LEN digits.
14064 1.1 is # If the int operation results in more than LEN digits,
14065 1.1 is # or less than LEN -1 digits, adjust ILOG and repeat from
14066 1.1 is # A6. This test occurs only on the first pass. If the
14067 1.1 is # result is exactly 10^LEN, decrement ILOG and divide
14068 1.1 is # the mantissa by 10. The calculation of 10^LEN cannot
14069 1.1 is # be inexact, since all powers of ten upto 10^27 are exact
14070 1.1 is # in extended precision, so the use of a previous power-of-ten
14071 1.1 is # table will introduce no error.
14072 1.1 is #
14073 1.1 is #
14074 1.1 is # Register usage:
14075 1.1 is # Input/Output
14076 1.1 is # d0: FPCR with size set to ext/scratch final = 0
14077 1.1 is # d2: x/x
14078 1.1 is # d3: x/scratch final = x
14079 1.1 is # d4: LEN/LEN adjusted
14080 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR
14081 1.1 is # d6: ILOG/ILOG adjusted
14082 1.1 is # d7: k-factor/Unchanged
14083 1.1 is # a0: pointer into memory for packed bcd string formation
14084 1.1 is # a1: ptr to PTENxx array/Unchanged
14085 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged
14086 1.1 is # fp0: int portion of Y/abs(YINT) adjusted
14087 1.1 is # fp1: 10^ISCALE/Unchanged
14088 1.1 is # fp2: x/10^LEN
14089 1.1 is # F_SCR1:x/x
14090 1.1 is # F_SCR2:Y with original exponent/Unchanged
14091 1.1 is # L_SCR1:original USER_FPCR/Unchanged
14092 1.1 is # L_SCR2:first word of X packed/Unchanged
14093 1.1 is
14094 1.1 is A13_st:
14095 1.1 is swap %d5 # put ICTR in lower word of d5
14096 1.1 is tst.w %d5 # check if ICTR = 0
14097 1.1 is bne not_zr # if non-zero, go to second test
14098 1.1 is #
14099 1.1 is # Compute 10^(LEN-1)
14100 1.1 is #
14101 1.1 is fmov.s FONE(%pc),%fp2 # init fp2 to 1.0
14102 1.1 is mov.l %d4,%d0 # put LEN in d0
14103 1.1 is subq.l &1,%d0 # d0 = LEN -1
14104 1.1 is clr.l %d3 # clr table index
14105 1.1 is l_loop:
14106 1.1 is lsr.l &1,%d0 # shift next bit into carry
14107 1.1 is bcc.b l_next # if zero, skip the mul
14108 1.1 is fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no)
14109 1.1 is l_next:
14110 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry
14111 1.1 is tst.l %d0 # test if LEN is zero
14112 1.1 is bne.b l_loop # if not, loop
14113 1.1 is #
14114 1.1 is # 10^LEN-1 is computed for this test and A14. If the input was
14115 1.1 is # denormalized, check only the case in which YINT > 10^LEN.
14116 1.1 is #
14117 1.1 is tst.b BINDEC_FLG(%a6) # check if input was norm
14118 1.1 is beq.b A13_con # if norm, continue with checking
14119 1.1 is fabs.x %fp0 # take abs of YINT
14120 1.1 is bra test_2
14121 1.1 is #
14122 1.1 is # Compare abs(YINT) to 10^(LEN-1) and 10^LEN
14123 1.1 is #
14124 1.1 is A13_con:
14125 1.1 is fabs.x %fp0 # take abs of YINT
14126 1.1 is fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^(LEN-1)
14127 1.1 is fbge.w test_2 # if greater, do next test
14128 1.1 is subq.l &1,%d6 # subtract 1 from ILOG
14129 1.1 is mov.w &1,%d5 # set ICTR
14130 1.1 is fmov.l &rm_mode*0x10,%fpcr # set rmode to RM
14131 1.1 is fmul.s FTEN(%pc),%fp2 # compute 10^LEN
14132 1.1 is bra.w A6_str # return to A6 and recompute YINT
14133 1.1 is test_2:
14134 1.1 is fmul.s FTEN(%pc),%fp2 # compute 10^LEN
14135 1.1 is fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^LEN
14136 1.1 is fblt.w A14_st # if less, all is ok, go to A14
14137 1.1 is fbgt.w fix_ex # if greater, fix and redo
14138 1.1 is fdiv.s FTEN(%pc),%fp0 # if equal, divide by 10
14139 1.1 is addq.l &1,%d6 # and inc ILOG
14140 1.1 is bra.b A14_st # and continue elsewhere
14141 1.1 is fix_ex:
14142 1.1 is addq.l &1,%d6 # increment ILOG by 1
14143 1.1 is mov.w &1,%d5 # set ICTR
14144 1.1 is fmov.l &rm_mode*0x10,%fpcr # set rmode to RM
14145 1.1 is bra.w A6_str # return to A6 and recompute YINT
14146 1.1 is #
14147 1.1 is # Since ICTR <> 0, we have already been through one adjustment,
14148 1.1 is # and shouldn't have another; this is to check if abs(YINT) = 10^LEN
14149 1.1 is # 10^LEN is again computed using whatever table is in a1 since the
14150 1.1 is # value calculated cannot be inexact.
14151 1.1 is #
14152 1.1 is not_zr:
14153 1.1 is fmov.s FONE(%pc),%fp2 # init fp2 to 1.0
14154 1.1 is mov.l %d4,%d0 # put LEN in d0
14155 1.1 is clr.l %d3 # clr table index
14156 1.1 is z_loop:
14157 1.1 is lsr.l &1,%d0 # shift next bit into carry
14158 1.1 is bcc.b z_next # if zero, skip the mul
14159 1.1 is fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no)
14160 1.1 is z_next:
14161 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry
14162 1.1 is tst.l %d0 # test if LEN is zero
14163 1.1 is bne.b z_loop # if not, loop
14164 1.1 is fabs.x %fp0 # get abs(YINT)
14165 1.1 is fcmp.x %fp0,%fp2 # check if abs(YINT) = 10^LEN
14166 1.1 is fbneq.w A14_st # if not, skip this
14167 1.1 is fdiv.s FTEN(%pc),%fp0 # divide abs(YINT) by 10
14168 1.1 is addq.l &1,%d6 # and inc ILOG by 1
14169 1.1 is addq.l &1,%d4 # and inc LEN
14170 1.1 is fmul.s FTEN(%pc),%fp2 # if LEN++, the get 10^^LEN
14171 1.1 is
14172 1.1 is # A14. Convert the mantissa to bcd.
14173 1.1 is # The binstr routine is used to convert the LEN digit
14174 1.1 is # mantissa to bcd in memory. The input to binstr is
14175 1.1 is # to be a fraction; i.e. (mantissa)/10^LEN and adjusted
14176 1.1 is # such that the decimal point is to the left of bit 63.
14177 1.1 is # The bcd digits are stored in the correct position in
14178 1.1 is # the final string area in memory.
14179 1.1 is #
14180 1.1 is #
14181 1.1 is # Register usage:
14182 1.1 is # Input/Output
14183 1.1 is # d0: x/LEN call to binstr - final is 0
14184 1.1 is # d1: x/0
14185 1.1 is # d2: x/ms 32-bits of mant of abs(YINT)
14186 1.1 is # d3: x/ls 32-bits of mant of abs(YINT)
14187 1.1 is # d4: LEN/Unchanged
14188 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR
14189 1.1 is # d6: ILOG
14190 1.1 is # d7: k-factor/Unchanged
14191 1.1 is # a0: pointer into memory for packed bcd string formation
14192 1.1 is # /ptr to first mantissa byte in result string
14193 1.1 is # a1: ptr to PTENxx array/Unchanged
14194 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged
14195 1.1 is # fp0: int portion of Y/abs(YINT) adjusted
14196 1.1 is # fp1: 10^ISCALE/Unchanged
14197 1.1 is # fp2: 10^LEN/Unchanged
14198 1.1 is # F_SCR1:x/Work area for final result
14199 1.1 is # F_SCR2:Y with original exponent/Unchanged
14200 1.1 is # L_SCR1:original USER_FPCR/Unchanged
14201 1.1 is # L_SCR2:first word of X packed/Unchanged
14202 1.1 is
14203 1.1 is A14_st:
14204 1.1 is fmov.l &rz_mode*0x10,%fpcr # force rz for conversion
14205 1.1 is fdiv.x %fp2,%fp0 # divide abs(YINT) by 10^LEN
14206 1.1 is lea.l FP_SCR0(%a6),%a0
14207 1.1 is fmov.x %fp0,(%a0) # move abs(YINT)/10^LEN to memory
14208 1.1 is mov.l 4(%a0),%d2 # move 2nd word of FP_RES to d2
14209 1.1 is mov.l 8(%a0),%d3 # move 3rd word of FP_RES to d3
14210 1.1 is clr.l 4(%a0) # zero word 2 of FP_RES
14211 1.1 is clr.l 8(%a0) # zero word 3 of FP_RES
14212 1.1 is mov.l (%a0),%d0 # move exponent to d0
14213 1.1 is swap %d0 # put exponent in lower word
14214 1.1 is beq.b no_sft # if zero, don't shift
14215 1.1 is sub.l &0x3ffd,%d0 # sub bias less 2 to make fract
14216 1.1 is tst.l %d0 # check if > 1
14217 1.1 is bgt.b no_sft # if so, don't shift
14218 1.1 is neg.l %d0 # make exp positive
14219 1.1 is m_loop:
14220 1.1 is lsr.l &1,%d2 # shift d2:d3 right, add 0s
14221 1.1 is roxr.l &1,%d3 # the number of places
14222 1.1 is dbf.w %d0,m_loop # given in d0
14223 1.1 is no_sft:
14224 1.1 is tst.l %d2 # check for mantissa of zero
14225 1.1 is bne.b no_zr # if not, go on
14226 1.1 is tst.l %d3 # continue zero check
14227 1.1 is beq.b zer_m # if zero, go directly to binstr
14228 1.1 is no_zr:
14229 1.1 is clr.l %d1 # put zero in d1 for addx
14230 1.1 is add.l &0x00000080,%d3 # inc at bit 7
14231 1.1 is addx.l %d1,%d2 # continue inc
14232 1.1 is and.l &0xffffff80,%d3 # strip off lsb not used by 882
14233 1.1 is zer_m:
14234 1.1 is mov.l %d4,%d0 # put LEN in d0 for binstr call
14235 1.1 is addq.l &3,%a0 # a0 points to M16 byte in result
14236 1.1 is bsr binstr # call binstr to convert mant
14237 1.1 is
14238 1.1 is
14239 1.1 is # A15. Convert the exponent to bcd.
14240 1.1 is # As in A14 above, the exp is converted to bcd and the
14241 1.1 is # digits are stored in the final string.
14242 1.1 is #
14243 1.1 is # Digits are stored in L_SCR1(a6) on return from BINDEC as:
14244 1.1 is #
14245 1.1 is # 32 16 15 0
14246 1.1 is # -----------------------------------------
14247 1.1 is # | 0 | e3 | e2 | e1 | e4 | X | X | X |
14248 1.1 is # -----------------------------------------
14249 1.1 is #
14250 1.1 is # And are moved into their proper places in FP_SCR0. If digit e4
14251 1.1 is # is non-zero, OPERR is signaled. In all cases, all 4 digits are
14252 1.1 is # written as specified in the 881/882 manual for packed decimal.
14253 1.1 is #
14254 1.1 is # Register usage:
14255 1.1 is # Input/Output
14256 1.1 is # d0: x/LEN call to binstr - final is 0
14257 1.1 is # d1: x/scratch (0);shift count for final exponent packing
14258 1.1 is # d2: x/ms 32-bits of exp fraction/scratch
14259 1.1 is # d3: x/ls 32-bits of exp fraction
14260 1.1 is # d4: LEN/Unchanged
14261 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR
14262 1.1 is # d6: ILOG
14263 1.1 is # d7: k-factor/Unchanged
14264 1.1 is # a0: ptr to result string/ptr to L_SCR1(a6)
14265 1.1 is # a1: ptr to PTENxx array/Unchanged
14266 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged
14267 1.1 is # fp0: abs(YINT) adjusted/float(ILOG)
14268 1.1 is # fp1: 10^ISCALE/Unchanged
14269 1.1 is # fp2: 10^LEN/Unchanged
14270 1.1 is # F_SCR1:Work area for final result/BCD result
14271 1.1 is # F_SCR2:Y with original exponent/ILOG/10^4
14272 1.1 is # L_SCR1:original USER_FPCR/Exponent digits on return from binstr
14273 1.1 is # L_SCR2:first word of X packed/Unchanged
14274 1.1 is
14275 1.1 is A15_st:
14276 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm
14277 1.1 is beq.b not_denorm
14278 1.1 is ftest.x %fp0 # test for zero
14279 1.1 is fbeq.w den_zero # if zero, use k-factor or 4933
14280 1.1 is fmov.l %d6,%fp0 # float ILOG
14281 1.1 is fabs.x %fp0 # get abs of ILOG
14282 1.1 is bra.b convrt
14283 1.1 is den_zero:
14284 1.1 is tst.l %d7 # check sign of the k-factor
14285 1.1 is blt.b use_ilog # if negative, use ILOG
14286 1.1 is fmov.s F4933(%pc),%fp0 # force exponent to 4933
14287 1.1 is bra.b convrt # do it
14288 1.1 is use_ilog:
14289 1.1 is fmov.l %d6,%fp0 # float ILOG
14290 1.1 is fabs.x %fp0 # get abs of ILOG
14291 1.1 is bra.b convrt
14292 1.1 is not_denorm:
14293 1.1 is ftest.x %fp0 # test for zero
14294 1.1 is fbneq.w not_zero # if zero, force exponent
14295 1.1 is fmov.s FONE(%pc),%fp0 # force exponent to 1
14296 1.1 is bra.b convrt # do it
14297 1.1 is not_zero:
14298 1.1 is fmov.l %d6,%fp0 # float ILOG
14299 1.1 is fabs.x %fp0 # get abs of ILOG
14300 1.1 is convrt:
14301 1.1 is fdiv.x 24(%a1),%fp0 # compute ILOG/10^4
14302 1.1 is fmov.x %fp0,FP_SCR1(%a6) # store fp0 in memory
14303 1.1 is mov.l 4(%a2),%d2 # move word 2 to d2
14304 1.1 is mov.l 8(%a2),%d3 # move word 3 to d3
14305 1.1 is mov.w (%a2),%d0 # move exp to d0
14306 1.1 is beq.b x_loop_fin # if zero, skip the shift
14307 1.1 is sub.w &0x3ffd,%d0 # subtract off bias
14308 1.1 is neg.w %d0 # make exp positive
14309 1.1 is x_loop:
14310 1.1 is lsr.l &1,%d2 # shift d2:d3 right
14311 1.1 is roxr.l &1,%d3 # the number of places
14312 1.1 is dbf.w %d0,x_loop # given in d0
14313 1.1 is x_loop_fin:
14314 1.1 is clr.l %d1 # put zero in d1 for addx
14315 1.1 is add.l &0x00000080,%d3 # inc at bit 6
14316 1.1 is addx.l %d1,%d2 # continue inc
14317 1.1 is and.l &0xffffff80,%d3 # strip off lsb not used by 882
14318 1.1 is mov.l &4,%d0 # put 4 in d0 for binstr call
14319 1.1 is lea.l L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits
14320 1.1 is bsr binstr # call binstr to convert exp
14321 1.1 is mov.l L_SCR1(%a6),%d0 # load L_SCR1 lword to d0
14322 1.1 is mov.l &12,%d1 # use d1 for shift count
14323 1.1 is lsr.l %d1,%d0 # shift d0 right by 12
14324 1.1 is bfins %d0,FP_SCR0(%a6){&4:&12} # put e3:e2:e1 in FP_SCR0
14325 1.1 is lsr.l %d1,%d0 # shift d0 right by 12
14326 1.1 is bfins %d0,FP_SCR0(%a6){&16:&4} # put e4 in FP_SCR0
14327 1.1 is tst.b %d0 # check if e4 is zero
14328 1.1 is beq.b A16_st # if zero, skip rest
14329 1.1 is or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR
14330 1.1 is
14331 1.1 is
14332 1.1 is # A16. Write sign bits to final string.
14333 1.1 is # Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
14334 1.1 is #
14335 1.1 is # Register usage:
14336 1.1 is # Input/Output
14337 1.1 is # d0: x/scratch - final is x
14338 1.1 is # d2: x/x
14339 1.1 is # d3: x/x
14340 1.1 is # d4: LEN/Unchanged
14341 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR
14342 1.1 is # d6: ILOG/ILOG adjusted
14343 1.1 is # d7: k-factor/Unchanged
14344 1.1 is # a0: ptr to L_SCR1(a6)/Unchanged
14345 1.1 is # a1: ptr to PTENxx array/Unchanged
14346 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged
14347 1.1 is # fp0: float(ILOG)/Unchanged
14348 1.1 is # fp1: 10^ISCALE/Unchanged
14349 1.1 is # fp2: 10^LEN/Unchanged
14350 1.1 is # F_SCR1:BCD result with correct signs
14351 1.1 is # F_SCR2:ILOG/10^4
14352 1.1 is # L_SCR1:Exponent digits on return from binstr
14353 1.1 is # L_SCR2:first word of X packed/Unchanged
14354 1.1 is
14355 1.1 is A16_st:
14356 1.1 is clr.l %d0 # clr d0 for collection of signs
14357 1.1 is and.b &0x0f,FP_SCR0(%a6) # clear first nibble of FP_SCR0
14358 1.1 is tst.l L_SCR2(%a6) # check sign of original mantissa
14359 1.1 is bge.b mant_p # if pos, don't set SM
14360 1.1 is mov.l &2,%d0 # move 2 in to d0 for SM
14361 1.1 is mant_p:
14362 1.1 is tst.l %d6 # check sign of ILOG
14363 1.1 is bge.b wr_sgn # if pos, don't set SE
14364 1.1 is addq.l &1,%d0 # set bit 0 in d0 for SE
14365 1.1 is wr_sgn:
14366 1.1 is bfins %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0
14367 1.1 is
14368 1.1 is # Clean up and restore all registers used.
14369 1.1 is
14370 1.1 is fmov.l &0,%fpsr # clear possible inex2/ainex bits
14371 1.1 is fmovm.x (%sp)+,&0xe0 # {%fp0-%fp2}
14372 1.1 is movm.l (%sp)+,&0x4fc # {%d2-%d7/%a2}
14373 1.1 is rts
14374 1.1 is
14375 1.1 is global PTENRN
14376 1.1 is PTENRN:
14377 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14378 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14379 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14380 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14381 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14382 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32
14383 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64
14384 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128
14385 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256
14386 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512
14387 1.1 is long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024
14388 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048
14389 1.1 is long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096
14390 1.1 is
14391 1.1 is global PTENRP
14392 1.1 is PTENRP:
14393 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14394 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14395 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14396 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14397 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14398 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32
14399 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D6 # 10 ^ 64
14400 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128
14401 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256
14402 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512
14403 1.1 is long 0x4D480000,0xC9767586,0x81750C18 # 10 ^ 1024
14404 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048
14405 1.1 is long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096
14406 1.1 is
14407 1.1 is global PTENRM
14408 1.1 is PTENRM:
14409 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14410 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14411 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14412 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14413 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14414 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59D # 10 ^ 32
14415 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64
14416 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CDF # 10 ^ 128
14417 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8D # 10 ^ 256
14418 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C6 # 10 ^ 512
14419 1.1 is long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024
14420 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE4 # 10 ^ 2048
14421 1.1 is long 0x75250000,0xC4605202,0x8A20979A # 10 ^ 4096
14422 1.1 is
14423 1.1 is #########################################################################
14424 1.1 is # binstr(): Converts a 64-bit binary integer to bcd. #
14425 1.1 is # #
14426 1.1 is # INPUT *************************************************************** #
14427 1.1 is # d2:d3 = 64-bit binary integer #
14428 1.1 is # d0 = desired length (LEN) #
14429 1.1 is # a0 = pointer to start in memory for bcd characters #
14430 1.1 is # (This pointer must point to byte 4 of the first #
14431 1.1 is # lword of the packed decimal memory string.) #
14432 1.1 is # #
14433 1.1 is # OUTPUT ************************************************************** #
14434 1.1 is # a0 = pointer to LEN bcd digits representing the 64-bit integer. #
14435 1.1 is # #
14436 1.1 is # ALGORITHM *********************************************************** #
14437 1.1 is # The 64-bit binary is assumed to have a decimal point before #
14438 1.1 is # bit 63. The fraction is multiplied by 10 using a mul by 2 #
14439 1.1 is # shift and a mul by 8 shift. The bits shifted out of the #
14440 1.1 is # msb form a decimal digit. This process is iterated until #
14441 1.1 is # LEN digits are formed. #
14442 1.1 is # #
14443 1.1 is # A1. Init d7 to 1. D7 is the byte digit counter, and if 1, the #
14444 1.1 is # digit formed will be assumed the least significant. This is #
14445 1.1 is # to force the first byte formed to have a 0 in the upper 4 bits. #
14446 1.1 is # #
14447 1.1 is # A2. Beginning of the loop: #
14448 1.1 is # Copy the fraction in d2:d3 to d4:d5. #
14449 1.1 is # #
14450 1.1 is # A3. Multiply the fraction in d2:d3 by 8 using bit-field #
14451 1.1 is # extracts and shifts. The three msbs from d2 will go into d1. #
14452 1.1 is # #
14453 1.1 is # A4. Multiply the fraction in d4:d5 by 2 using shifts. The msb #
14454 1.1 is # will be collected by the carry. #
14455 1.1 is # #
14456 1.1 is # A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5 #
14457 1.1 is # into d2:d3. D1 will contain the bcd digit formed. #
14458 1.1 is # #
14459 1.1 is # A6. Test d7. If zero, the digit formed is the ms digit. If non- #
14460 1.1 is # zero, it is the ls digit. Put the digit in its place in the #
14461 1.1 is # upper word of d0. If it is the ls digit, write the word #
14462 1.1 is # from d0 to memory. #
14463 1.1 is # #
14464 1.1 is # A7. Decrement d6 (LEN counter) and repeat the loop until zero. #
14465 1.1 is # #
14466 1.1 is #########################################################################
14467 1.1 is
14468 1.1 is # Implementation Notes:
14469 1.1 is #
14470 1.1 is # The registers are used as follows:
14471 1.1 is #
14472 1.1 is # d0: LEN counter
14473 1.1 is # d1: temp used to form the digit
14474 1.1 is # d2: upper 32-bits of fraction for mul by 8
14475 1.1 is # d3: lower 32-bits of fraction for mul by 8
14476 1.1 is # d4: upper 32-bits of fraction for mul by 2
14477 1.1 is # d5: lower 32-bits of fraction for mul by 2
14478 1.1 is # d6: temp for bit-field extracts
14479 1.1 is # d7: byte digit formation word;digit count {0,1}
14480 1.1 is # a0: pointer into memory for packed bcd string formation
14481 1.1 is #
14482 1.1 is
14483 1.1 is global binstr
14484 1.1 is binstr:
14485 1.1 is movm.l &0xff00,-(%sp) # {%d0-%d7}
14486 1.1 is
14487 1.1 is #
14488 1.1 is # A1: Init d7
14489 1.1 is #
14490 1.1 is mov.l &1,%d7 # init d7 for second digit
14491 1.1 is subq.l &1,%d0 # for dbf d0 would have LEN+1 passes
14492 1.1 is #
14493 1.1 is # A2. Copy d2:d3 to d4:d5. Start loop.
14494 1.1 is #
14495 1.1 is loop:
14496 1.1 is mov.l %d2,%d4 # copy the fraction before muls
14497 1.1 is mov.l %d3,%d5 # to d4:d5
14498 1.1 is #
14499 1.1 is # A3. Multiply d2:d3 by 8; extract msbs into d1.
14500 1.1 is #
14501 1.1 is bfextu %d2{&0:&3},%d1 # copy 3 msbs of d2 into d1
14502 1.1 is asl.l &3,%d2 # shift d2 left by 3 places
14503 1.1 is bfextu %d3{&0:&3},%d6 # copy 3 msbs of d3 into d6
14504 1.1 is asl.l &3,%d3 # shift d3 left by 3 places
14505 1.1 is or.l %d6,%d2 # or in msbs from d3 into d2
14506 1.1 is #
14507 1.1 is # A4. Multiply d4:d5 by 2; add carry out to d1.
14508 1.1 is #
14509 1.1 is asl.l &1,%d5 # mul d5 by 2
14510 1.1 is roxl.l &1,%d4 # mul d4 by 2
14511 1.1 is swap %d6 # put 0 in d6 lower word
14512 1.1 is addx.w %d6,%d1 # add in extend from mul by 2
14513 1.1 is #
14514 1.1 is # A5. Add mul by 8 to mul by 2. D1 contains the digit formed.
14515 1.1 is #
14516 1.1 is add.l %d5,%d3 # add lower 32 bits
14517 1.1 is nop # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14518 1.1 is addx.l %d4,%d2 # add with extend upper 32 bits
14519 1.1 is nop # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14520 1.1 is addx.w %d6,%d1 # add in extend from add to d1
14521 1.1 is swap %d6 # with d6 = 0; put 0 in upper word
14522 1.1 is #
14523 1.1 is # A6. Test d7 and branch.
14524 1.1 is #
14525 1.1 is tst.w %d7 # if zero, store digit & to loop
14526 1.1 is beq.b first_d # if non-zero, form byte & write
14527 1.1 is sec_d:
14528 1.1 is swap %d7 # bring first digit to word d7b
14529 1.1 is asl.w &4,%d7 # first digit in upper 4 bits d7b
14530 1.1 is add.w %d1,%d7 # add in ls digit to d7b
14531 1.1 is mov.b %d7,(%a0)+ # store d7b byte in memory
14532 1.1 is swap %d7 # put LEN counter in word d7a
14533 1.1 is clr.w %d7 # set d7a to signal no digits done
14534 1.1 is dbf.w %d0,loop # do loop some more!
14535 1.1 is bra.b end_bstr # finished, so exit
14536 1.1 is first_d:
14537 1.1 is swap %d7 # put digit word in d7b
14538 1.1 is mov.w %d1,%d7 # put new digit in d7b
14539 1.1 is swap %d7 # put LEN counter in word d7a
14540 1.1 is addq.w &1,%d7 # set d7a to signal first digit done
14541 1.1 is dbf.w %d0,loop # do loop some more!
14542 1.1 is swap %d7 # put last digit in string
14543 1.1 is lsl.w &4,%d7 # move it to upper 4 bits
14544 1.1 is mov.b %d7,(%a0)+ # store it in memory string
14545 1.1 is #
14546 1.1 is # Clean up and return with result in fp0.
14547 1.1 is #
14548 1.1 is end_bstr:
14549 1.1 is movm.l (%sp)+,&0xff # {%d0-%d7}
14550 1.1 is rts
14551 1.1 is
14552 1.1 is #########################################################################
14553 1.1 is # XDEF **************************************************************** #
14554 1.1 is # facc_in_b(): dmem_read_byte failed #
14555 1.1 is # facc_in_w(): dmem_read_word failed #
14556 1.1 is # facc_in_l(): dmem_read_long failed #
14557 1.1 is # facc_in_d(): dmem_read of dbl prec failed #
14558 1.1 is # facc_in_x(): dmem_read of ext prec failed #
14559 1.1 is # #
14560 1.1 is # facc_out_b(): dmem_write_byte failed #
14561 1.1 is # facc_out_w(): dmem_write_word failed #
14562 1.1 is # facc_out_l(): dmem_write_long failed #
14563 1.1 is # facc_out_d(): dmem_write of dbl prec failed #
14564 1.1 is # facc_out_x(): dmem_write of ext prec failed #
14565 1.1 is # #
14566 1.1 is # XREF **************************************************************** #
14567 1.1 is # _real_access() - exit through access error handler #
14568 1.1 is # #
14569 1.1 is # INPUT *************************************************************** #
14570 1.1 is # None #
14571 1.1 is # #
14572 1.1 is # OUTPUT ************************************************************** #
14573 1.1 is # None #
14574 1.1 is # #
14575 1.1 is # ALGORITHM *********************************************************** #
14576 1.1 is # Flow jumps here when an FP data fetch call gets an error #
14577 1.1 is # result. This means the operating system wants an access error frame #
14578 1.1 is # made out of the current exception stack frame. #
14579 1.1 is # So, we first call restore() which makes sure that any updated #
14580 1.1 is # -(an)+ register gets returned to its pre-exception value and then #
14581 1.1 is # we change the stack to an acess error stack frame. #
14582 1.1 is # #
14583 1.1 is #########################################################################
14584 1.1 is
14585 1.1 is facc_in_b:
14586 1.1 is movq.l &0x1,%d0 # one byte
14587 1.1 is bsr.w restore # fix An
14588 1.1 is
14589 1.1 is mov.w &0x0121,EXC_VOFF(%a6) # set FSLW
14590 1.1 is bra.w facc_finish
14591 1.1 is
14592 1.1 is facc_in_w:
14593 1.1 is movq.l &0x2,%d0 # two bytes
14594 1.1 is bsr.w restore # fix An
14595 1.1 is
14596 1.1 is mov.w &0x0141,EXC_VOFF(%a6) # set FSLW
14597 1.1 is bra.b facc_finish
14598 1.1 is
14599 1.1 is facc_in_l:
14600 1.1 is movq.l &0x4,%d0 # four bytes
14601 1.1 is bsr.w restore # fix An
14602 1.1 is
14603 1.1 is mov.w &0x0101,EXC_VOFF(%a6) # set FSLW
14604 1.1 is bra.b facc_finish
14605 1.1 is
14606 1.1 is facc_in_d:
14607 1.1 is movq.l &0x8,%d0 # eight bytes
14608 1.1 is bsr.w restore # fix An
14609 1.1 is
14610 1.1 is mov.w &0x0161,EXC_VOFF(%a6) # set FSLW
14611 1.1 is bra.b facc_finish
14612 1.1 is
14613 1.1 is facc_in_x:
14614 1.1 is movq.l &0xc,%d0 # twelve bytes
14615 1.1 is bsr.w restore # fix An
14616 1.1 is
14617 1.1 is mov.w &0x0161,EXC_VOFF(%a6) # set FSLW
14618 1.1 is bra.b facc_finish
14619 1.1 is
14620 1.1 is ################################################################
14621 1.1 is
14622 1.1 is facc_out_b:
14623 1.1 is movq.l &0x1,%d0 # one byte
14624 1.1 is bsr.w restore # restore An
14625 1.1 is
14626 1.1 is mov.w &0x00a1,EXC_VOFF(%a6) # set FSLW
14627 1.1 is bra.b facc_finish
14628 1.1 is
14629 1.1 is facc_out_w:
14630 1.1 is movq.l &0x2,%d0 # two bytes
14631 1.1 is bsr.w restore # restore An
14632 1.1 is
14633 1.1 is mov.w &0x00c1,EXC_VOFF(%a6) # set FSLW
14634 1.1 is bra.b facc_finish
14635 1.1 is
14636 1.1 is facc_out_l:
14637 1.1 is movq.l &0x4,%d0 # four bytes
14638 1.1 is bsr.w restore # restore An
14639 1.1 is
14640 1.1 is mov.w &0x0081,EXC_VOFF(%a6) # set FSLW
14641 1.1 is bra.b facc_finish
14642 1.1 is
14643 1.1 is facc_out_d:
14644 1.1 is movq.l &0x8,%d0 # eight bytes
14645 1.1 is bsr.w restore # restore An
14646 1.1 is
14647 1.1 is mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW
14648 1.1 is bra.b facc_finish
14649 1.1 is
14650 1.1 is facc_out_x:
14651 1.1 is mov.l &0xc,%d0 # twelve bytes
14652 1.1 is bsr.w restore # restore An
14653 1.1 is
14654 1.1 is mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW
14655 1.1 is
14656 1.1 is # here's where we actually create the access error frame from the
14657 1.1 is # current exception stack frame.
14658 1.1 is facc_finish:
14659 1.1 is mov.l USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
14660 1.1 is
14661 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
14662 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
14663 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
14664 1.1 is
14665 1.1 is unlk %a6
14666 1.1 is
14667 1.1 is mov.l (%sp),-(%sp) # store SR, hi(PC)
14668 1.1 is mov.l 0x8(%sp),0x4(%sp) # store lo(PC)
14669 1.1 is mov.l 0xc(%sp),0x8(%sp) # store EA
14670 1.1 is mov.l &0x00000001,0xc(%sp) # store FSLW
14671 1.1 is mov.w 0x6(%sp),0xc(%sp) # fix FSLW (size)
14672 1.1 is mov.w &0x4008,0x6(%sp) # store voff
14673 1.1 is
14674 1.1 is btst &0x5,(%sp) # supervisor or user mode?
14675 1.1 is beq.b facc_out2 # user
14676 1.1 is bset &0x2,0xd(%sp) # set supervisor TM bit
14677 1.1 is
14678 1.1 is facc_out2:
14679 1.1 is bra.l _real_access
14680 1.1 is
14681 1.1 is ##################################################################
14682 1.1 is
14683 1.1 is # if the effective addressing mode was predecrement or postincrement,
14684 1.1 is # the emulation has already changed its value to the correct post-
14685 1.1 is # instruction value. but since we're exiting to the access error
14686 1.1 is # handler, then AN must be returned to its pre-instruction value.
14687 1.1 is # we do that here.
14688 1.1 is restore:
14689 1.1 is mov.b EXC_OPWORD+0x1(%a6),%d1
14690 1.1 is andi.b &0x38,%d1 # extract opmode
14691 1.1 is cmpi.b %d1,&0x18 # postinc?
14692 1.1 is beq.w rest_inc
14693 1.1 is cmpi.b %d1,&0x20 # predec?
14694 1.1 is beq.w rest_dec
14695 1.1 is rts
14696 1.1 is
14697 1.1 is rest_inc:
14698 1.1 is mov.b EXC_OPWORD+0x1(%a6),%d1
14699 1.1 is andi.w &0x0007,%d1 # fetch An
14700 1.1 is
14701 1.1 is mov.w (tbl_rest_inc.b,%pc,%d1.w*2),%d1
14702 1.1 is jmp (tbl_rest_inc.b,%pc,%d1.w*1)
14703 1.1 is
14704 1.1 is tbl_rest_inc:
14705 1.1 is short ri_a0 - tbl_rest_inc
14706 1.1 is short ri_a1 - tbl_rest_inc
14707 1.1 is short ri_a2 - tbl_rest_inc
14708 1.1 is short ri_a3 - tbl_rest_inc
14709 1.1 is short ri_a4 - tbl_rest_inc
14710 1.1 is short ri_a5 - tbl_rest_inc
14711 1.1 is short ri_a6 - tbl_rest_inc
14712 1.1 is short ri_a7 - tbl_rest_inc
14713 1.1 is
14714 1.1 is ri_a0:
14715 1.1 is sub.l %d0,EXC_DREGS+0x8(%a6) # fix stacked a0
14716 1.1 is rts
14717 1.1 is ri_a1:
14718 1.1 is sub.l %d0,EXC_DREGS+0xc(%a6) # fix stacked a1
14719 1.1 is rts
14720 1.1 is ri_a2:
14721 1.1 is sub.l %d0,%a2 # fix a2
14722 1.1 is rts
14723 1.1 is ri_a3:
14724 1.1 is sub.l %d0,%a3 # fix a3
14725 1.1 is rts
14726 1.1 is ri_a4:
14727 1.1 is sub.l %d0,%a4 # fix a4
14728 1.1 is rts
14729 1.1 is ri_a5:
14730 1.1 is sub.l %d0,%a5 # fix a5
14731 1.1 is rts
14732 1.1 is ri_a6:
14733 1.1 is sub.l %d0,(%a6) # fix stacked a6
14734 1.1 is rts
14735 1.1 is # if it's a fmove out instruction, we don't have to fix a7
14736 1.1 is # because we hadn't changed it yet. if it's an opclass two
14737 1.1 is # instruction (data moved in) and the exception was in supervisor
14738 1.1 is # mode, then also also wasn't updated. if it was user mode, then
14739 1.1 is # restore the correct a7 which is in the USP currently.
14740 1.1 is ri_a7:
14741 1.1 is cmpi.b EXC_VOFF(%a6),&0x30 # move in or out?
14742 1.1 is bne.b ri_a7_done # out
14743 1.1 is
14744 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor?
14745 1.1 is bne.b ri_a7_done # supervisor
14746 1.1 is movc %usp,%a0 # restore USP
14747 1.1 is sub.l %d0,%a0
14748 1.1 is movc %a0,%usp
14749 1.1 is ri_a7_done:
14750 1.1 is rts
14751 1.1 is
14752 1.1 is # need to invert adjustment value if the <ea> was predec
14753 1.1 is rest_dec:
14754 1.1 is neg.l %d0
14755 1.1 is bra.b rest_inc
14756