ARM.Builtins.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. MODULE Builtins;
  2. IMPORT SYSTEM, FPE64;
  3. CONST
  4. B = 127;
  5. C = 800000H;
  6. E = 100H;
  7. S = LONGINT(80000000H); (* used by VFP unit emulation *)
  8. MAXFLOAT32 = LONGINT(7F7FFFFFH);
  9. TYPE
  10. ULONGINT = LONGINT; (* alias to make distinction between signed and unsigned more clear *)
  11. UHUGEINT = HUGEINT;
  12. FLOAT32 = LONGINT; (* alias to make clear that the integer actually contains a IEEE 32 bit float *)
  13. FLOAT64= HUGEINT;
  14. DoubleWord = RECORD
  15. low*: UNSIGNED32; high*: SIGNED32;
  16. END;
  17. PROCEDURE DivS8*(left, right: SHORTINT): SHORTINT;
  18. VAR result, dummy: LONGINT;
  19. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN SHORTINT(result)
  20. END DivS8;
  21. PROCEDURE DivS16*(left, right: INTEGER): INTEGER;
  22. VAR result, dummy: LONGINT;
  23. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN INTEGER(result)
  24. END DivS16;
  25. PROCEDURE DivS32*(left, right: LONGINT): LONGINT;
  26. VAR result, dummy: LONGINT;
  27. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN result
  28. END DivS32;
  29. PROCEDURE DivU32*(left, right: ULONGINT): ULONGINT;
  30. VAR result, dummy: LONGINT;
  31. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, result, dummy); RETURN result
  32. END DivU32;
  33. PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
  34. VAR result, dummy: HUGEINT;
  35. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS64(left, right, result, dummy); RETURN result
  36. END DivS64;
  37. PROCEDURE ModS8*(left, right: SHORTINT): SHORTINT;
  38. VAR result, dummy: LONGINT;
  39. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN SHORTINT(result)
  40. END ModS8;
  41. PROCEDURE ModS16*(left, right: INTEGER): INTEGER;
  42. VAR result, dummy: LONGINT;
  43. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN INTEGER(result)
  44. END ModS16;
  45. PROCEDURE ModS32*(left, right: LONGINT): LONGINT;
  46. VAR result, dummy: LONGINT;
  47. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN result
  48. END ModS32;
  49. PROCEDURE ModU32*(left, right: ULONGINT): ULONGINT;
  50. VAR result, dummy: LONGINT;
  51. BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, dummy, result); RETURN result
  52. END ModU32;
  53. PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
  54. VAR result, dummy: HUGEINT;
  55. BEGIN {UNCOOPERATIVE, UNCHECKED}
  56. DivModS64(left, right, dummy, result); RETURN result
  57. END ModS64;
  58. PROCEDURE RolS64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  59. CODE
  60. LDR R2, [FP, #+8] ; R2 := amount
  61. LDR R3, [FP, #+12] ; R3 := source[Low]
  62. LDR R4, [FP, #+16] ; R4 := source[High]
  63. ; source = R4:R3
  64. AND R2, R2, #3FH ; R2 := R2 MOD 64
  65. CMP R2, #32
  66. ; IF R2 < 32:
  67. MOVLT R0, R3, LSL R2
  68. MOVLT R1, R4, LSL R2
  69. RSBLT R2, R2, #32 ; R2 := 32 - R2
  70. ORRLT R0, R0, R4, LSR R2
  71. ORRLT R1, R1, R3, LSR R2
  72. ; IF R2 >= 32:
  73. SUBGE R2, R2, #32 ; R2 := R2 - 32
  74. MOVGE R0, R4, LSL R2
  75. MOVGE R1, R3, LSL R2
  76. RSBGE R2, R2, #32 ; R2 := 32 - R2
  77. ORRGE R0, R0, R3, LSR R2
  78. ORRGE R1, R1, R4, LSR R2
  79. ; result = R1:R0
  80. END RolS64;
  81. PROCEDURE RolU64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  82. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN RolS64(source, amount)
  83. END RolU64;
  84. PROCEDURE RorS64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  85. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN RolS64(source, 64 - (amount MOD 64))
  86. END RorS64;
  87. PROCEDURE RorU64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  88. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN RolS64(source, 64 - (amount MOD 64))
  89. END RorU64;
  90. (* signed division and modulus
  91. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  92. *)
  93. PROCEDURE DivModS32(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT);
  94. BEGIN {UNCOOPERATIVE, UNCHECKED}
  95. ASSERT(divisor > 0);
  96. IF dividend >= 0 THEN
  97. DivModU32(dividend, divisor, quotient, remainder)
  98. ELSE
  99. dividend := -dividend;
  100. DivModU32(dividend, divisor, quotient, remainder);
  101. quotient := -quotient;
  102. IF remainder # 0 THEN
  103. DEC(quotient);
  104. remainder := divisor - remainder
  105. END
  106. END
  107. END DivModS32;
  108. (*
  109. Fast 32-bit unsigned integer division/modulo (author Alexey Morozov)
  110. *)
  111. PROCEDURE DivModU32*(dividend, divisor: ULONGINT; VAR quotient, remainder: ULONGINT);
  112. CODE
  113. MOV R2, #0 ; quotient will be stored in R2
  114. LDR R0, [FP,#dividend] ; R0 := dividend
  115. LDR R1, [FP,#divisor] ; R1 := divisor
  116. ; check for the case dividend < divisor
  117. CMP R0, R1
  118. BEQ Equal
  119. BLS Exit ; nothing to do than setting quotient to 0 and remainder to dividend (R0)
  120. CLZ R3, R0 ; R3 := clz(dividend)
  121. CLZ R4, R1 ; R4 := clz(divisor)
  122. SUB R3, R4, R3 ; R2 := clz(divisor) - clz(dividend) , R2 >= 0
  123. LSL R1, R1, R3 ; scale divisor: divisor := LSH(divisor,clz(divisor)-clz(dividend))
  124. Loop:
  125. CMP R0, R1
  126. ADC R2, R2, R2
  127. SUBCS R0, R0, R1
  128. LSR R1, R1, #1
  129. SUBS R3, R3, #1
  130. BPL Loop
  131. ; R0 holds the remainder
  132. B Exit
  133. Equal:
  134. MOV R2, #1
  135. MOV R0, #0
  136. Exit:
  137. LDR R1, [FP,#quotient] ; R1 := address of quotient
  138. LDR R3, [FP,#remainder] ; R3 := address of remainder
  139. STR R2, [R1,#0] ; quotient := R2
  140. STR R0, [R3,#0] ; remainder := R0
  141. END DivModU32;
  142. (* signed division and modulus
  143. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  144. *)
  145. PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
  146. BEGIN {UNCOOPERATIVE, UNCHECKED}
  147. ASSERT(divisor > 0);
  148. IF dividend >= 0 THEN
  149. DivModU64(dividend, divisor, quotient, remainder)
  150. ELSE
  151. dividend := -dividend;
  152. DivModU64(dividend, divisor, quotient, remainder);
  153. quotient := -quotient;
  154. IF remainder # 0 THEN
  155. DEC(quotient);
  156. remainder := divisor - remainder
  157. END
  158. END
  159. END DivModS64;
  160. (* Count leading zeros in a binary representation of a given 64-bit integer number *)
  161. PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
  162. CODE
  163. ; high-half
  164. LDR R1, [FP,#x+4]
  165. CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
  166. BEQ LowHalf
  167. CLZ R0, R1
  168. B Exit
  169. ; low-half
  170. LowHalf:
  171. LDR R1, [FP,#x]
  172. CLZ R0, R1
  173. ADD R0, R0, #32 ; add 32 zeros from the high-half
  174. Exit:
  175. END Clz64;
  176. (*
  177. Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
  178. *)
  179. PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
  180. VAR m: LONGINT;
  181. BEGIN {UNCOOPERATIVE, UNCHECKED}
  182. quotient := 0;
  183. IF dividend = 0 THEN remainder := 0; RETURN; END;
  184. IF dividend < divisor THEN remainder := dividend; RETURN; END;
  185. m := Clz64(divisor) - Clz64(dividend);
  186. ASSERT(m >= 0);
  187. divisor := LSH(divisor,m);
  188. WHILE m >= 0 DO
  189. quotient := LSH(quotient,1);
  190. IF dividend >= divisor THEN
  191. INC(quotient);
  192. DEC(dividend,divisor);
  193. END;
  194. divisor := LSH(divisor,-1);
  195. DEC(m);
  196. END;
  197. remainder := dividend;
  198. (*
  199. CODE
  200. ldr r0, [FP,#dividend]
  201. ldr r1, [FP,#dividend+4]
  202. ldr r2, [FP,#divisor]
  203. ldr r3, [FP,#divisor+4]
  204. ldr r5, [FP,#quotient]
  205. ldr r6, [FP,#remainder]
  206. str r0, [r5,#0]
  207. str r1, [r5,#4]
  208. str r2, [r6,#0]
  209. str r3, [r6,#4]
  210. *)
  211. END DivModU64;
  212. (* only called when no FPU64 is available *)
  213. PROCEDURE NegF32*(float: FLOAT32): FLOAT32;
  214. CODE
  215. LDR R0, [FP, #+float] ; R0 := float
  216. EOR R0, R0, #S ; invert only the sign bit
  217. END NegF32;
  218. (* only called when no FPU64 is available *)
  219. PROCEDURE AbsF32*(float: FLOAT32): FLOAT32;
  220. CODE
  221. LDR R0, [FP, #+float] ; R0 := float
  222. BIC R0, R0, #S ; clear the sign bit
  223. END AbsF32;
  224. (* only called when no FPU32 is available *)
  225. PROCEDURE AddF32*(x, y: FLOAT32): FLOAT32;
  226. VAR xe, ye, s: LONGINT;
  227. BEGIN {UNCOOPERATIVE, UNCHECKED}
  228. IF SYSTEM.NULL(x) = TRUE THEN x := y
  229. ELSIF SYSTEM.NULL(y) = FALSE THEN
  230. xe := x DIV C MOD E; (* exponent with bias *)
  231. IF x >= 0 THEN x := (x MOD C + C)*2 ELSE x := -(x MOD C + C)*2 END ;
  232. ye := y DIV C MOD E; (* exponent with bias *)
  233. IF y >= 0 THEN y := (y MOD C + C)*2 ELSE y := -(y MOD C + C)*2 END ;
  234. IF xe < ye THEN
  235. ye := ye - xe; xe := xe + ye; (*denorm x*)
  236. IF ye <= 25 THEN x := ASH(x, -ye) ELSE x := 0 END
  237. ELSIF ye < xe THEN
  238. ye := xe - ye; (*denorm y*)
  239. IF ye <= 25 THEN y := ASH(y, -ye) ELSE y := 0 END
  240. END ;
  241. s := x + y; x := ABS(s);
  242. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, s)*{31});
  243. IF x # 0 THEN
  244. IF x >= 4*C THEN x := (x+2) DIV 4; INC(xe)
  245. ELSIF x >= 2*C THEN x := (x+1) DIV 2
  246. ELSE DEC(xe);
  247. WHILE x < C DO x := 2*x; DEC(xe) END
  248. END ;
  249. IF xe < 0 THEN x := 0 (*underflow*)
  250. ELSIF xe > 0FEH THEN x := MAXFLOAT32 + s; (* overflow *)
  251. ELSE x := xe*C + (x - C) + s;
  252. END;
  253. END
  254. END ;
  255. RETURN x
  256. END AddF32;
  257. (* only called when no FPU64 is available *)
  258. PROCEDURE AddF64*(x,y: FLOAT64): FLOAT64;
  259. VAR z: FLOAT64;
  260. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Add(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  261. END AddF64;
  262. (* only called when no FPU64 is available *)
  263. PROCEDURE MulF64*(x,y: FLOAT64): FLOAT64;
  264. VAR z: FLOAT64;
  265. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Mul(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  266. END MulF64;
  267. (* only called when no FPU64 is available *)
  268. PROCEDURE DivF64*(x,y: FLOAT64): FLOAT64;
  269. VAR z: FLOAT64;
  270. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Div(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  271. END DivF64;
  272. (* only called when no FPU64 is available *)
  273. PROCEDURE SubF64*(x,y: FLOAT64): FLOAT64;
  274. VAR z: FLOAT64;
  275. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Sub(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  276. END SubF64;
  277. (* only called when no FPU64 is available *)
  278. PROCEDURE AbsF64*(x: FLOAT64): FLOAT64;
  279. VAR z: FLOAT64;
  280. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Abs(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  281. END AbsF64;
  282. (* only called when no FPU64 is available *)
  283. PROCEDURE NegF64*(x: FLOAT64): FLOAT64;
  284. VAR z: FLOAT64;
  285. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Neg(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  286. END NegF64;
  287. PROCEDURE ConvS32F64*(x: FLOAT64): LONGINT;
  288. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN FPE64.Fix(SYSTEM.VAL(FPE64.Float64,x))
  289. END ConvS32F64;
  290. PROCEDURE ConvS64F64*(x: FLOAT64): HUGEINT;
  291. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN FPE64.FixInt64(SYSTEM.VAL(FPE64.Float64,x))
  292. END ConvS64F64;
  293. PROCEDURE ConvS64F32*(x: FLOAT32): HUGEINT;
  294. VAR d: FPE64.Float64;
  295. BEGIN {UNCOOPERATIVE, UNCHECKED}
  296. FPE64.Double(x, d);
  297. RETURN FPE64.FixInt64(d)
  298. END ConvS64F32;
  299. (* only called when no FPU32 is available *)
  300. PROCEDURE ConvF32F64*(x: FLOAT64): FLOAT32;
  301. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN FPE64.Single(SYSTEM.VAL(FPE64.Float64,x))
  302. END ConvF32F64;
  303. (* if an FPU32 is available, the result must be made available via FPU register *)
  304. PROCEDURE ConvF32F64F*(x: FLOAT64): REAL;
  305. VAR r: FLOAT32;
  306. BEGIN {UNCOOPERATIVE, UNCHECKED}
  307. r := FPE64.Single(SYSTEM.VAL(FPE64.Float64,x));
  308. RETURN SYSTEM.VAL(REAL, r);
  309. END ConvF32F64F;
  310. (* only called when no FPU64 is available *)
  311. PROCEDURE ConvF64F32*(x: FLOAT32): FLOAT64;
  312. VAR z: FLOAT64;
  313. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Double(x,SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  314. END ConvF64F32;
  315. (* only called when no FPU64 is available *)
  316. PROCEDURE ConvF64S64*(x: HUGEINT): FLOAT64;
  317. VAR flt: FLOAT64;
  318. BEGIN {UNCOOPERATIVE, UNCHECKED}
  319. FPE64.FloatInt64(x, SYSTEM.VAL(FPE64.Float64, flt)); RETURN flt
  320. END ConvF64S64;
  321. (* stub in order to make the runtime itself compile, cf next procedure. This module needs to be compiled with FPU support on *)
  322. PROCEDURE ConvF64U32*(x: UNSIGNED32): FLOAT64;
  323. BEGIN {UNCOOPERATIVE, UNCHECKED}
  324. HALT(100);
  325. END ConvF64U32;
  326. (* if an FPU64 is available, the result must be made available via FPU register *)
  327. PROCEDURE ConvF64S64F*(x: DoubleWord): LONGREAL;
  328. VAR l,h:LONGREAL;
  329. BEGIN {UNCOOPERATIVE, UNCHECKED}
  330. l := x.low;
  331. h := x.high;
  332. RETURN h * 100000000H + l;
  333. END ConvF64S64F;
  334. (* only called when no FPU64 is available *)
  335. PROCEDURE ConvF64S32*(x: LONGINT): FLOAT64;
  336. VAR flt: FLOAT64;
  337. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  338. END ConvF64S32;
  339. (* only called when no FPU64 is available *)
  340. PROCEDURE ConvF64S16*(x: INTEGER): FLOAT64;
  341. VAR flt: FLOAT64;
  342. BEGIN {UNCOOPERATIVE, UNCHECKED} FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  343. END ConvF64S16;
  344. (* only called when no FPU32 is available *)
  345. PROCEDURE ConvF32S16*(x: INTEGER): FLOAT32;
  346. BEGIN {UNCOOPERATIVE, UNCHECKED}
  347. RETURN ConvF32S32(LONGINT(x))
  348. END ConvF32S16;
  349. (* only called when no FPU32 is available *)
  350. PROCEDURE ConvF32S8*(x: SHORTINT): FLOAT32;
  351. BEGIN {UNCOOPERATIVE, UNCHECKED}
  352. RETURN ConvF32S16(INTEGER(x))
  353. END ConvF32S8;
  354. (* only called when no FPU64 is available *)
  355. PROCEDURE ConvF64S8*(x: SHORTINT): FLOAT64;
  356. BEGIN {UNCOOPERATIVE, UNCHECKED}
  357. RETURN ConvF64S16(INTEGER(x))
  358. END ConvF64S8;
  359. (* only called when no FPU32 is available *)
  360. PROCEDURE SubF32*(left, right: FLOAT32): FLOAT32;
  361. BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN AddF32(left, NegF32(right))
  362. END SubF32;
  363. (* only called when no FPU32 is available *)
  364. PROCEDURE MulF32*(x, y: FLOAT32): FLOAT32;
  365. VAR xe, zh, ye, s: LONGINT; (*zh, ye in this order; ye used as zh in MULD*)
  366. BEGIN {UNCOOPERATIVE, UNCHECKED}
  367. IF SYSTEM.NULL(y) = TRUE THEN x := 0
  368. ELSIF SYSTEM.NULL(y) = FALSE THEN
  369. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  370. xe := x DIV C MOD E; (* exponent with bias *)
  371. ye := y DIV C MOD E; (* exponent with bias *)
  372. x := (x MOD C + C) * 20H;
  373. y := (y MOD C + C) * 20H;
  374. xe := xe + ye - B; (* exponent with bias *)
  375. SYSTEM.MULD(ye, x, y); (* note that this implicitly changes zh *)
  376. IF zh >= 4*C THEN
  377. x := (zh+2) DIV 4;
  378. INC(xe);
  379. ELSE
  380. x := (zh+1) DIV 2;
  381. END;
  382. IF xe < 0 THEN (* underflow *)
  383. x := 0;
  384. ELSIF xe > 0FEH THEN (* overflow *)
  385. x := MAXFLOAT32 + s;
  386. ELSE
  387. x := xe*C + (x-C) + s;
  388. END;
  389. END ;
  390. RETURN x
  391. END MulF32;
  392. (* only called when no FPU32 is available *)
  393. PROCEDURE DivF32*(x, y: FLOAT32): FLOAT32;
  394. VAR xe, ye, q, s: LONGINT;
  395. BEGIN {UNCOOPERATIVE, UNCHECKED}
  396. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  397. IF SYSTEM.NULL(y) = TRUE THEN
  398. x := MAXFLOAT32 + s;
  399. ELSIF SYSTEM.NULL(x) = FALSE THEN
  400. xe := x DIV C MOD E; (* exponent with bias *)
  401. ye := y DIV C MOD E; (* exponent with bias *)
  402. x := x MOD C + C;
  403. y := y MOD C + C;
  404. xe := xe - ye + B; (* exponent with bias *)
  405. IF x < y THEN
  406. x := x*2; DEC(xe);
  407. END ;
  408. IF xe < 0 THEN (* underflow *)
  409. x := 0;
  410. ELSIF xe > 0FEH THEN (* overflow *)
  411. x := MAXFLOAT32 + s;
  412. ELSE (* divide *)
  413. q := 0;
  414. WHILE q < LONGINT(1000000H) DO (* 2*C *)
  415. q := 2*q;
  416. IF x >= y THEN
  417. x := x - y;
  418. INC(q);
  419. END;
  420. x := 2*x;
  421. END;
  422. q := (q+1) DIV 2; (*round*)
  423. x := xe*C + (q-C) + s;
  424. END;
  425. END;
  426. RETURN x
  427. END DivF32;
  428. (** converts a float into an integer, ignores the fractional part
  429. - corresponds to ENTIER(x) **)
  430. PROCEDURE ConvS32F32*(x: FLOAT32): LONGINT;
  431. VAR xe, s: LONGINT;
  432. BEGIN {UNCOOPERATIVE, UNCHECKED}
  433. IF SYSTEM.NULL(x) = TRUE THEN
  434. x := 0
  435. ELSE
  436. s := x; xe := x DIV C MOD E - B; x := x MOD C + C;
  437. IF s < 0 THEN x := -x END ;
  438. IF xe < 24 THEN x := ASH(x, xe - 23)
  439. ELSIF xe < 31 THEN x := LSH(x, xe - 23)
  440. ELSIF s < 0 THEN x := LONGINT(80000000H);
  441. ELSE x := LONGINT(7FFFFFFFH);
  442. END;
  443. END ;
  444. RETURN x
  445. END ConvS32F32;
  446. (** converts an integer into a float, ignores the non-integer part
  447. - corresponds to REAL(int)
  448. - note that no rounding occurs
  449. only called when no FPU32 is available
  450. **)
  451. PROCEDURE ConvF32S32*(x: LONGINT): FLOAT32;
  452. VAR xe, s: LONGINT;
  453. BEGIN {UNCOOPERATIVE, UNCHECKED}
  454. IF x = LONGINT(80000000H) THEN (* ABS cannot handle the most negative LONGINT number! *)
  455. x := LONGINT(0CF000000H);
  456. ELSIF x # 0 THEN
  457. s := x;
  458. x := ABS(x); xe := 23;
  459. WHILE x >= 2*C DO
  460. x := x DIV 2; INC(xe);
  461. END;
  462. WHILE x < C DO
  463. x := 2*x; DEC(xe);
  464. END;
  465. x := (xe + B)*C - C + x;
  466. IF s < 0 THEN x := x+S END
  467. END ;
  468. RETURN x
  469. END ConvF32S32;
  470. (* only called when no FPU32 is available *)
  471. PROCEDURE ConvF32S64*(x: HUGEINT): FLOAT32;
  472. BEGIN {UNCOOPERATIVE, UNCHECKED}
  473. RETURN ConvF32F64(ConvF64S64(x))
  474. END ConvF32S64;
  475. (* stub in order to make the runtime itself compile, cf next procedure. This module needs to be compiled with FPU support on *)
  476. PROCEDURE ConvF32U32*(x: UNSIGNED32): FLOAT32;
  477. BEGIN {UNCOOPERATIVE, UNCHECKED}
  478. HALT(100);
  479. END ConvF32U32;
  480. (* if an FPU32 is available, the result must be made available via FPU register *)
  481. PROCEDURE ConvF32S64F*(x: DoubleWord): REAL;
  482. VAR l,h:REAL;
  483. BEGIN {UNCOOPERATIVE, UNCHECKED}
  484. l := x.low;
  485. h := x.high;
  486. RETURN h * 100000000H + l;
  487. END ConvF32S64F;
  488. (* ---- STRING OPERATIONS ---- *)
  489. (** compare two strings
  490. - returns 0 if both strings are lexicographically equal
  491. - returns +1 if 'left' is lexicographically greater than 'right'
  492. - returns -1 if 'left' is lexicographically less than 'right'
  493. **)
  494. PROCEDURE CompareString*(CONST left, right: ARRAY OF CHAR): SHORTINT;
  495. VAR
  496. result: SHORTINT;
  497. i: LONGINT;
  498. leftChar, rightChar: CHAR;
  499. BEGIN {UNCOOPERATIVE, UNCHECKED}
  500. result := 0;
  501. i := 0;
  502. REPEAT
  503. ASSERT (i < LEN (left));
  504. ASSERT (i < LEN (right));
  505. leftChar := left[i]; rightChar := right[i];
  506. IF leftChar < rightChar THEN result := -1
  507. ELSIF leftChar > rightChar THEN result := +1
  508. END;
  509. INC(i)
  510. UNTIL (result # 0) OR (leftChar = 0X) OR (rightChar = 0X);
  511. RETURN result
  512. END CompareString;
  513. (** copy a string from 'source' to 'destination'
  514. - note that PACO semantics are used **)
  515. PROCEDURE CopyString*(VAR destination: ARRAY OF CHAR; CONST source: ARRAY OF CHAR);
  516. VAR
  517. sourceLength, destinationLength: LONGINT;
  518. BEGIN {UNCOOPERATIVE, UNCHECKED}
  519. destinationLength := LEN(destination);
  520. sourceLength := LEN(source);
  521. IF destinationLength < sourceLength THEN sourceLength := destinationLength END;
  522. SYSTEM.MOVE(ADDRESSOF(source[0]), ADDRESSOF(destination[0]), sourceLength)
  523. END CopyString;
  524. END Builtins.