1*         $NetBSD: x_store.sa,v 1.5 2022/04/08 10:17:53 andvar Exp $
2
3*         MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
4*         M68000 Hi-Performance Microprocessor Division
5*         M68040 Software Package
6*
7*         M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
8*         All rights reserved.
9*
10*         THE SOFTWARE is provided on an "AS IS" basis and without warranty.
11*         To the maximum extent permitted by applicable law,
12*         MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
13*         INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
14*         PARTICULAR PURPOSE and any warranty against infringement with
15*         regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
16*         and any accompanying written materials.
17*
18*         To the maximum extent permitted by applicable law,
19*         IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
20*         (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
21*         PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
22*         OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
23*         SOFTWARE.  Motorola assumes no responsibility for the maintenance
24*         and support of the SOFTWARE.
25*
26*         You are hereby granted a copyright license to use, modify, and
27*         distribute the SOFTWARE so long as this entire notice is retained
28*         without alteration in any modified and/or redistributed versions,
29*         and that such modified versions are clearly identified as such.
30*         No licenses are granted by implication, estoppel or otherwise
31*         under any patents or trademarks of Motorola, Inc.
32
33*
34*         x_store.sa 3.2 1/24/91
35*
36*         store --- store operand to memory or register
37*
38*         Used by underflow and overflow handlers.
39*
40*         a6 = points to fp value to be stored.
41*
42
43X_STORE   IDNT    2,1 Motorola 040 Floating Point Software Package
44
45          section   8
46
47fpreg_mask:
48          dc.b      $80,$40,$20,$10,$08,$04,$02,$01
49
50          include   fpsp.h
51
52          xref      mem_write
53          xref      get_fline
54          xref      g_opcls
55          xref      g_dfmtou
56          xref      reg_dest
57
58          xdef      dest_ext
59          xdef      dest_dbl
60          xdef      dest_sgl
61
62          xdef      store
63store:
64          btst.b    #E3,E_BYTE(a6)
65          beq.b     E1_sto
66E3_sto:
67          move.l    CMDREG3B(a6),d0
68          bfextu    d0{6:3},d0                    ;isolate dest. reg from cmdreg3b
69sto_fp:
70          lea       fpreg_mask,a1
71          move.b    (a1,d0.w),d0                  ;convert reg# to dynamic register mask
72          tst.b     LOCAL_SGN(a0)
73          beq.b     is_pos
74          bset.b    #sign_bit,LOCAL_EX(a0)
75is_pos:
76          fmovem.x (a0),d0              ;move to correct register
77*
78*         if fp0-fp3 is being modified, we must put a copy
79*         in the USER_FPn variable on the stack because all exception
80*         handlers restore fp0-fp3 from there.
81*
82          cmp.b     #$80,d0
83          bne.b     not_fp0
84          fmovem.x fp0,USER_FP0(a6)
85          rts
86not_fp0:
87          cmp.b     #$40,d0
88          bne.b     not_fp1
89          fmovem.x fp1,USER_FP1(a6)
90          rts
91not_fp1:
92          cmp.b     #$20,d0
93          bne.b     not_fp2
94          fmovem.x fp2,USER_FP2(a6)
95          rts
96not_fp2:
97          cmp.b     #$10,d0
98          bne.b     not_fp3
99          fmovem.x fp3,USER_FP3(a6)
100          rts
101not_fp3:
102          rts
103
104E1_sto:
105          bsr.l     g_opcls             ;returns opclass in d0
106          cmpi.b    #3,d0
107          beq       opc011              ;branch if opclass 3
108          move.l    CMDREG1B(a6),d0
109          bfextu    d0{6:3},d0          ;extract destination register
110          bra.b     sto_fp
111
112opc011:
113          bsr.l     g_dfmtou  ;returns dest format in d0
114*                                       ;ext=00, sgl=01, dbl=10
115          move.l    a0,a1               ;save source addr in a1
116          move.l    EXC_EA(a6),a0       ;get the address
117          tst.l     d0                  ;if dest format is extended
118          beq.w     dest_ext  ;then branch
119          cmpi.l    #1,d0               ;if dest format is single
120          beq.b     short_dest_sgl      ;then branch
121*
122*         fall through to dest_dbl
123*
124
125*
126*         dest_dbl --- write double precision value to user space
127*
128*Input
129*         a0 -> destination address
130*         a1 -> source in extended precision
131*Output
132*         a0 -> destroyed
133*         a1 -> destroyed
134*         d0 -> 0
135*
136*Changes extended precision to double precision.
137* Note: no attempt is made to round the extended value to double.
138*         dbl_sign = ext_sign
139*         dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)
140*         get rid of ext integer bit
141*         dbl_mant = ext_mant{62:12}
142*
143*                   ---------------   ---------------    ---------------
144*  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
145*                   ---------------   ---------------    ---------------
146*                    95           64    63 62           32      31     11         0
147*                                            |                             |
148*                                            |                             |
149*                                            |                             |
150*                                          v                     v
151*                                   ---------------   ---------------
152*  double   ->            |s|exp| mant  |   |  mant       |
153*                                   ---------------   ---------------
154*                                   63     51   32   31            0
155*
156dest_dbl:
157          clr.l     d0                  ;clear d0
158          move.w    LOCAL_EX(a1),d0     ;get exponent
159          sub.w     #$3fff,d0 ;subtract extended precision bias
160          cmp.w     #$4000,d0 ;check if inf
161          beq.b     inf                 ;if so, special case
162          add.w     #$3ff,d0  ;add double precision bias
163          swap      d0                  ;d0 now in upper word
164          lsl.l     #4,d0               ;d0 now in proper place for dbl prec exp
165          tst.b     LOCAL_SGN(a1)
166          beq.b     get_mant  ;if positive, go process mantissa
167          bset.l    #31,d0              ;if negative, put in sign information
168*                                       ; before continuing
169          bra.b     get_mant  ;go process mantissa
170inf:
171          move.l    #$7ff00000,d0       ;load dbl inf exponent
172          clr.l     LOCAL_HI(a1)        ;clear msb
173          tst.b     LOCAL_SGN(a1)
174          beq.b     dbl_inf             ;if positive, go ahead and write it
175          bset.l    #31,d0              ;if negative put in sign information
176dbl_inf:
177          move.l    d0,LOCAL_EX(a1)     ;put the new exp back on the stack
178          bra.b     dbl_wrt
179get_mant:
180          move.l    LOCAL_HI(a1),d1     ;get ms mantissa
181          bfextu    d1{1:20},d1         ;get upper 20 bits of ms
182          or.l      d1,d0               ;put these bits in ms word of double
183          move.l    d0,LOCAL_EX(a1)     ;put the new exp back on the stack
184          move.l    LOCAL_HI(a1),d1     ;get ms mantissa
185          move.l    #21,d0              ;load shift count
186          lsl.l     d0,d1               ;put lower 11 bits in upper bits
187          move.l    d1,LOCAL_HI(a1)     ;build lower lword in memory
188          move.l    LOCAL_LO(a1),d1     ;get ls mantissa
189          bfextu    d1{0:21},d0         ;get ls 21 bits of double
190          or.l      d0,LOCAL_HI(a1)     ;put them in double result
191dbl_wrt:
192          move.l    #$8,d0              ;byte count for double precision number
193          exg       a0,a1               ;a0=supervisor source, a1=user dest
194          bsr.l     mem_write ;move the number to the user's memory
195          rts
196*
197*         dest_sgl --- write single precision value to user space
198*
199*Input
200*         a0 -> destination address
201*         a1 -> source in extended precision
202*
203*Output
204*         a0 -> destroyed
205*         a1 -> destroyed
206*         d0 -> 0
207*
208*Changes extended precision to single precision.
209*         sgl_sign = ext_sign
210*         sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)
211*         get rid of ext integer bit
212*         sgl_mant = ext_mant{62:12}
213*
214*                   ---------------   ---------------    ---------------
215*  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
216*                   ---------------   ---------------    ---------------
217*                    95           64    63 62        40 32      31     12         0
218*                                            |       |
219*                                            |       |
220*                                            |       |
221*                                          v     v
222*                                   ---------------
223*  single   ->            |s|exp| mant  |
224*                                   ---------------
225*                                   31     22     0
226*
227dest_sgl:
228short_dest_sgl:
229          clr.l     d0
230          move.w    LOCAL_EX(a1),d0     ;get exponent
231          sub.w     #$3fff,d0 ;subtract extended precision bias
232          cmp.w     #$4000,d0 ;check if inf
233          beq.b     sinf                ;if so, special case
234          add.w     #$7f,d0             ;add single precision bias
235          swap      d0                  ;put exp in upper word of d0
236          lsl.l     #7,d0               ;shift it into single exp bits
237          tst.b     LOCAL_SGN(a1)
238          beq.b     get_sman  ;if positive, continue
239          bset.l    #31,d0              ;if negative, put in sign first
240          bra.b     get_sman  ;get mantissa
241sinf:
242          move.l    #$7f800000,d0       ;load single inf exp to d0
243          tst.b     LOCAL_SGN(a1)
244          beq.b     sgl_wrt             ;if positive, continue
245          bset.l    #31,d0              ;if negative, put in sign info
246          bra.b     sgl_wrt
247
248get_sman:
249          move.l    LOCAL_HI(a1),d1     ;get ms mantissa
250          bfextu    d1{1:23},d1         ;get upper 23 bits of ms
251          or.l      d1,d0               ;put these bits in ms word of single
252
253sgl_wrt:
254          move.l    d0,L_SCR1(a6)       ;put the new exp back on the stack
255          move.l    #$4,d0              ;byte count for single precision number
256          tst.l     a0                  ;users destination address
257          beq.b     sgl_Dn              ;destination is a data register
258          exg       a0,a1               ;a0=supervisor source, a1=user dest
259          lea.l     L_SCR1(a6),a0       ;point a0 to data
260          bsr.l     mem_write ;move the number to the user's memory
261          rts
262sgl_Dn:
263          bsr.l     get_fline ;returns fline word in d0
264          and.w     #$7,d0              ;isolate register number
265          move.l    d0,d1               ;d1 has size:reg formatted for reg_dest
266          or.l      #$10,d1             ;reg_dest wants size added to reg#
267          bra.l     reg_dest  ;size is X, rts in reg_dest will
268*                                       ;return to caller of dest_sgl
269
270dest_ext:
271          tst.b     LOCAL_SGN(a1)       ;put back sign into exponent word
272          beq.b     dstx_cont
273          bset.b    #sign_bit,LOCAL_EX(a1)
274dstx_cont:
275          clr.b     LOCAL_SGN(a1)       ;clear out the sign byte
276
277          move.l    #$0c,d0             ;byte count for extended number
278          exg       a0,a1               ;a0=supervisor source, a1=user dest
279          bsr.l     mem_write ;move the number to the user's memory
280          rts
281
282          end
283