x_operr.S 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. |
  2. | x_operr.sa 3.5 7/1/91
  3. |
  4. | fpsp_operr --- FPSP handler for operand error exception
  5. |
  6. | See 68040 User's Manual pp. 9-44f
  7. |
  8. | Note 1: For trap disabled 040 does the following:
  9. | If the dest is a fp reg, then an extended precision non_signaling
  10. | NAN is stored in the dest reg. If the dest format is b, w, or l and
  11. | the source op is a NAN, then garbage is stored as the result (actually
  12. | the upper 32 bits of the mantissa are sent to the integer unit). If
  13. | the dest format is integer (b, w, l) and the operr is caused by
  14. | integer overflow, or the source op is inf, then the result stored is
  15. | garbage.
  16. | There are three cases in which operr is incorrectly signaled on the
  17. | 040. This occurs for move_out of format b, w, or l for the largest
  18. | negative integer (-2^7 for b, -2^15 for w, -2^31 for l).
  19. |
  20. | On opclass = 011 fmove.(b,w,l) that causes a conversion
  21. | overflow -> OPERR, the exponent in wbte (and fpte) is:
  22. | byte 56 - (62 - exp)
  23. | word 48 - (62 - exp)
  24. | long 32 - (62 - exp)
  25. |
  26. | where exp = (true exp) - 1
  27. |
  28. | So, wbtemp and fptemp will contain the following on erroneously
  29. | signalled operr:
  30. | fpts = 1
  31. | fpte = $4000 (15 bit externally)
  32. | byte fptm = $ffffffff ffffff80
  33. | word fptm = $ffffffff ffff8000
  34. | long fptm = $ffffffff 80000000
  35. |
  36. | Note 2: For trap enabled 040 does the following:
  37. | If the inst is move_out, then same as Note 1.
  38. | If the inst is not move_out, the dest is not modified.
  39. | The exceptional operand is not defined for integer overflow
  40. | during a move_out.
  41. |
  42. | Copyright (C) Motorola, Inc. 1990
  43. | All Rights Reserved
  44. |
  45. | For details on the license for this file, please see the
  46. | file, README, in this same directory.
  47. X_OPERR: |idnt 2,1 | Motorola 040 Floating Point Software Package
  48. |section 8
  49. #include "fpsp.h"
  50. |xref mem_write
  51. |xref real_operr
  52. |xref real_inex
  53. |xref get_fline
  54. |xref fpsp_done
  55. |xref reg_dest
  56. .global fpsp_operr
  57. fpsp_operr:
  58. |
  59. link %a6,#-LOCAL_SIZE
  60. fsave -(%a7)
  61. moveml %d0-%d1/%a0-%a1,USER_DA(%a6)
  62. fmovemx %fp0-%fp3,USER_FP0(%a6)
  63. fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
  64. |
  65. | Check if this is an opclass 3 instruction.
  66. | If so, fall through, else branch to operr_end
  67. |
  68. btstb #TFLAG,T_BYTE(%a6)
  69. beqs operr_end
  70. |
  71. | If the destination size is B,W,or L, the operr must be
  72. | handled here.
  73. |
  74. movel CMDREG1B(%a6),%d0
  75. bfextu %d0{#3:#3},%d0 |0=long, 4=word, 6=byte
  76. cmpib #0,%d0 |determine size; check long
  77. beq operr_long
  78. cmpib #4,%d0 |check word
  79. beq operr_word
  80. cmpib #6,%d0 |check byte
  81. beq operr_byte
  82. |
  83. | The size is not B,W,or L, so the operr is handled by the
  84. | kernel handler. Set the operr bits and clean up, leaving
  85. | only the integer exception frame on the stack, and the
  86. | fpu in the original exceptional state.
  87. |
  88. operr_end:
  89. bsetb #operr_bit,FPSR_EXCEPT(%a6)
  90. bsetb #aiop_bit,FPSR_AEXCEPT(%a6)
  91. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  92. fmovemx USER_FP0(%a6),%fp0-%fp3
  93. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  94. frestore (%a7)+
  95. unlk %a6
  96. bral real_operr
  97. operr_long:
  98. moveql #4,%d1 |write size to d1
  99. moveb STAG(%a6),%d0 |test stag for nan
  100. andib #0xe0,%d0 |clr all but tag
  101. cmpib #0x60,%d0 |check for nan
  102. beq operr_nan
  103. cmpil #0x80000000,FPTEMP_LO(%a6) |test if ls lword is special
  104. bnes chklerr |if not equal, check for incorrect operr
  105. bsr check_upper |check if exp and ms mant are special
  106. tstl %d0
  107. bnes chklerr |if d0 is true, check for incorrect operr
  108. movel #0x80000000,%d0 |store special case result
  109. bsr operr_store
  110. bra not_enabled |clean and exit
  111. |
  112. | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
  113. |
  114. chklerr:
  115. movew FPTEMP_EX(%a6),%d0
  116. andw #0x7FFF,%d0 |ignore sign bit
  117. cmpw #0x3FFE,%d0 |this is the only possible exponent value
  118. bnes chklerr2
  119. fixlong:
  120. movel FPTEMP_LO(%a6),%d0
  121. bsr operr_store
  122. bra not_enabled
  123. chklerr2:
  124. movew FPTEMP_EX(%a6),%d0
  125. andw #0x7FFF,%d0 |ignore sign bit
  126. cmpw #0x4000,%d0
  127. bcc store_max |exponent out of range
  128. movel FPTEMP_LO(%a6),%d0
  129. andl #0x7FFF0000,%d0 |look for all 1's on bits 30-16
  130. cmpl #0x7FFF0000,%d0
  131. beqs fixlong
  132. tstl FPTEMP_LO(%a6)
  133. bpls chklepos
  134. cmpl #0xFFFFFFFF,FPTEMP_HI(%a6)
  135. beqs fixlong
  136. bra store_max
  137. chklepos:
  138. tstl FPTEMP_HI(%a6)
  139. beqs fixlong
  140. bra store_max
  141. operr_word:
  142. moveql #2,%d1 |write size to d1
  143. moveb STAG(%a6),%d0 |test stag for nan
  144. andib #0xe0,%d0 |clr all but tag
  145. cmpib #0x60,%d0 |check for nan
  146. beq operr_nan
  147. cmpil #0xffff8000,FPTEMP_LO(%a6) |test if ls lword is special
  148. bnes chkwerr |if not equal, check for incorrect operr
  149. bsr check_upper |check if exp and ms mant are special
  150. tstl %d0
  151. bnes chkwerr |if d0 is true, check for incorrect operr
  152. movel #0x80000000,%d0 |store special case result
  153. bsr operr_store
  154. bra not_enabled |clean and exit
  155. |
  156. | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
  157. |
  158. chkwerr:
  159. movew FPTEMP_EX(%a6),%d0
  160. andw #0x7FFF,%d0 |ignore sign bit
  161. cmpw #0x3FFE,%d0 |this is the only possible exponent value
  162. bnes store_max
  163. movel FPTEMP_LO(%a6),%d0
  164. swap %d0
  165. bsr operr_store
  166. bra not_enabled
  167. operr_byte:
  168. moveql #1,%d1 |write size to d1
  169. moveb STAG(%a6),%d0 |test stag for nan
  170. andib #0xe0,%d0 |clr all but tag
  171. cmpib #0x60,%d0 |check for nan
  172. beqs operr_nan
  173. cmpil #0xffffff80,FPTEMP_LO(%a6) |test if ls lword is special
  174. bnes chkberr |if not equal, check for incorrect operr
  175. bsr check_upper |check if exp and ms mant are special
  176. tstl %d0
  177. bnes chkberr |if d0 is true, check for incorrect operr
  178. movel #0x80000000,%d0 |store special case result
  179. bsr operr_store
  180. bra not_enabled |clean and exit
  181. |
  182. | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
  183. |
  184. chkberr:
  185. movew FPTEMP_EX(%a6),%d0
  186. andw #0x7FFF,%d0 |ignore sign bit
  187. cmpw #0x3FFE,%d0 |this is the only possible exponent value
  188. bnes store_max
  189. movel FPTEMP_LO(%a6),%d0
  190. asll #8,%d0
  191. swap %d0
  192. bsr operr_store
  193. bra not_enabled
  194. |
  195. | This operr condition is not of the special case. Set operr
  196. | and aiop and write the portion of the nan to memory for the
  197. | given size.
  198. |
  199. operr_nan:
  200. orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop
  201. movel ETEMP_HI(%a6),%d0 |output will be from upper 32 bits
  202. bsr operr_store
  203. bra end_operr
  204. |
  205. | Store_max loads the max pos or negative for the size, sets
  206. | the operr and aiop bits, and clears inex and ainex, incorrectly
  207. | set by the 040.
  208. |
  209. store_max:
  210. orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop
  211. bclrb #inex2_bit,FPSR_EXCEPT(%a6)
  212. bclrb #ainex_bit,FPSR_AEXCEPT(%a6)
  213. fmovel #0,%FPSR
  214. tstw FPTEMP_EX(%a6) |check sign
  215. blts load_neg
  216. movel #0x7fffffff,%d0
  217. bsr operr_store
  218. bra end_operr
  219. load_neg:
  220. movel #0x80000000,%d0
  221. bsr operr_store
  222. bra end_operr
  223. |
  224. | This routine stores the data in d0, for the given size in d1,
  225. | to memory or data register as required. A read of the fline
  226. | is required to determine the destination.
  227. |
  228. operr_store:
  229. movel %d0,L_SCR1(%a6) |move write data to L_SCR1
  230. movel %d1,-(%a7) |save register size
  231. bsrl get_fline |fline returned in d0
  232. movel (%a7)+,%d1
  233. bftst %d0{#26:#3} |if mode is zero, dest is Dn
  234. bnes dest_mem
  235. |
  236. | Destination is Dn. Get register number from d0. Data is on
  237. | the stack at (a7). D1 has size: 1=byte,2=word,4=long/single
  238. |
  239. andil #7,%d0 |isolate register number
  240. cmpil #4,%d1
  241. beqs op_long |the most frequent case
  242. cmpil #2,%d1
  243. bnes op_con
  244. orl #8,%d0
  245. bras op_con
  246. op_long:
  247. orl #0x10,%d0
  248. op_con:
  249. movel %d0,%d1 |format size:reg for reg_dest
  250. bral reg_dest |call to reg_dest returns to caller
  251. | ;of operr_store
  252. |
  253. | Destination is memory. Get <ea> from integer exception frame
  254. | and call mem_write.
  255. |
  256. dest_mem:
  257. leal L_SCR1(%a6),%a0 |put ptr to write data in a0
  258. movel EXC_EA(%a6),%a1 |put user destination address in a1
  259. movel %d1,%d0 |put size in d0
  260. bsrl mem_write
  261. rts
  262. |
  263. | Check the exponent for $c000 and the upper 32 bits of the
  264. | mantissa for $ffffffff. If both are true, return d0 clr
  265. | and store the lower n bits of the least lword of FPTEMP
  266. | to d0 for write out. If not, it is a real operr, and set d0.
  267. |
  268. check_upper:
  269. cmpil #0xffffffff,FPTEMP_HI(%a6) |check if first byte is all 1's
  270. bnes true_operr |if not all 1's then was true operr
  271. cmpiw #0xc000,FPTEMP_EX(%a6) |check if incorrectly signalled
  272. beqs not_true_operr |branch if not true operr
  273. cmpiw #0xbfff,FPTEMP_EX(%a6) |check if incorrectly signalled
  274. beqs not_true_operr |branch if not true operr
  275. true_operr:
  276. movel #1,%d0 |signal real operr
  277. rts
  278. not_true_operr:
  279. clrl %d0 |signal no real operr
  280. rts
  281. |
  282. | End_operr tests for operr enabled. If not, it cleans up the stack
  283. | and does an rte. If enabled, it cleans up the stack and branches
  284. | to the kernel operr handler with only the integer exception
  285. | frame on the stack and the fpu in the original exceptional state
  286. | with correct data written to the destination.
  287. |
  288. end_operr:
  289. btstb #operr_bit,FPCR_ENABLE(%a6)
  290. beqs not_enabled
  291. enabled:
  292. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  293. fmovemx USER_FP0(%a6),%fp0-%fp3
  294. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  295. frestore (%a7)+
  296. unlk %a6
  297. bral real_operr
  298. not_enabled:
  299. |
  300. | It is possible to have either inex2 or inex1 exceptions with the
  301. | operr. If the inex enable bit is set in the FPCR, and either
  302. | inex2 or inex1 occurred, we must clean up and branch to the
  303. | real inex handler.
  304. |
  305. ck_inex:
  306. moveb FPCR_ENABLE(%a6),%d0
  307. andb FPSR_EXCEPT(%a6),%d0
  308. andib #0x3,%d0
  309. beq operr_exit
  310. |
  311. | Inexact enabled and reported, and we must take an inexact exception.
  312. |
  313. take_inex:
  314. moveb #INEX_VEC,EXC_VEC+1(%a6)
  315. movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
  316. orl #sx_mask,E_BYTE(%a6)
  317. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  318. fmovemx USER_FP0(%a6),%fp0-%fp3
  319. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  320. frestore (%a7)+
  321. unlk %a6
  322. bral real_inex
  323. |
  324. | Since operr is only an E1 exception, there is no need to frestore
  325. | any state back to the fpu.
  326. |
  327. operr_exit:
  328. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  329. fmovemx USER_FP0(%a6),%fp0-%fp3
  330. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  331. unlk %a6
  332. bral fpsp_done
  333. |end