ARM.ARMRuntime.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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. PROCEDURE NegF32*(float: FLOAT32): FLOAT32;
  258. CODE
  259. LDR R0, [FP, #+float] ; R0 := float
  260. EOR R0, R0, #S ; invert only the sign bit
  261. END NegF32;
  262. PROCEDURE AbsF32*(float: FLOAT32): FLOAT32;
  263. CODE
  264. LDR R0, [FP, #+float] ; R0 := float
  265. BIC R0, R0, #S ; clear the sign bit
  266. END AbsF32;
  267. PROCEDURE AddF32*(x, y: FLOAT32): FLOAT32;
  268. VAR xe, ye, s: LONGINT;
  269. BEGIN
  270. IF SYSTEM.NULL(x) = TRUE THEN x := y
  271. ELSIF SYSTEM.NULL(y) = FALSE THEN
  272. xe := x DIV C MOD E; (* exponent with bias *)
  273. IF x >= 0 THEN x := (x MOD C + C)*2 ELSE x := -(x MOD C + C)*2 END ;
  274. ye := y DIV C MOD E; (* exponent with bias *)
  275. IF y >= 0 THEN y := (y MOD C + C)*2 ELSE y := -(y MOD C + C)*2 END ;
  276. IF xe < ye THEN
  277. ye := ye - xe; xe := xe + ye; (*denorm x*)
  278. IF ye <= 25 THEN x := ASH(x, -ye) ELSE x := 0 END
  279. ELSIF ye < xe THEN
  280. ye := xe - ye; (*denorm y*)
  281. IF ye <= 25 THEN y := ASH(y, -ye) ELSE y := 0 END
  282. END ;
  283. s := x + y; x := ABS(s);
  284. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, s)*{31});
  285. IF x # 0 THEN
  286. IF x >= 4*C THEN x := (x+2) DIV 4; INC(xe)
  287. ELSIF x >= 2*C THEN x := (x+1) DIV 2
  288. ELSE DEC(xe);
  289. WHILE x < C DO x := 2*x; DEC(xe) END
  290. END ;
  291. IF xe < 0 THEN x := 0 (*underflow*)
  292. ELSIF xe > 0FEH THEN x := MAXREAL + s; (* overflow *)
  293. ELSE x := xe*C + (x - C) + s;
  294. END;
  295. END
  296. END ;
  297. RETURN x
  298. END AddF32;
  299. PROCEDURE AddF64*(x,y: FLOAT64): FLOAT64;
  300. VAR z: FLOAT64;
  301. BEGIN FPE64.Add(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  302. END AddF64;
  303. PROCEDURE MulF64*(x,y: FLOAT64): FLOAT64;
  304. VAR z: FLOAT64;
  305. BEGIN FPE64.Mul(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  306. END MulF64;
  307. PROCEDURE DivF64*(x,y: FLOAT64): FLOAT64;
  308. VAR z: FLOAT64;
  309. BEGIN FPE64.Div(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  310. END DivF64;
  311. PROCEDURE SubF64*(x,y: FLOAT64): FLOAT64;
  312. VAR z: FLOAT64;
  313. BEGIN FPE64.Sub(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,y),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  314. END SubF64;
  315. PROCEDURE AbsF64*(x: FLOAT64): FLOAT64;
  316. VAR z: FLOAT64;
  317. BEGIN FPE64.Abs(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  318. END AbsF64;
  319. PROCEDURE NegF64*(x: FLOAT64): FLOAT64;
  320. VAR z: FLOAT64;
  321. BEGIN FPE64.Neg(SYSTEM.VAL(FPE64.Float64,x),SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  322. END NegF64;
  323. PROCEDURE ConvS32F64*(x: FLOAT64): LONGINT;
  324. BEGIN RETURN FPE64.Fix(SYSTEM.VAL(FPE64.Float64,x))
  325. END ConvS32F64;
  326. PROCEDURE ConvF32F64*(x: FLOAT64): REAL;
  327. BEGIN RETURN FPE64.Single(SYSTEM.VAL(FPE64.Float64,x))
  328. END ConvF32F64;
  329. PROCEDURE ConvF64F32*(x: REAL): FLOAT64;
  330. VAR z: FLOAT64;
  331. BEGIN FPE64.Double(x,SYSTEM.VAL(FPE64.Float64,z)); RETURN z
  332. END ConvF64F32;
  333. PROCEDURE ConvF64S32*(x: LONGINT): FLOAT64;
  334. VAR flt: FLOAT64;
  335. BEGIN FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  336. END ConvF64S32;
  337. PROCEDURE ConvF64S16*(x: INTEGER): FLOAT64;
  338. VAR flt: FLOAT64;
  339. BEGIN FPE64.Float(x, SYSTEM.VAL(FPE64.Float64,flt)); RETURN flt
  340. END ConvF64S16;
  341. PROCEDURE ConvF32S16*(x: INTEGER): REAL;
  342. BEGIN
  343. RETURN ConvF32S32(LONGINT(x))
  344. END ConvF32S16;
  345. PROCEDURE ConvF32S8*(x: SHORTINT): REAL;
  346. BEGIN
  347. RETURN ConvF32S16(INTEGER(x))
  348. END ConvF32S8;
  349. PROCEDURE ConvF64S8*(x: SHORTINT): FLOAT64;
  350. BEGIN
  351. RETURN ConvF64S16(INTEGER(x))
  352. END ConvF64S8;
  353. PROCEDURE SubF32*(left, right: FLOAT32): FLOAT32;
  354. BEGIN RETURN AddF32(left, NegF32(right))
  355. END SubF32;
  356. PROCEDURE MulF32*(x, y: FLOAT32): FLOAT32;
  357. VAR xe, zh, ye, s: LONGINT; (*zh, ye in this order; ye used as zh in MULD*)
  358. BEGIN
  359. IF SYSTEM.NULL(y) = TRUE THEN x := 0
  360. ELSIF SYSTEM.NULL(y) = FALSE THEN
  361. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  362. xe := x DIV C MOD E; (* exponent with bias *)
  363. ye := y DIV C MOD E; (* exponent with bias *)
  364. x := (x MOD C + C) * 20H;
  365. y := (y MOD C + C) * 20H;
  366. xe := xe + ye - B; (* exponent with bias *)
  367. SYSTEM.MULD(ye, x, y); (* note that this implicitly changes zh *)
  368. IF zh >= 4*C THEN
  369. x := (zh+2) DIV 4;
  370. INC(xe);
  371. ELSE
  372. x := (zh+1) DIV 2;
  373. END;
  374. IF xe < 0 THEN (* underflow *)
  375. x := 0;
  376. ELSIF xe > 0FEH THEN (* overflow *)
  377. x := MAXREAL + s;
  378. ELSE
  379. x := xe*C + (x-C) + s;
  380. END;
  381. END ;
  382. RETURN x
  383. END MulF32;
  384. PROCEDURE DivF32*(x, y: FLOAT32): FLOAT32;
  385. VAR xe, ye, q, s: LONGINT;
  386. BEGIN
  387. s := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.XOR(x, y))*{31});
  388. IF SYSTEM.NULL(y) = TRUE THEN
  389. x := MAXREAL + s;
  390. ELSIF SYSTEM.NULL(x) = FALSE THEN
  391. xe := x DIV C MOD E; (* exponent with bias *)
  392. ye := y DIV C MOD E; (* exponent with bias *)
  393. x := x MOD C + C;
  394. y := y MOD C + C;
  395. xe := xe - ye + B; (* exponent with bias *)
  396. IF x < y THEN
  397. x := x*2; DEC(xe);
  398. END ;
  399. IF xe < 0 THEN (* underflow *)
  400. x := 0;
  401. ELSIF xe > 0FEH THEN (* overflow *)
  402. x := MAXREAL + s;
  403. ELSE (* divide *)
  404. q := 0;
  405. WHILE q < LONGINT(1000000H) DO (* 2*C *)
  406. q := 2*q;
  407. IF x >= y THEN
  408. x := x - y;
  409. INC(q);
  410. END;
  411. x := 2*x;
  412. END;
  413. q := (q+1) DIV 2; (*round*)
  414. x := xe*C + (q-C) + s;
  415. END;
  416. END;
  417. RETURN x
  418. END DivF32;
  419. (** converts a float into an integer, ignores the fractional part
  420. - corresponds to ENTIER(x) **)
  421. PROCEDURE ConvS32F32*(x: FLOAT32): LONGINT;
  422. VAR xe, s: LONGINT;
  423. BEGIN
  424. IF SYSTEM.NULL(x) = TRUE THEN
  425. x := 0
  426. ELSE
  427. s := x; xe := x DIV C MOD E - B; x := x MOD C + C;
  428. IF s < 0 THEN x := -x END ;
  429. IF xe < 24 THEN x := ASH(x, xe - 23)
  430. ELSIF xe < 31 THEN x := LSH(x, xe - 23)
  431. ELSIF s < 0 THEN x := LONGINT(80000000H);
  432. ELSE x := LONGINT(7FFFFFFFH);
  433. END;
  434. END ;
  435. RETURN x
  436. END ConvS32F32;
  437. (** converts an integer into a float, ignores the non-integer part
  438. - corresponds to REAL(int)
  439. - note that no rounding occurs
  440. **)
  441. PROCEDURE ConvF32S32*(x: LONGINT): FLOAT32;
  442. VAR xe, s: LONGINT;
  443. BEGIN
  444. IF x = LONGINT(80000000H) THEN (* ABS cannot handle the most negative LONGINT number! *)
  445. x := LONGINT(0CF000000H);
  446. ELSIF x # 0 THEN
  447. s := x;
  448. x := ABS(x); xe := 23;
  449. WHILE x >= 2*C DO
  450. x := x DIV 2; INC(xe);
  451. END;
  452. WHILE x < C DO
  453. x := 2*x; DEC(xe);
  454. END;
  455. x := (xe + B)*C - C + x;
  456. IF s < 0 THEN x := x+S END
  457. END ;
  458. RETURN x
  459. END ConvF32S32;
  460. (* ---- STRING OPERATIONS ---- *)
  461. (** compare two strings
  462. - returns 0 if both strings are lexicographically equal
  463. - returns +1 if 'left' is lexicographically greater than 'right'
  464. - returns -1 if 'left' is lexicographically less than 'right'
  465. **)
  466. PROCEDURE CompareString*(CONST left, right: ARRAY OF CHAR): SHORTINT;
  467. VAR
  468. result: SHORTINT;
  469. i: LONGINT;
  470. leftChar, rightChar: CHAR;
  471. BEGIN
  472. result := 0;
  473. i := 0;
  474. REPEAT
  475. leftChar := left[i]; rightChar := right[i];
  476. IF leftChar < rightChar THEN result := -1
  477. ELSIF leftChar > rightChar THEN result := +1
  478. END;
  479. INC(i)
  480. UNTIL (result # 0) OR (leftChar = 0X) OR (rightChar = 0X);
  481. RETURN result
  482. END CompareString;
  483. (** copy a string from 'source' to 'destination'
  484. - note that PACO semantics are used **)
  485. PROCEDURE CopyString*(VAR destination: ARRAY OF CHAR; CONST source: ARRAY OF CHAR);
  486. VAR
  487. sourceLength, destinationLength: LONGINT;
  488. BEGIN
  489. destinationLength := LEN(destination);
  490. sourceLength := LEN(source);
  491. IF destinationLength < sourceLength THEN sourceLength := destinationLength END;
  492. SYSTEM.MOVE(ADDRESSOF(source[0]), ADDRESSOF(destination[0]), sourceLength)
  493. END CopyString;
  494. END ARMRuntime.