gen_except.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. |
  2. | gen_except.sa 3.7 1/16/92
  3. |
  4. | gen_except --- FPSP routine to detect reportable exceptions
  5. |
  6. | This routine compares the exception enable byte of the
  7. | user_fpcr on the stack with the exception status byte
  8. | of the user_fpsr.
  9. |
  10. | Any routine which may report an exceptions must load
  11. | the stack frame in memory with the exceptional operand(s).
  12. |
  13. | Priority for exceptions is:
  14. |
  15. | Highest: bsun
  16. | snan
  17. | operr
  18. | ovfl
  19. | unfl
  20. | dz
  21. | inex2
  22. | Lowest: inex1
  23. |
  24. | Note: The IEEE standard specifies that inex2 is to be
  25. | reported if ovfl occurs and the ovfl enable bit is not
  26. | set but the inex2 enable bit is.
  27. |
  28. |
  29. | Copyright (C) Motorola, Inc. 1990
  30. | All Rights Reserved
  31. |
  32. | For details on the license for this file, please see the
  33. | file, README, in this same directory.
  34. GEN_EXCEPT: |idnt 2,1 | Motorola 040 Floating Point Software Package
  35. |section 8
  36. #include "fpsp.h"
  37. |xref real_trace
  38. |xref fpsp_done
  39. |xref fpsp_fmt_error
  40. exc_tbl:
  41. .long bsun_exc
  42. .long commonE1
  43. .long commonE1
  44. .long ovfl_unfl
  45. .long ovfl_unfl
  46. .long commonE1
  47. .long commonE3
  48. .long commonE3
  49. .long no_match
  50. .global gen_except
  51. gen_except:
  52. cmpib #IDLE_SIZE-4,1(%a7) |test for idle frame
  53. beq do_check |go handle idle frame
  54. cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
  55. beqs unimp_x |go handle unimp frame
  56. cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
  57. beqs unimp_x |go handle unimp frame
  58. cmpib #BUSY_SIZE-4,1(%a7) |if size <> $60, fmt error
  59. bnel fpsp_fmt_error
  60. leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
  61. | ;equates will work
  62. | Fix up the new busy frame with entries from the unimp frame
  63. |
  64. movel ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
  65. movel ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
  66. movel ETEMP_LO(%a6),ETEMP_LO(%a1)
  67. movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
  68. movel CMDREG1B(%a6),%d0 |fix cmd1b to make it
  69. andl #0x03c30000,%d0 |work for cmd3b
  70. bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
  71. lsll #5,%d1
  72. swap %d1
  73. orl %d1,%d0 |put it in the right place
  74. bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
  75. lsll #2,%d1
  76. swap %d1
  77. orl %d1,%d0 |put them in the right place
  78. movel %d0,CMDREG3B(%a1) |in the busy frame
  79. |
  80. | Or in the FPSR from the emulation with the USER_FPSR on the stack.
  81. |
  82. fmovel %FPSR,%d0
  83. orl %d0,USER_FPSR(%a6)
  84. movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
  85. orl #sx_mask,E_BYTE(%a1)
  86. bra do_clean
  87. |
  88. | Frame is an unimp frame possible resulting from an fmove <ea>,fp0
  89. | that caused an exception
  90. |
  91. | a1 is modified to point into the new frame allowing fpsp equates
  92. | to be valid.
  93. |
  94. unimp_x:
  95. cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
  96. bnes test_rev
  97. leal UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
  98. bras unimp_con
  99. test_rev:
  100. cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
  101. bnel fpsp_fmt_error |if not $28 or $30
  102. leal UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
  103. unimp_con:
  104. |
  105. | Fix up the new unimp frame with entries from the old unimp frame
  106. |
  107. movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
  108. |
  109. | Or in the FPSR from the emulation with the USER_FPSR on the stack.
  110. |
  111. fmovel %FPSR,%d0
  112. orl %d0,USER_FPSR(%a6)
  113. bra do_clean
  114. |
  115. | Frame is idle, so check for exceptions reported through
  116. | USER_FPSR and set the unimp frame accordingly.
  117. | A7 must be incremented to the point before the
  118. | idle fsave vector to the unimp vector.
  119. |
  120. do_check:
  121. addl #4,%a7 |point A7 back to unimp frame
  122. |
  123. | Or in the FPSR from the emulation with the USER_FPSR on the stack.
  124. |
  125. fmovel %FPSR,%d0
  126. orl %d0,USER_FPSR(%a6)
  127. |
  128. | On a busy frame, we must clear the nmnexc bits.
  129. |
  130. cmpib #BUSY_SIZE-4,1(%a7) |check frame type
  131. bnes check_fr |if busy, clr nmnexc
  132. clrw NMNEXC(%a6) |clr nmnexc & nmcexc
  133. btstb #5,CMDREG1B(%a6) |test for fmove out
  134. bnes frame_com
  135. movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
  136. orl #sx_mask,E_BYTE(%a6)
  137. bras frame_com
  138. check_fr:
  139. cmpb #UNIMP_40_SIZE-4,1(%a7)
  140. beqs frame_com
  141. clrw NMNEXC(%a6)
  142. frame_com:
  143. moveb FPCR_ENABLE(%a6),%d0 |get fpcr enable byte
  144. andb FPSR_EXCEPT(%a6),%d0 |and in the fpsr exc byte
  145. bfffo %d0{#24:#8},%d1 |test for first set bit
  146. leal exc_tbl,%a0 |load jmp table address
  147. subib #24,%d1 |normalize bit offset to 0-8
  148. movel (%a0,%d1.w*4),%a0 |load routine address based
  149. | ;based on first enabled exc
  150. jmp (%a0) |jump to routine
  151. |
  152. | Bsun is not possible in unimp or unsupp
  153. |
  154. bsun_exc:
  155. bra do_clean
  156. |
  157. | The typical work to be done to the unimp frame to report an
  158. | exception is to set the E1/E3 byte and clr the U flag.
  159. | commonE1 does this for E1 exceptions, which are snan,
  160. | operr, and dz. commonE3 does this for E3 exceptions, which
  161. | are inex2 and inex1, and also clears the E1 exception bit
  162. | left over from the unimp exception.
  163. |
  164. commonE1:
  165. bsetb #E1,E_BYTE(%a6) |set E1 flag
  166. bra commonE |go clean and exit
  167. commonE3:
  168. tstb UFLG_TMP(%a6) |test flag for unsup/unimp state
  169. bnes unsE3
  170. uniE3:
  171. bsetb #E3,E_BYTE(%a6) |set E3 flag
  172. bclrb #E1,E_BYTE(%a6) |clr E1 from unimp
  173. bra commonE
  174. unsE3:
  175. tstb RES_FLG(%a6)
  176. bnes unsE3_0
  177. unsE3_1:
  178. bsetb #E3,E_BYTE(%a6) |set E3 flag
  179. unsE3_0:
  180. bclrb #E1,E_BYTE(%a6) |clr E1 flag
  181. movel CMDREG1B(%a6),%d0
  182. andl #0x03c30000,%d0 |work for cmd3b
  183. bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
  184. lsll #5,%d1
  185. swap %d1
  186. orl %d1,%d0 |put it in the right place
  187. bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
  188. lsll #2,%d1
  189. swap %d1
  190. orl %d1,%d0 |put them in the right place
  191. movel %d0,CMDREG3B(%a6) |in the busy frame
  192. commonE:
  193. bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp
  194. bra do_clean |go clean and exit
  195. |
  196. | No bits in the enable byte match existing exceptions. Check for
  197. | the case of the ovfl exc without the ovfl enabled, but with
  198. | inex2 enabled.
  199. |
  200. no_match:
  201. btstb #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
  202. beqs no_exc |if clear, exit
  203. btstb #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
  204. beqs no_exc |if clear, exit
  205. bras ovfl_unfl |go to unfl_ovfl to determine if
  206. | ;it is an unsupp or unimp exc
  207. | No exceptions are to be reported. If the instruction was
  208. | unimplemented, no FPU restore is necessary. If it was
  209. | unsupported, we must perform the restore.
  210. no_exc:
  211. tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state
  212. beqs uni_no_exc
  213. uns_no_exc:
  214. tstb RES_FLG(%a6) |check if frestore is needed
  215. bne do_clean |if clear, no frestore needed
  216. uni_no_exc:
  217. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  218. fmovemx USER_FP0(%a6),%fp0-%fp3
  219. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  220. unlk %a6
  221. bra finish_up
  222. |
  223. | Unsupported Data Type Handler:
  224. | Ovfl:
  225. | An fmoveout that results in an overflow is reported this way.
  226. | Unfl:
  227. | An fmoveout that results in an underflow is reported this way.
  228. |
  229. | Unimplemented Instruction Handler:
  230. | Ovfl:
  231. | Only scosh, setox, ssinh, stwotox, and scale can set overflow in
  232. | this manner.
  233. | Unfl:
  234. | Stwotox, setox, and scale can set underflow in this manner.
  235. | Any of the other Library Routines such that f(x)=x in which
  236. | x is an extended denorm can report an underflow exception.
  237. | It is the responsibility of the exception-causing exception
  238. | to make sure that WBTEMP is correct.
  239. |
  240. | The exceptional operand is in FP_SCR1.
  241. |
  242. ovfl_unfl:
  243. tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state
  244. beqs ofuf_con
  245. |
  246. | The caller was from an unsupported data type trap. Test if the
  247. | caller set CU_ONLY. If so, the exceptional operand is expected in
  248. | FPTEMP, rather than WBTEMP.
  249. |
  250. tstb CU_ONLY(%a6) |test if inst is cu-only
  251. beq unsE3
  252. | move.w #$fe,CU_SAVEPC(%a6)
  253. clrb CU_SAVEPC(%a6)
  254. bsetb #E1,E_BYTE(%a6) |set E1 exception flag
  255. movew ETEMP_EX(%a6),FPTEMP_EX(%a6)
  256. movel ETEMP_HI(%a6),FPTEMP_HI(%a6)
  257. movel ETEMP_LO(%a6),FPTEMP_LO(%a6)
  258. bsetb #fptemp15_bit,DTAG(%a6) |set fpte15
  259. bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp
  260. bra do_clean |go clean and exit
  261. ofuf_con:
  262. moveb (%a7),VER_TMP(%a6) |save version number
  263. cmpib #BUSY_SIZE-4,1(%a7) |check for busy frame
  264. beqs busy_fr |if unimp, grow to busy
  265. cmpib #VER_40,(%a7) |test for orig unimp frame
  266. bnes try_41 |if not, test for rev frame
  267. moveql #13,%d0 |need to zero 14 lwords
  268. bras ofuf_fin
  269. try_41:
  270. cmpib #VER_41,(%a7) |test for rev unimp frame
  271. bnel fpsp_fmt_error |if neither, exit with error
  272. moveql #11,%d0 |need to zero 12 lwords
  273. ofuf_fin:
  274. clrl (%a7)
  275. loop1:
  276. clrl -(%a7) |clear and dec a7
  277. dbra %d0,loop1
  278. moveb VER_TMP(%a6),(%a7)
  279. moveb #BUSY_SIZE-4,1(%a7) |write busy fmt word.
  280. busy_fr:
  281. movel FP_SCR1(%a6),WBTEMP_EX(%a6) |write
  282. movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |exceptional op to
  283. movel FP_SCR1+8(%a6),WBTEMP_LO(%a6) |wbtemp
  284. bsetb #E3,E_BYTE(%a6) |set E3 flag
  285. bclrb #E1,E_BYTE(%a6) |make sure E1 is clear
  286. bclrb #UFLAG,T_BYTE(%a6) |clr U flag
  287. movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
  288. orl #sx_mask,E_BYTE(%a6)
  289. movel CMDREG1B(%a6),%d0 |fix cmd1b to make it
  290. andl #0x03c30000,%d0 |work for cmd3b
  291. bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
  292. lsll #5,%d1
  293. swap %d1
  294. orl %d1,%d0 |put it in the right place
  295. bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
  296. lsll #2,%d1
  297. swap %d1
  298. orl %d1,%d0 |put them in the right place
  299. movel %d0,CMDREG3B(%a6) |in the busy frame
  300. |
  301. | Check if the frame to be restored is busy or unimp.
  302. |** NOTE *** Bug fix for errata (0d43b #3)
  303. | If the frame is unimp, we must create a busy frame to
  304. | fix the bug with the nmnexc bits in cases in which they
  305. | are set by a previous instruction and not cleared by
  306. | the save. The frame will be unimp only if the final
  307. | instruction in an emulation routine caused the exception
  308. | by doing an fmove <ea>,fp0. The exception operand, in
  309. | internal format, is in fptemp.
  310. |
  311. do_clean:
  312. cmpib #UNIMP_40_SIZE-4,1(%a7)
  313. bnes do_con
  314. moveql #13,%d0 |in orig, need to zero 14 lwords
  315. bras do_build
  316. do_con:
  317. cmpib #UNIMP_41_SIZE-4,1(%a7)
  318. bnes do_restore |frame must be busy
  319. moveql #11,%d0 |in rev, need to zero 12 lwords
  320. do_build:
  321. moveb (%a7),VER_TMP(%a6)
  322. clrl (%a7)
  323. loop2:
  324. clrl -(%a7) |clear and dec a7
  325. dbra %d0,loop2
  326. |
  327. | Use a1 as pointer into new frame. a6 is not correct if an unimp or
  328. | busy frame was created as the result of an exception on the final
  329. | instruction of an emulation routine.
  330. |
  331. | We need to set the nmcexc bits if the exception is E1. Otherwise,
  332. | the exc taken will be inex2.
  333. |
  334. leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 for new frame
  335. moveb VER_TMP(%a6),(%a7) |write busy fmt word
  336. moveb #BUSY_SIZE-4,1(%a7)
  337. movel FP_SCR1(%a6),WBTEMP_EX(%a1) |write
  338. movel FP_SCR1+4(%a6),WBTEMP_HI(%a1) |exceptional op to
  339. movel FP_SCR1+8(%a6),WBTEMP_LO(%a1) |wbtemp
  340. | btst.b #E1,E_BYTE(%a1)
  341. | beq.b do_restore
  342. bfextu USER_FPSR(%a6){#17:#4},%d0 |get snan/operr/ovfl/unfl bits
  343. bfins %d0,NMCEXC(%a1){#4:#4} |and insert them in nmcexc
  344. movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
  345. orl #sx_mask,E_BYTE(%a1)
  346. do_restore:
  347. moveml USER_DA(%a6),%d0-%d1/%a0-%a1
  348. fmovemx USER_FP0(%a6),%fp0-%fp3
  349. fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
  350. frestore (%a7)+
  351. tstb RES_FLG(%a6) |RES_FLG indicates a "continuation" frame
  352. beq cont
  353. bsr bug1384
  354. cont:
  355. unlk %a6
  356. |
  357. | If trace mode enabled, then go to trace handler. This handler
  358. | cannot have any fp instructions. If there are fp inst's and an
  359. | exception has been restored into the machine then the exception
  360. | will occur upon execution of the fp inst. This is not desirable
  361. | in the kernel (supervisor mode). See MC68040 manual Section 9.3.8.
  362. |
  363. finish_up:
  364. btstb #7,(%a7) |test T1 in SR
  365. bnes g_trace
  366. btstb #6,(%a7) |test T0 in SR
  367. bnes g_trace
  368. bral fpsp_done
  369. |
  370. | Change integer stack to look like trace stack
  371. | The address of the instruction that caused the
  372. | exception is already in the integer stack (is
  373. | the same as the saved friar)
  374. |
  375. | If the current frame is already a 6-word stack then all
  376. | that needs to be done is to change the vector# to TRACE.
  377. | If the frame is only a 4-word stack (meaning we got here
  378. | on an Unsupported data type exception), then we need to grow
  379. | the stack an extra 2 words and get the FPIAR from the FPU.
  380. |
  381. g_trace:
  382. bftst EXC_VEC-4(%sp){#0:#4}
  383. bne g_easy
  384. subw #4,%sp | make room
  385. movel 4(%sp),(%sp)
  386. movel 8(%sp),4(%sp)
  387. subw #BUSY_SIZE,%sp
  388. fsave (%sp)
  389. fmovel %fpiar,BUSY_SIZE+EXC_EA-4(%sp)
  390. frestore (%sp)
  391. addw #BUSY_SIZE,%sp
  392. g_easy:
  393. movew #TRACE_VEC,EXC_VEC-4(%a7)
  394. bral real_trace
  395. |
  396. | This is a work-around for hardware bug 1384.
  397. |
  398. bug1384:
  399. link %a5,#0
  400. fsave -(%sp)
  401. cmpib #0x41,(%sp) | check for correct frame
  402. beq frame_41
  403. bgt nofix | if more advanced mask, do nada
  404. frame_40:
  405. tstb 1(%sp) | check to see if idle
  406. bne notidle
  407. idle40:
  408. clrl (%sp) | get rid of old fsave frame
  409. movel %d1,USER_D1(%a6) | save d1
  410. movew #8,%d1 | place unimp frame instead
  411. loop40: clrl -(%sp)
  412. dbra %d1,loop40
  413. movel USER_D1(%a6),%d1 | restore d1
  414. movel #0x40280000,-(%sp)
  415. frestore (%sp)+
  416. unlk %a5
  417. rts
  418. frame_41:
  419. tstb 1(%sp) | check to see if idle
  420. bne notidle
  421. idle41:
  422. clrl (%sp) | get rid of old fsave frame
  423. movel %d1,USER_D1(%a6) | save d1
  424. movew #10,%d1 | place unimp frame instead
  425. loop41: clrl -(%sp)
  426. dbra %d1,loop41
  427. movel USER_D1(%a6),%d1 | restore d1
  428. movel #0x41300000,-(%sp)
  429. frestore (%sp)+
  430. unlk %a5
  431. rts
  432. notidle:
  433. bclrb #etemp15_bit,-40(%a5)
  434. frestore (%sp)+
  435. unlk %a5
  436. rts
  437. nofix:
  438. frestore (%sp)+
  439. unlk %a5
  440. rts
  441. |end