fpbit-sf.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. ; SF format is:
  2. ;
  3. ; [sign] 1.[23bits] E[8bits(n-127)]
  4. ;
  5. ; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
  6. ;
  7. ; [A+0] mmmmmmmm
  8. ; [A+1] mmmmmmmm
  9. ; [A+2] Emmmmmmm
  10. ; [A+3] SEEEEEEE
  11. ;
  12. ; Special values (xxx != 0):
  13. ;
  14. ; s1111111 10000000 00000000 00000000 infinity
  15. ; s1111111 1xxxxxxx xxxxxxxx xxxxxxxx NaN
  16. ; s0000000 00000000 00000000 00000000 zero
  17. ; s0000000 0xxxxxxx xxxxxxxx xxxxxxxx denormals
  18. ;
  19. ; Note that CMPtype is "signed char" for rl78
  20. ;
  21. #include "vregs.h"
  22. #define Z PSW.6
  23. START_FUNC ___negsf2
  24. ;; Negate the floating point value.
  25. ;; Input at [SP+4]..[SP+7].
  26. ;; Output to R8..R11.
  27. movw ax, [SP+4]
  28. movw r8, ax
  29. movw ax, [SP+6]
  30. xor a, #0x80
  31. movw r10, ax
  32. ret
  33. END_FUNC ___negsf2
  34. ;; ------------------internal functions used by later code --------------
  35. START_FUNC __int_isnan
  36. ;; [HL] points to value, returns Z if it's a NaN
  37. mov a, [hl+2]
  38. and a, #0x80
  39. mov x, a
  40. mov a, [hl+3]
  41. and a, #0x7f
  42. cmpw ax, #0x7f80
  43. skz
  44. ret ; return NZ if not NaN
  45. mov a, [hl+2]
  46. and a, #0x7f
  47. or a, [hl+1]
  48. or a, [hl]
  49. bnz $1f
  50. clr1 Z ; Z, normal
  51. ret
  52. 1:
  53. set1 Z ; nan
  54. ret
  55. END_FUNC __int_isnan
  56. START_FUNC __int_eithernan
  57. ;; call from toplevel functions, returns Z if either number is a NaN,
  58. ;; or NZ if both are OK.
  59. movw ax, sp
  60. addw ax, #8
  61. movw hl, ax
  62. call $!__int_isnan
  63. bz $1f
  64. movw ax, sp
  65. addw ax, #12
  66. movw hl, ax
  67. call $!__int_isnan
  68. 1:
  69. ret
  70. END_FUNC __int_eithernan
  71. START_FUNC __int_iszero
  72. ;; [HL] points to value, returns Z if it's zero
  73. mov a, [hl+3]
  74. and a, #0x7f
  75. or a, [hl+2]
  76. or a, [hl+1]
  77. or a, [hl]
  78. ret
  79. END_FUNC __int_iszero
  80. START_FUNC __int_cmpsf
  81. ;; This is always called from some other function here,
  82. ;; so the stack offsets are adjusted accordingly.
  83. ;; X [SP+8] <=> Y [SP+12] : <a> <=> 0
  84. movw ax, sp
  85. addw ax, #8
  86. movw hl, ax
  87. call $!__int_iszero
  88. bnz $1f
  89. movw ax, sp
  90. addw ax, #12
  91. movw hl, ax
  92. call $!__int_iszero
  93. bnz $2f
  94. ;; At this point, both args are zero.
  95. mov a, #0
  96. ret
  97. 2:
  98. movw ax, sp
  99. addw ax, #8
  100. movw hl, ax
  101. 1:
  102. ;; At least one arg is non-zero so we can just compare magnitudes.
  103. ;; Args are [HL] and [HL+4].
  104. mov a, [HL+3]
  105. xor a, [HL+7]
  106. mov1 cy, a.7
  107. bnc $1f
  108. mov a, [HL+3]
  109. sar a, 7
  110. or a, #1
  111. ret
  112. 1: ;; Signs the same, compare magnitude. It's safe to lump
  113. ;; the sign bits, exponent, and mantissa together here, since they're
  114. ;; stored in the right sequence.
  115. movw ax, [HL+2]
  116. cmpw ax, [HL+6]
  117. bc $ybig_cmpsf ; branch if X < Y
  118. bnz $xbig_cmpsf ; branch if X > Y
  119. movw ax, [HL]
  120. cmpw ax, [HL+4]
  121. bc $ybig_cmpsf ; branch if X < Y
  122. bnz $xbig_cmpsf ; branch if X > Y
  123. mov a, #0
  124. ret
  125. xbig_cmpsf: ; |X| > |Y| so return A = 1 if pos, 0xff if neg
  126. mov a, [HL+3]
  127. sar a, 7
  128. or a, #1
  129. ret
  130. ybig_cmpsf: ; |X| < |Y| so return A = 0xff if pos, 1 if neg
  131. mov a, [HL+3]
  132. xor a, #0x80
  133. sar a, 7
  134. or a, #1
  135. ret
  136. END_FUNC __int_cmpsf
  137. ;; ----------------------------------------------------------
  138. START_FUNC ___cmpsf2
  139. ;; This functions calculates "A <=> B". That is, if A is less than B
  140. ;; they return -1, if A is greater than B, they return 1, and if A
  141. ;; and B are equal they return 0. If either argument is NaN the
  142. ;; behaviour is undefined.
  143. ;; Input at [SP+4]..[SP+7].
  144. ;; Output to R8..R9.
  145. call $!__int_eithernan
  146. bnz $1f
  147. movw r8, #1
  148. ret
  149. 1:
  150. call $!__int_cmpsf
  151. mov r8, a
  152. sar a, 7
  153. mov r9, a
  154. ret
  155. END_FUNC ___cmpsf2
  156. ;; ----------------------------------------------------------
  157. ;; These functions are all basically the same as ___cmpsf2
  158. ;; except that they define how they handle NaNs.
  159. START_FUNC ___eqsf2
  160. ;; Returns zero iff neither argument is NaN
  161. ;; and both arguments are equal.
  162. START_ANOTHER_FUNC ___nesf2
  163. ;; Returns non-zero iff either argument is NaN or the arguments are
  164. ;; unequal. Effectively __nesf2 is the same as __eqsf2
  165. START_ANOTHER_FUNC ___lesf2
  166. ;; Returns a value less than or equal to zero if neither
  167. ;; argument is NaN, and the first is less than or equal to the second.
  168. START_ANOTHER_FUNC ___ltsf2
  169. ;; Returns a value less than zero if neither argument is
  170. ;; NaN, and the first is strictly less than the second.
  171. ;; Input at [SP+4]..[SP+7].
  172. ;; Output to R8.
  173. mov r8, #1
  174. ;;; Fall through
  175. START_ANOTHER_FUNC __int_cmp_common
  176. call $!__int_eithernan
  177. sknz
  178. ;; return value (pre-filled-in below) for "either is nan"
  179. ret
  180. call $!__int_cmpsf
  181. mov r8, a
  182. ret
  183. END_ANOTHER_FUNC __int_cmp_common
  184. END_ANOTHER_FUNC ___ltsf2
  185. END_ANOTHER_FUNC ___lesf2
  186. END_ANOTHER_FUNC ___nesf2
  187. END_FUNC ___eqsf2
  188. START_FUNC ___gesf2
  189. ;; Returns a value greater than or equal to zero if neither argument
  190. ;; is a NaN and the first is greater than or equal to the second.
  191. START_ANOTHER_FUNC ___gtsf2
  192. ;; Returns a value greater than zero if neither argument
  193. ;; is NaN, and the first is strictly greater than the second.
  194. mov r8, #0xffff
  195. br $__int_cmp_common
  196. END_ANOTHER_FUNC ___gtsf2
  197. END_FUNC ___gesf2
  198. ;; ----------------------------------------------------------
  199. START_FUNC ___unordsf2
  200. ;; Returns a nonzero value if either argument is NaN, otherwise 0.
  201. call $!__int_eithernan
  202. movw r8, #0
  203. sknz ; this is from the call, not the movw
  204. movw r8, #1
  205. ret
  206. END_FUNC ___unordsf2
  207. ;; ----------------------------------------------------------
  208. START_FUNC ___fixsfsi
  209. ;; Converts its floating point argument into a signed long,
  210. ;; rounding toward zero.
  211. ;; The behaviour with NaNs and Infinities is not well defined.
  212. ;; We choose to return 0 for NaNs, -INTMAX for -inf and INTMAX for +inf.
  213. ;; This matches the behaviour of the C function in libgcc2.c.
  214. ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb).
  215. ;; Special case handling for infinities as __fixunssfsi
  216. ;; will not give us the values that we want.
  217. movw ax, sp
  218. addw ax, #4
  219. movw hl, ax
  220. call !!__int_isinf
  221. bnz $1f
  222. mov a, [SP+7]
  223. bt a.7, $2f
  224. ;; +inf
  225. movw r8, #-1
  226. movw r10, #0x7fff
  227. ret
  228. ;; -inf
  229. 2: mov r8, #0
  230. mov r10, #0x8000
  231. ret
  232. ;; Load the value into r10:r11:X:A
  233. 1: movw ax, [SP+4]
  234. movw r10, ax
  235. movw ax, [SP+6]
  236. ;; If the value is positive we can just use __fixunssfsi
  237. bf a.7, $__int_fixunssfsi
  238. ;; Otherwise we negate the value, call __fixunssfsi and
  239. ;; then negate its result.
  240. clr1 a.7
  241. call $!__int_fixunssfsi
  242. movw ax, #0
  243. subw ax, r8
  244. movw r8, ax
  245. movw ax, #0
  246. sknc
  247. decw ax
  248. subw ax, r10
  249. movw r10, ax
  250. ;; Check for a positive result (which should only happen when
  251. ;; __fixunssfsi returns UINTMAX or 0). In such cases just return 0.
  252. mov a, r11
  253. bt a.7, $1f
  254. movw r10,#0x0
  255. movw r8, #0x0
  256. 1: ret
  257. END_FUNC ___fixsfsi
  258. START_FUNC ___fixunssfsi
  259. ;; Converts its floating point argument into an unsigned long
  260. ;; rounding towards zero. Negative arguments all become zero.
  261. ;; We choose to return 0 for NaNs and -inf, but UINTMAX for +inf.
  262. ;; This matches the behaviour of the C function in libgcc2.c.
  263. ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb)
  264. ;; Get the input value.
  265. movw ax, [SP+4]
  266. movw r10, ax
  267. movw ax, [SP+6]
  268. ;; Fall through into the internal function.
  269. .global __int_fixunssfsi
  270. __int_fixunssfsi:
  271. ;; Input in (lsb) r10.r11.x.a (msb).
  272. ;; Test for a negative input. We shift the other bits at the
  273. ;; same time so that A ends up holding the whole exponent:
  274. ;;
  275. ;; before:
  276. ;; SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
  277. ;; A X R11 R10
  278. ;;
  279. ;; after:
  280. ;; EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
  281. ;; A X R11 R10
  282. shlw ax, 1
  283. bnc $1f
  284. ;; Return zero.
  285. 2: movw r8, #0
  286. movw r10, #0
  287. ret
  288. ;; An exponent of -1 is either a NaN or infinity.
  289. 1: cmp a, #-1
  290. bnz $3f
  291. ;; For NaN we return 0. For infinity we return UINTMAX.
  292. mov a, x
  293. or a, r10
  294. or a, r11
  295. cmp0 a
  296. bnz $2b
  297. 6: movw r8, #-1 ; -1 => UINT_MAX
  298. movw r10, #-1
  299. ret
  300. ;; If the exponent is negative the value is < 1 and so the
  301. ;; converted value is 0. Note we must allow for the bias
  302. ;; applied to the exponent. Thus a value of 127 in the
  303. ;; EEEEEEEE bits actually represents an exponent of 0, whilst
  304. ;; a value less than 127 actually represents a negative exponent.
  305. ;; Also if the EEEEEEEE bits are all zero then this represents
  306. ;; either a denormal value or 0.0. Either way for these values
  307. ;; we return 0.
  308. 3: sub a, #127
  309. bc $2b
  310. ;; A now holds the bias adjusted exponent, which is known to be >= 0.
  311. ;; If the exponent is > 31 then the conversion will overflow.
  312. cmp a, #32
  313. bnc $6b
  314. 4:
  315. ;; Save the exponent in H. We increment it by one because we want
  316. ;; to be sure that the loop below will always execute at least once.
  317. inc a
  318. mov h, a
  319. ;; Get the top 24 bits of the mantissa into A:X:R10
  320. ;; Include the implicit 1-bit that is inherent in the IEEE fp format.
  321. ;;
  322. ;; before:
  323. ;; EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
  324. ;; H X R11 R10
  325. ;; after:
  326. ;; EEEEEEEE 1MMMMMMM MMMMMMMM MMMMMMMM
  327. ;; H A X R10
  328. mov a, r11
  329. xch a, x
  330. shr a, 1
  331. set1 a.7
  332. ;; Clear B:C:R12:R13
  333. movw bc, #0
  334. movw r12, #0
  335. ;; Shift bits from the mantissa (A:X:R10) into (B:C:R12:R13),
  336. ;; decrementing the exponent as we go.
  337. ;; before:
  338. ;; MMMMMMMM MMMMMMMM MMMMMMMM xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  339. ;; A X R10 B C R12 R13
  340. ;; first iter:
  341. ;; MMMMMMMM MMMMMMMM MMMMMMM0 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxM
  342. ;; A X R10 B C R12 R13
  343. ;; second iter:
  344. ;; MMMMMMMM MMMMMMMM MMMMMM00 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxMM
  345. ;; A X R10 B C R12 R13
  346. ;; etc.
  347. 5:
  348. xch a, r10
  349. shl a, 1
  350. xch a, r10
  351. rolwc ax, 1
  352. xch a, r13
  353. rolc a, 1
  354. xch a, r13
  355. xch a, r12
  356. rolc a, 1
  357. xch a, r12
  358. rolwc bc, 1
  359. dec h
  360. bnz $5b
  361. ;; Result is currently in (lsb) r13.r12. c. b. (msb),
  362. ;; Move it into (lsb) r8. r9. r10. r11 (msb).
  363. mov a, r13
  364. mov r8, a
  365. mov a, r12
  366. mov r9, a
  367. mov a, c
  368. mov r10, a
  369. mov a, b
  370. mov r11, a
  371. ret
  372. END_FUNC ___fixunssfsi
  373. ;; ------------------------------------------------------------------------
  374. START_FUNC ___floatsisf
  375. ;; Converts its signed long argument into a floating point.
  376. ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
  377. ;; Get the argument.
  378. movw ax, [SP+4]
  379. movw bc, ax
  380. movw ax, [SP+6]
  381. ;; Test the sign bit. If the value is positive then drop into
  382. ;; the unsigned conversion routine.
  383. bf a.7, $2f
  384. ;; If negative convert to positive ...
  385. movw hl, ax
  386. movw ax, #0
  387. subw ax, bc
  388. movw bc, ax
  389. movw ax, #0
  390. sknc
  391. decw ax
  392. subw ax, hl
  393. ;; If the result is negative then the input was 0x80000000 and
  394. ;; we want to return -0.0, which will not happen if we call
  395. ;; __int_floatunsisf.
  396. bt a.7, $1f
  397. ;; Call the unsigned conversion routine.
  398. call $!__int_floatunsisf
  399. ;; Negate the result.
  400. set1 r11.7
  401. ;; Done.
  402. ret
  403. 1: ;; Return -0.0 aka 0xcf000000
  404. clrb a
  405. mov r8, a
  406. mov r9, a
  407. mov r10, a
  408. mov a, #0xcf
  409. mov r11, a
  410. ret
  411. START_ANOTHER_FUNC ___floatunsisf
  412. ;; Converts its unsigned long argument into a floating point.
  413. ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
  414. ;; Get the argument.
  415. movw ax, [SP+4]
  416. movw bc, ax
  417. movw ax, [SP+6]
  418. 2: ;; Internal entry point from __floatsisf
  419. ;; Input in AX (high) and BC (low)
  420. .global __int_floatunsisf
  421. __int_floatunsisf:
  422. ;; Special case handling for zero.
  423. cmpw ax, #0
  424. bnz $1f
  425. movw ax, bc
  426. cmpw ax, #0
  427. movw ax, #0
  428. bnz $1f
  429. ;; Return 0.0
  430. movw r8, ax
  431. movw r10, ax
  432. ret
  433. 1: ;; Pre-load the loop count/exponent.
  434. ;; Exponents are biased by 0x80 and we start the loop knowing that
  435. ;; we are going to skip the highest set bit. Hence the highest value
  436. ;; that we can get for the exponent is 0x1e (bits from input) + 0x80 = 0x9e.
  437. mov h, #0x9e
  438. ;; Move bits off the top of AX:BC until we hit a 1 bit.
  439. ;; Decrement the count of remaining bits as we go.
  440. 2: shlw bc, 1
  441. rolwc ax, 1
  442. bc $3f
  443. dec h
  444. br $2b
  445. ;; Ignore the first one bit - it is implicit in the IEEE format.
  446. ;; The count of remaining bits is the exponent.
  447. ;; Assemble the final floating point value. We have...
  448. ;; before:
  449. ;; EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM xxxxxxxx
  450. ;; H A X B C
  451. ;; after:
  452. ;; 0EEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
  453. ;; R11 R10 R9 R8
  454. 3: shrw ax, 1
  455. mov r10, a
  456. mov a, x
  457. mov r9, a
  458. mov a, b
  459. rorc a, 1
  460. ;; If the bottom bit of B was set before we shifted it out then we
  461. ;; need to round the result up. Unless none of the bits in C are set.
  462. ;; In this case we are exactly half-way between two values, and we
  463. ;; round towards an even value. We round up by increasing the
  464. ;; mantissa by 1. If this results in a zero mantissa we have to
  465. ;; increment the exponent. We round down by ignoring the dropped bits.
  466. bnc $4f
  467. cmp0 c
  468. sknz
  469. bf a.0, $4f
  470. 5: ;; Round the mantissa up by 1.
  471. add a, #1
  472. addc r9, #0
  473. addc r10, #0
  474. bf r10.7, $4f
  475. inc h
  476. clr1 r10.7
  477. 4: mov r8, a
  478. mov a, h
  479. shr a, 1
  480. mov r11, a
  481. sknc
  482. set1 r10.7
  483. ret
  484. END_ANOTHER_FUNC ___floatunsisf
  485. END_FUNC ___floatsisf