ARM.ARMRuntime.Mod 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. MODULE ARMRuntime;
  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. MAXREAL = 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. PROCEDURE DivS8*(left, right: SHORTINT): SHORTINT;
  15. VAR result, dummy: LONGINT;
  16. BEGIN DivModS32(left, right, result, dummy); RETURN SHORTINT(result)
  17. END DivS8;
  18. PROCEDURE DivS16*(left, right: INTEGER): INTEGER;
  19. VAR result, dummy: LONGINT;
  20. BEGIN DivModS32(left, right, result, dummy); RETURN INTEGER(result)
  21. END DivS16;
  22. PROCEDURE DivS32*(left, right: LONGINT): LONGINT;
  23. VAR result, dummy: LONGINT;
  24. BEGIN DivModS32(left, right, result, dummy); RETURN result
  25. END DivS32;
  26. PROCEDURE DivU32*(left, right: ULONGINT): ULONGINT;
  27. VAR result, dummy: LONGINT;
  28. BEGIN DivModU32(left, right, result, dummy); RETURN result
  29. END DivU32;
  30. PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
  31. VAR result, dummy: HUGEINT;
  32. BEGIN
  33. DivModS64(left, right, result, dummy); RETURN result
  34. END DivS64;
  35. PROCEDURE ModS8*(left, right: SHORTINT): SHORTINT;
  36. VAR result, dummy: LONGINT;
  37. BEGIN DivModS32(left, right, dummy, result); RETURN SHORTINT(result)
  38. END ModS8;
  39. PROCEDURE ModS16*(left, right: INTEGER): INTEGER;
  40. VAR result, dummy: LONGINT;
  41. BEGIN DivModS32(left, right, dummy, result); RETURN INTEGER(result)
  42. END ModS16;
  43. PROCEDURE ModS32*(left, right: LONGINT): LONGINT;
  44. VAR result, dummy: LONGINT;
  45. BEGIN DivModS32(left, right, dummy, result); RETURN result
  46. END ModS32;
  47. PROCEDURE ModU32*(left, right: ULONGINT): ULONGINT;
  48. VAR result, dummy: LONGINT;
  49. BEGIN DivModU32(left, right, dummy, result); RETURN result
  50. END ModU32;
  51. PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
  52. VAR result, dummy: HUGEINT;
  53. BEGIN
  54. DivModS64(left, right, dummy, result); RETURN result
  55. END ModS64;
  56. PROCEDURE RolS64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  57. CODE
  58. LDR R2, [FP, #+8] ; R2 := amount
  59. LDR R3, [FP, #+12] ; R3 := source[Low]
  60. LDR R4, [FP, #+16] ; R4 := source[High]
  61. ; source = R4:R3
  62. AND R2, R2, #3FH ; R2 := R2 MOD 64
  63. CMP R2, #32
  64. ; IF R2 < 32:
  65. MOVLT R0, R3, LSL R2
  66. MOVLT R1, R4, LSL R2
  67. RSBLT R2, R2, #32 ; R2 := 32 - R2
  68. ORRLT R0, R0, R4, LSR R2
  69. ORRLT R1, R1, R3, LSR R2
  70. ; IF R2 >= 32:
  71. SUBGE R2, R2, #32 ; R2 := R2 - 32
  72. MOVGE R0, R4, LSL R2
  73. MOVGE R1, R3, LSL R2
  74. RSBGE R2, R2, #32 ; R2 := 32 - R2
  75. ORRGE R0, R0, R3, LSR R2
  76. ORRGE R1, R1, R4, LSR R2
  77. ; result = R1:R0
  78. END RolS64;
  79. PROCEDURE RolU64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  80. BEGIN RETURN RolS64(source, amount)
  81. END RolU64;
  82. PROCEDURE RorS64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  83. BEGIN RETURN RolS64(source, 64 - (amount MOD 64))
  84. END RorS64;
  85. PROCEDURE RorU64*(source: HUGEINT; amount: ULONGINT): HUGEINT;
  86. BEGIN RETURN RolS64(source, 64 - (amount MOD 64))
  87. END RorU64;
  88. (* signed division and modulus
  89. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  90. *)
  91. PROCEDURE DivModS32(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT);
  92. BEGIN
  93. ASSERT(divisor > 0);
  94. IF dividend >= 0 THEN
  95. DivModU32(dividend, divisor, quotient, remainder)
  96. ELSE
  97. dividend := -dividend;
  98. DivModU32(dividend, divisor, quotient, remainder);
  99. quotient := -quotient;
  100. IF remainder # 0 THEN
  101. DEC(quotient);
  102. remainder := divisor - remainder
  103. END
  104. END
  105. END DivModS32;
  106. (*
  107. Fast 32-bit unsigned integer division/modulo (author Alexey Morozov)
  108. *)
  109. PROCEDURE DivModU32(dividend, divisor: ULONGINT; VAR quotient, remainder: ULONGINT);
  110. CODE
  111. MOV R2, #0 ; quotient will be stored in R2
  112. LDR R0, [FP,#dividend] ; R0 := dividend
  113. LDR R1, [FP,#divisor] ; R1 := divisor
  114. ; check for the case dividend < divisor
  115. CMP R0, R1
  116. BLT Exit ; nothing to do than setting quotient to 0 and remainder to dividend (R0)
  117. CLZ R3, R0 ; R3 := clz(dividend)
  118. CLZ R4, R1 ; R4 := clz(divisor)
  119. SUB R3, R4, R3 ; R2 := clz(divisor) - clz(dividend) , R2 >= 0
  120. LSL R1, R1, R3 ; scale divisor: divisor := LSH(divisor,clz(divisor)-clz(dividend))
  121. Loop:
  122. CMP R0, R1
  123. ADC R2, R2, R2
  124. SUBCS R0, R0, R1
  125. LSR R1, R1, #1
  126. SUBS R3, R3, #1
  127. BPL Loop
  128. ; R0 holds the remainder
  129. Exit:
  130. LDR R1, [FP,#quotient] ; R1 := address of quotient
  131. LDR R3, [FP,#remainder] ; R3 := address of remainder
  132. STR R2, [R1,#0] ; quotient := R1
  133. STR R0, [R3,#0] ; remainder := R0
  134. END DivModU32;
  135. (**
  136. Signed 64-bit multiplication. Adapted version based on the original code
  137. from "Runtime ABI for the ARM Cortex-M0" (https://github.com/bobbl/libaeabi-cortexm0/blob/master/lmul.S)
  138. /* Runtime ABI for the ARM Cortex-M0
  139. * lmul.S: 64 bit multiplication
  140. *
  141. * Copyright (c) 2013 Jörg Mische <bobbl@gmx.de>
  142. *
  143. * Permission to use, copy, modify, and/or distribute this software for any
  144. * purpose with or without fee is hereby granted, provided that the above
  145. * copyright notice and this permission notice appear in all copies.
  146. *
  147. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  148. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  149. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  150. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  151. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  152. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  153. * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  154. */
  155. Multiply r1:r0 and r3:r2 and return the product in r1:r0
  156. Can also be used for unsigned long product
  157. *)
  158. PROCEDURE MulS64*(x, y: HUGEINT): HUGEINT;
  159. CODE
  160. ldr r0, [FP,#x]
  161. ldr r1, [FP,#x+4]
  162. ldr r2, [FP,#y]
  163. ldr r3, [FP,#y+4]
  164. muls r1, r1, r2
  165. muls r3, r3, r0
  166. adds r1, r1, r3
  167. lsrs r3, r0, #16
  168. lsrs r4, r2, #16
  169. muls r3, r3, r4
  170. adds r1, r1, r3
  171. lsrs r3, r0, #16
  172. uxth r0, r0
  173. uxth r2, r2
  174. muls r3, r3, r2
  175. muls r4, r4, r0
  176. muls r0, r0, r2
  177. movs r2, #0
  178. adds r3, r3, r4
  179. adcs r2, r2, r2
  180. lsls r2, r2, #16
  181. adds r1, r1, r2
  182. lsls r2, r3, #16
  183. lsrs r3, r3, #16
  184. adds r0, r0, r2
  185. adcs r1, r1, r3
  186. END MulS64;
  187. (* signed division and modulus
  188. - note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
  189. *)
  190. PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
  191. BEGIN
  192. ASSERT(divisor > 0);
  193. IF dividend >= 0 THEN
  194. DivModU64(dividend, divisor, quotient, remainder)
  195. ELSE
  196. dividend := -dividend;
  197. DivModU64(dividend, divisor, quotient, remainder);
  198. quotient := -quotient;
  199. IF remainder # 0 THEN
  200. DEC(quotient);
  201. remainder := divisor - remainder
  202. END
  203. END
  204. END DivModS64;
  205. (* Count leading zeros in a binary representation of a given 64-bit integer number *)
  206. PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
  207. CODE
  208. ; high-half
  209. LDR R1, [FP,#x+4]
  210. CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
  211. BEQ LowHalf
  212. CLZ R0, R1
  213. B Exit
  214. ; low-half
  215. LowHalf:
  216. LDR R1, [FP,#x]
  217. CLZ R0, R1
  218. ADD R0, R0, #32 ; add 32 zeros from the high-half
  219. Exit:
  220. END Clz64;
  221. (*
  222. Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
  223. *)
  224. PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
  225. VAR m: LONGINT;
  226. BEGIN
  227. quotient := 0;
  228. IF dividend = 0 THEN remainder := 0; RETURN; END;
  229. IF dividend < divisor THEN remainder := dividend; RETURN; END;
  230. m := Clz64(divisor) - Clz64(dividend);
  231. ASSERT(m >= 0);
  232. divisor := LSH(divisor,m);
  233. WHILE m >= 0 DO
  234. quotient := LSH(quotient,1);
  235. IF dividend >= divisor THEN
  236. INC(quotient);
  237. DEC(dividend,divisor);
  238. END;
  239. divisor := LSH(divisor,-1);
  240. DEC(m);
  241. END;
  242. remainder := dividend;
  243. (*
  244. CODE
  245. ldr r0, [FP,#dividend]
  246. ldr r1, [FP,#dividend+4]
  247. ldr r2, [FP,#divisor]
  248. ldr r3, [FP,#divisor+4]
  249. ldr r5, [FP,#quotient]
  250. ldr r6, [FP,#remainder]
  251. str r0, [r5,#0]
  252. str r1, [r5,#4]
  253. str r2, [r6,#0]
  254. str r3, [r6,#4]
  255. *)
  256. END DivModU64;
  257. (* ---- FLOATING POINT EMULATION ----
  258. The following procedures are used in case the target platform does not feature a math coprocessor (aka VFP unit).
  259. Most of the code was taken from the Minos FPU emulation module "FPU.Mos".
  260. Note that parameters and return types are declared as integers, even though they do contain floating point values
  261. according to the IEEE standard.
  262. *)
  263. (** Tests for 0.0 (+0 or -0)
  264. - corresponds to SYSTEM.NULL **)
  265. PROCEDURE IsZeroF32(float: FLOAT32): BOOLEAN;
  266. CODE
  267. LDR R0, [FP, #+float] ; R0 := float
  268. BIC R0, R0, #S ; clear the sign bit
  269. CMP R0, #0 ; IF R0 = 0
  270. MOVEQ R0, #1 ; THEN RETURN TRUE
  271. MOVNE R0, #0 ; ELSE RETURN FALSE
  272. END IsZeroF32;
  273. (** Serves to obtain the sign for products and quotients.
  274. - corresponds to SYSTEM.XOR **)
  275. PROCEDURE SignXorF32(left, right: FLOAT32): FLOAT32;
  276. CODE
  277. LDR R0, [FP, #+left] ; R0 := left
  278. LDR R1, [FP, #+right] ; R1: = right
  279. EOR R0, R0, R1 ; R0 := R0 xor R1
  280. AND R0, R0, #S ; clear all bits except the sign bit
  281. END SignXorF32;
  282. (** multiplies two 32-bit unsigned integer to produce a 64-bit result: [resultLow | resultHigh] = left * right
  283. - corresponds to SYSTEM.MULD (but the low and high part of the result are passed explicitly) **)
  284. PROCEDURE MulD(VAR resultLow, resultHigh: FLOAT32; left, right: FLOAT32);
  285. CODE
  286. LDR R2, [FP, #+resultLow] ; R2 := address of resultLow
  287. LDR R3, [FP, #+resultHigh] ; R3: = address of resultHigh
  288. LDR R4, [FP, #+left] ; R4 := left
  289. LDR R5, [FP, #+right] ; R5: = right
  290. UMULL R0, R1, R4, R5
  291. STR R0, [R4, #+0]
  292. STR R1, [R5, #+0]
  293. END MulD;
  294. PROCEDURE NegF32*(float: FLOAT32): FLOAT32;
  295. CODE
  296. LDR R0, [FP, #+float] ; R0 := float
  297. EOR R0, R0, #S ; invert only the sign bit
  298. END NegF32;
  299. PROCEDURE AbsF32*(float: FLOAT32): FLOAT32;
  300. CODE
  301. LDR R0, [FP, #+float] ; R0 := float
  302. BIC R0, R0, #S ; clear the sign bit
  303. END AbsF32;
  304. PROCEDURE AddF32*(x, y: FLOAT32): FLOAT32;
  305. VAR xe, ye, s: LONGINT;
  306. BEGIN
  307. IF SYSTEM.NULL(x) = TRUE THEN x := y
  308. ELSIF SYSTEM.NULL(y) = FALSE THEN
  309. xe := x DIV C MOD E; (* exponent with bias *)
  310. IF x >= 0 THEN x := (x MOD C + C)*2 ELSE x := -(x MOD C + C)*2 END ;
  311. ye := y DIV C MOD E; (* exponent with bias *)
  312. IF y >= 0 THEN y := (y MOD C + C)*2 ELSE y := -(y MOD C + C)*2 END ;
  313. IF xe < ye THEN
  314. ye := ye - xe; xe := xe + ye; (*denorm x*)
  315. IF ye <= 25 THEN x := ASH(x, -ye) ELSE x := 0 END
  316. ELSIF ye < xe THEN
  317. ye := xe - ye; (*denorm y*)
  318. IF ye <= 25 THEN y := ASH(y, -ye) ELSE y := 0 END
  319. END ;
  320. s := x + y; x := ABS(s);
  321. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, s)*{31});
  322. IF x # 0 THEN
  323. IF x >= 4*C THEN x := (x+2) DIV 4; INC(xe)
  324. ELSIF x >= 2*C THEN x := (x+1) DIV 2
  325. ELSE DEC(xe);
  326. WHILE x < C DO x := 2*x; DEC(xe) END
  327. END ;
  328. IF xe < 0 THEN x := 0 (*underflow*)
  329. ELSIF xe > 0FEH THEN x := MAXREAL + s; (* overflow *)
  330. ELSE x := xe*C + (x - C) + s;
  331. END;
  332. END
  333. END ;
  334. RETURN x
  335. END AddF32;
  336. PROCEDURE AddF64*(x,y: FLOAT64): FLOAT64;
  337. VAR z: FLOAT64;
  338. BEGIN FPE64.Add(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  339. END AddF64;
  340. PROCEDURE MulF64*(x,y: FLOAT64): FLOAT64;
  341. VAR z: FLOAT64;
  342. BEGIN FPE64.Mul(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  343. END MulF64;
  344. PROCEDURE DivF64*(x,y: FLOAT64): FLOAT64;
  345. VAR z: FLOAT64;
  346. BEGIN FPE64.Div(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  347. END DivF64;
  348. PROCEDURE SubF64*(x,y: FLOAT64): FLOAT64;
  349. VAR z: FLOAT64;
  350. BEGIN FPE64.Sub(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  351. END SubF64;
  352. PROCEDURE AbsF64*(x: FLOAT64): FLOAT64;
  353. VAR z: FLOAT64;
  354. BEGIN FPE64.Abs(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  355. END AbsF64;
  356. PROCEDURE NegF64*(x: FLOAT64): FLOAT64;
  357. VAR z: FLOAT64;
  358. BEGIN FPE64.Neg(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  359. END NegF64;
  360. PROCEDURE ConvS32F64*(x: FLOAT64): LONGINT;
  361. BEGIN RETURN FPE64.Fix(SYSTEM.VAL(FPE64.Float64,x))
  362. END ConvS32F64;
  363. PROCEDURE ConvF32F64*(x: FLOAT64): REAL;
  364. BEGIN RETURN FPE64.Single(SYSTEM.VAL(FPE64.Float64,x))
  365. END ConvF32F64;
  366. PROCEDURE ConvF64F32*(x: REAL): FLOAT64;
  367. VAR z: FLOAT64;
  368. BEGIN FPE64.Double(x,SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  369. END ConvF64F32;
  370. PROCEDURE ConvF64S32*(x: LONGINT): FLOAT64;
  371. VAR flt: FLOAT64;
  372. BEGIN FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  373. END ConvF64S32;
  374. PROCEDURE ConvF64S16*(x: INTEGER): FLOAT64;
  375. VAR flt: FLOAT64;
  376. BEGIN FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  377. END ConvF64S16;
  378. PROCEDURE ConvF32S16*(x: INTEGER): REAL;
  379. BEGIN
  380. RETURN ConvF32S32(LONGINT(x))
  381. END ConvF32S16;
  382. PROCEDURE ConvF32S8*(x: SHORTINT): REAL;
  383. BEGIN
  384. RETURN ConvF32S16(INTEGER(x))
  385. END ConvF32S8;
  386. PROCEDURE ConvF64S8*(x: SHORTINT): FLOAT64;
  387. BEGIN
  388. RETURN ConvF64S16(INTEGER(x))
  389. END ConvF64S8;
  390. PROCEDURE SubF32*(left, right: FLOAT32): FLOAT32;
  391. BEGIN RETURN AddF32(left, NegF32(right))
  392. END SubF32;
  393. PROCEDURE MulF32*(x, y: FLOAT32): FLOAT32;
  394. VAR xe, zh, ye, s: LONGINT; (*zh, ye in this order; ye used as zh in MULD*)
  395. BEGIN
  396. IF SYSTEM.NULL(y) = TRUE THEN x := 0
  397. ELSIF SYSTEM.NULL(y) = FALSE THEN
  398. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  399. xe := x DIV C MOD E; (* exponent with bias *)
  400. ye := y DIV C MOD E; (* exponent with bias *)
  401. x := (x MOD C + C) * 20H;
  402. y := (y MOD C + C) * 20H;
  403. xe := xe + ye - B; (* exponent with bias *)
  404. SYSTEM.MULD(ye, x, y); (* note that this implicitly changes zh *)
  405. IF zh >= 4*C THEN
  406. x := (zh+2) DIV 4;
  407. INC(xe);
  408. ELSE
  409. x := (zh+1) DIV 2;
  410. END;
  411. IF xe < 0 THEN (* underflow *)
  412. x := 0;
  413. ELSIF xe > 0FEH THEN (* overflow *)
  414. x := MAXREAL + s;
  415. ELSE
  416. x := xe*C + (x-C) + s;
  417. END;
  418. END ;
  419. RETURN x
  420. END MulF32;
  421. PROCEDURE DivF32*(x, y: FLOAT32): FLOAT32;
  422. VAR xe, ye, q, s: LONGINT;
  423. BEGIN
  424. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  425. IF SYSTEM.NULL(y) = TRUE THEN
  426. x := MAXREAL + s;
  427. ELSIF SYSTEM.NULL(x) = FALSE THEN
  428. xe := x DIV C MOD E; (* exponent with bias *)
  429. ye := y DIV C MOD E; (* exponent with bias *)
  430. x := x MOD C + C;
  431. y := y MOD C + C;
  432. xe := xe - ye + B; (* exponent with bias *)
  433. IF x < y THEN
  434. x := x*2; DEC(xe);
  435. END ;
  436. IF xe < 0 THEN (* underflow *)
  437. x := 0;
  438. ELSIF xe > 0FEH THEN (* overflow *)
  439. x := MAXREAL + s;
  440. ELSE (* divide *)
  441. q := 0;
  442. WHILE q < LONGINT(1000000H) DO (* 2*C *)
  443. q := 2*q;
  444. IF x >= y THEN
  445. x := x - y;
  446. INC(q);
  447. END;
  448. x := 2*x;
  449. END;
  450. q := (q+1) DIV 2; (*round*)
  451. x := xe*C + (q-C) + s;
  452. END;
  453. END;
  454. RETURN x
  455. END DivF32;
  456. (** converts a float into an integer, ignores the fractional part
  457. - corresponds to ENTIER(x) **)
  458. PROCEDURE ConvS32F32*(x: FLOAT32): LONGINT;
  459. VAR xe, s: LONGINT;
  460. BEGIN
  461. IF SYSTEM.NULL(x) = TRUE THEN
  462. x := 0
  463. ELSE
  464. s := x; xe := x DIV C MOD E - B; x := x MOD C + C;
  465. IF s < 0 THEN x := -x END ;
  466. IF xe < 24 THEN x := ASH(x, xe - 23)
  467. ELSIF xe < 31 THEN x := LSH(x, xe - 23)
  468. ELSIF s < 0 THEN x := LONGINT(80000000H);
  469. ELSE x := LONGINT(7FFFFFFFH);
  470. END;
  471. END ;
  472. RETURN x
  473. END ConvS32F32;
  474. (** converts an integer into a float, ignores the non-integer part
  475. - corresponds to REAL(int)
  476. - note that no rounding occurs
  477. **)
  478. PROCEDURE ConvF32S32*(x: LONGINT): FLOAT32;
  479. VAR xe, s: LONGINT;
  480. BEGIN
  481. IF x = LONGINT(80000000H) THEN (* ABS cannot handle the most negative LONGINT number! *)
  482. x := LONGINT(0CF000000H);
  483. ELSIF x # 0 THEN
  484. s := x;
  485. x := ABS(x); xe := 23;
  486. WHILE x >= 2*C DO
  487. x := x DIV 2; INC(xe);
  488. END;
  489. WHILE x < C DO
  490. x := 2*x; DEC(xe);
  491. END;
  492. x := (xe + B)*C - C + x;
  493. IF s < 0 THEN x := x+S END
  494. END ;
  495. RETURN x
  496. END ConvF32S32;
  497. (** whether x < y
  498. - note that this operation should rather be done by direct code emission of the backend
  499. **)
  500. PROCEDURE LessThanF32(x, y: FLOAT32): BOOLEAN;
  501. BEGIN
  502. HALT(200)
  503. END LessThanF32;
  504. (* ---- STRING OPERATIONS ---- *)
  505. (** compare two strings
  506. - returns 0 if both strings are lexicographically equal
  507. - returns +1 if 'left' is lexicographically greater than 'right'
  508. - returns -1 if 'left' is lexicographically less than 'right'
  509. **)
  510. PROCEDURE CompareString*(CONST left, right: ARRAY OF CHAR): SHORTINT;
  511. VAR
  512. result: SHORTINT;
  513. i: LONGINT;
  514. leftChar, rightChar: CHAR;
  515. BEGIN
  516. result := 0;
  517. i := 0;
  518. REPEAT
  519. leftChar := left[i]; rightChar := right[i];
  520. IF leftChar < rightChar THEN result := -1
  521. ELSIF leftChar > rightChar THEN result := +1
  522. END;
  523. INC(i)
  524. UNTIL (result # 0) OR (leftChar = 0X) OR (rightChar = 0X);
  525. RETURN result
  526. END CompareString;
  527. (** copy a string from 'source' to 'destination'
  528. - note that PACO semantics are used **)
  529. PROCEDURE CopyString*(VAR destination: ARRAY OF CHAR; CONST source: ARRAY OF CHAR);
  530. VAR
  531. sourceLength, destinationLength: LONGINT;
  532. BEGIN
  533. destinationLength := LEN(destination);
  534. sourceLength := LEN(source);
  535. IF destinationLength < sourceLength THEN sourceLength := destinationLength END;
  536. SYSTEM.MOVE(ADDRESSOF(source[0]), ADDRESSOF(destination[0]), sourceLength)
  537. END CopyString;
  538. END ARMRuntime.