loongarch64.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by the Free Pascal development team.
  4. Processor dependent implementation for the system unit for
  5. RiscV64
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. const
  13. fpu_i = 1 shl 0;
  14. fpu_u = 1 shl 1;
  15. fpu_o = 1 shl 2;
  16. fpu_z = 1 shl 3;
  17. fpu_v = 1 shl 4;
  18. function getrm: dword; nostackframe; assembler;
  19. asm
  20. movfcsr2gr $a0, $r3
  21. srli.w $a0, $a0, 8
  22. end;
  23. procedure __setrm(val: dword); nostackframe; assembler;
  24. asm
  25. slli.w $a0, $a0, 8
  26. movgr2fcsr $r3, $a0
  27. end;
  28. procedure setrm(val: dword);
  29. begin
  30. DefaultFPUControlWord.rndmode:=val;
  31. __setrm(val);
  32. end;
  33. function getenables: dword; nostackframe; assembler;
  34. asm
  35. movfcsr2gr $a0, $r1
  36. end;
  37. procedure __setenables(enables : dword); nostackframe; assembler;
  38. asm
  39. movgr2fcsr $r1, $a0
  40. end;
  41. procedure setenables(enables : dword);
  42. begin
  43. DefaultFPUControlWord.cw:=enables;
  44. __setenables(enables);
  45. end;
  46. function getcause: dword; nostackframe; assembler;
  47. asm
  48. movfcsr2gr $a0, $r2
  49. srli.w $a0, $a0, 24
  50. end;
  51. procedure setcause(cause : dword); nostackframe; assembler;
  52. asm
  53. slli.w $a0, $a0, 24
  54. movgr2fcsr $r2, $a0
  55. end;
  56. function GetNativeFPUControlWord: TNativeFPUControlWord;
  57. begin
  58. result.cw:=getenables;
  59. result.rndmode:=getrm;
  60. end;
  61. procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
  62. begin
  63. setenables(cw.cw);
  64. setrm(cw.rndmode);
  65. end;
  66. procedure RaisePendingExceptions;
  67. var
  68. cause : dword;
  69. f: TFPUException;
  70. begin
  71. cause:=getcause;
  72. if (cause and fpu_i) <> 0 then
  73. float_raise(exPrecision);
  74. if (cause and fpu_u) <> 0 then
  75. float_raise(exUnderflow);
  76. if (cause and fpu_o) <> 0 then
  77. float_raise(exOverflow);
  78. if (cause and fpu_z) <> 0 then
  79. float_raise(exZeroDivide);
  80. if (cause and fpu_v) <> 0 then
  81. float_raise(exInvalidOp);
  82. { now the soft float exceptions }
  83. for f in softfloat_exception_flags do
  84. float_raise(f);
  85. end;
  86. procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
  87. var
  88. cause : dword;
  89. begin
  90. cause:=getcause;
  91. { check, if the exception is masked }
  92. if ((cause and fpu_i) <> 0) and (exPrecision in softfloat_exception_mask) then
  93. cause:=cause and not(fpu_i);
  94. if ((cause and fpu_u) <> 0) and (exUnderflow in softfloat_exception_mask) then
  95. cause:=cause and not(fpu_u);
  96. if ((cause and fpu_o) <> 0) and (exOverflow in softfloat_exception_mask) then
  97. cause:=cause and not(fpu_o);
  98. if ((cause and fpu_z) <> 0) and (exZeroDivide in softfloat_exception_mask) then
  99. cause:=cause and not(fpu_z);
  100. if ((cause and fpu_v) <> 0) and (exInvalidOp in softfloat_exception_mask) then
  101. cause:=cause and not(fpu_v);
  102. setcause(cause);
  103. if cause<>0 then
  104. RaisePendingExceptions;
  105. end;
  106. {$define FPC_SYSTEM_HAS_SYSINITFPU}
  107. procedure SysInitFPU;
  108. begin
  109. setrm(0);
  110. setcause(0);
  111. setenables(fpu_z or fpu_v);
  112. softfloat_exception_mask:=[exPrecision,exUnderflow];
  113. softfloat_exception_flags:=[];
  114. end;
  115. {****************************************************************************
  116. Math Routines
  117. ****************************************************************************}
  118. {$define FPC_SYSTEM_HAS_SWAPENDIAN}
  119. {TODO It may be better to use the inline method}
  120. {signed 16bit}
  121. function SwapEndian(const AValue: SmallInt): SmallInt;assembler; nostackframe;
  122. asm
  123. revb.2h $a0, $a0
  124. ext.w.h $a0, $a0
  125. end;
  126. {unsigned 16bit}
  127. function SwapEndian(const AValue: Word): Word;assembler; nostackframe;
  128. asm
  129. revb.2h $a0, $a0
  130. bstrpick.d $a0, $a0, 15, 0
  131. end;
  132. {signed 32bit}
  133. function SwapEndian(const AValue: LongInt): LongInt; assembler; nostackframe;
  134. asm
  135. revb.2w $a0, $a0
  136. addi.w $a0, $a0, 0
  137. end;
  138. {unsigned 32bit}
  139. function SwapEndian(const AValue: DWord): DWord; assembler; nostackframe;
  140. asm
  141. revb.2w $a0, $a0
  142. bstrpick.d $a0, $a0, 31, 0
  143. end;
  144. {signed 64bit}
  145. function SwapEndian(const AValue: Int64): Int64; assembler; nostackframe;
  146. asm
  147. revb.d $a0, $a0
  148. end;
  149. {unsigned 64bit}
  150. function SwapEndian(const AValue: QWord): QWord; assembler; nostackframe;
  151. asm
  152. revb.d $a0, $a0
  153. end;
  154. {****************************************************************************
  155. stack frame related stuff
  156. ****************************************************************************}
  157. {$IFNDEF INTERNAL_BACKTRACE}
  158. {$define FPC_SYSTEM_HAS_GET_FRAME}
  159. function get_frame:pointer;assembler;nostackframe;
  160. asm
  161. ori $a0, $fp, 0
  162. end;
  163. {$ENDIF not INTERNAL_BACKTRACE}
  164. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  165. function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler;
  166. asm
  167. ld.d $a0, $a0, -8
  168. end;
  169. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  170. function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler;
  171. asm
  172. ld.d $a0, $a0, -16
  173. end;
  174. {$define FPC_SYSTEM_HAS_SPTR}
  175. Function Sptr : pointer;assembler;nostackframe;
  176. asm
  177. ori $a0, $sp, 0
  178. end;
  179. function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
  180. asm
  181. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  182. addi.w $a1, $zero, -1
  183. amadd_db.w $a2, $a1, $a0
  184. add.w $a0, $a1, $a2
  185. {$else CPULOONGARCH_HAS_ATOMIC}
  186. dbar 0
  187. .LLoop:
  188. ll.w $a1, $a0, 0
  189. addi.w $a2, $a1, -1
  190. sc.w $a2, $a0, 0
  191. beqz $a2, .LLoop
  192. addi.w $a0, $a1, -1
  193. dbar 0
  194. {$endif CPULOONGARCH_HAS_ATOMIC}
  195. end;
  196. function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
  197. asm
  198. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  199. addi.w $a1, $zero, 1
  200. amadd_db.w $a2, $a1, $a0
  201. add.w $a0, $a1, $a2
  202. {$else CPULOONGARCH_HAS_ATOMIC}
  203. dbar 0
  204. .LLoop:
  205. ll.w $a1, $a0, 0
  206. addi.w $a2, $a1, 1
  207. sc.w $a2, $a0, 0
  208. beqz $a2, .LLoop
  209. addi.w $a0, $a1, 1
  210. dbar 0
  211. {$endif CPULOONGARCH_HAS_ATOMIC}
  212. end;
  213. function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  214. asm
  215. dbar 0
  216. .LLoop:
  217. ll.w $a3, $a0, 0
  218. ori $a2, $a1, 0
  219. sc.w $a2, $a0, 0
  220. beqz $a2, .LLoop
  221. ori $a0, $a3, 0
  222. dbar 0
  223. end;
  224. function InterLockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
  225. asm
  226. dbar 0
  227. .LLoop:
  228. ll.w $a3, $a0, 0
  229. bne $a3, $a2, .LFail
  230. ori $a4, $a1, 0
  231. sc.w $a4, $a0, 0
  232. beqz $a4, .LLoop
  233. .LFail:
  234. ori $a0, $a3, 0
  235. dbar 0
  236. end;
  237. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  238. asm
  239. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  240. amadd_db.w $a2, $a1, $a0
  241. move $a0, $a2
  242. {$else CPULOONGARCH_HAS_ATOMIC}
  243. dbar 0
  244. .LLoop:
  245. ll.w $a2, $a0, 0
  246. add.w $a3, $a1, $a2
  247. sc.w $a3, $a0, 0
  248. beqz $a3, .LLoop
  249. move $a0, $a2
  250. dbar 0
  251. {$endif CPULOONGARCH_HAS_ATOMIC}
  252. end;
  253. function InterLockedDecrement64 (var Target: int64) : int64; assembler; nostackframe;
  254. asm
  255. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  256. addi.d $a1, $zero, -1
  257. amadd_db.d $a2, $a1, $a0
  258. add.d $a0, $a1, $a2
  259. {$else CPULOONGARCH_HAS_ATOMIC}
  260. dbar 0
  261. .LLoop:
  262. ll.d $a1, $a0, 0
  263. addi.d $a2, $a1, -1
  264. sc.d $a2, $a0, 0
  265. beqz $a2, .LLoop
  266. addi.d $a0, $a1, -1
  267. dbar 0
  268. {$endif CPULOONGARCH_HAS_ATOMIC}
  269. end;
  270. function InterLockedIncrement64 (var Target: int64) : int64; assembler; nostackframe;
  271. asm
  272. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  273. addi.d $a1, $zero, 1
  274. amadd_db.d $a2, $a1, $a0
  275. add.d $a0, $a1, $a2
  276. {$else CPULOONGARCH_HAS_ATOMIC}
  277. dbar 0
  278. .LLoop:
  279. ll.d $a1, $a0, 0
  280. addi.d $a2, $a1, 1
  281. sc.d $a2, $a0, 0
  282. beqz $a2, .LLoop
  283. addi.d $a0, $a1, 1
  284. dbar 0
  285. {$endif CPULOONGARCH_HAS_ATOMIC}
  286. end;
  287. function InterLockedExchange64 (var Target: int64;Source : int64) : int64; assembler; nostackframe;
  288. asm
  289. dbar 0
  290. .LLoop:
  291. ll.d $a3, $a0, 0
  292. ori $a2, $a1, 0
  293. sc.d $a2, $a0, 0
  294. beqz $a2, .LLoop
  295. ori $a0, $a3, 0
  296. dbar 0
  297. end;
  298. function InterLockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64; assembler; nostackframe;
  299. asm
  300. dbar 0
  301. .LLoop:
  302. ll.d $a3, $a0, 0
  303. bne $a3, $a2, .LFail
  304. ori $a4, $a1, 0
  305. sc.d $a4, $a0, 0
  306. beqz $a4, .LLoop
  307. .LFail:
  308. ori $a0, $a3, 0
  309. dbar 0
  310. end;
  311. function InterLockedExchangeAdd64 (var Target: int64;Source : int64) : int64; assembler; nostackframe;
  312. asm
  313. {$ifdef CPULOONGARCH_HAS_ATOMIC}
  314. amadd_db.d $a2, $a1, $a0
  315. add.d $a0, $a1, $a2
  316. {$else CPULOONGARCH_HAS_ATOMIC}
  317. dbar 0
  318. .LLoop:
  319. ll.d $a2, $a0, 0
  320. add.d $a3, $a1, $a2
  321. sc.d $a3, $a0, 0
  322. beqz $a3, .LLoop
  323. add.d $a0, $a1, $a2
  324. dbar 0
  325. {$endif CPULOONGARCH_HAS_ATOMIC}
  326. end;
  327. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  328. function declocked(var l: longint) : boolean; inline;
  329. begin
  330. Result:=InterLockedDecrement(l) = 0;
  331. end;
  332. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  333. procedure inclocked(var l: longint); inline;
  334. begin
  335. InterLockedIncrement(l);
  336. end;
  337. {$define FPC_SYSTEM_HAS_DECLOCKED_INT64}
  338. function declocked(var l:int64):boolean;
  339. begin
  340. Result:=InterLockedDecrement64(l) = 0;
  341. end;
  342. {$define FPC_SYSTEM_HAS_INCLOCKED_INT64}
  343. procedure inclocked(var l:int64);
  344. begin
  345. InterLockedIncrement64(l);
  346. end;
  347. {$define FPC_SYSTEM_HAS_MEM_BARRIER}
  348. procedure ReadBarrier; assembler; nostackframe;
  349. asm
  350. dbar 0
  351. end;
  352. procedure ReadDependencyBarrier;{$ifdef SYSTEMINLINE}inline;{$endif}
  353. begin
  354. end;
  355. procedure ReadWriteBarrier; assembler; nostackframe;
  356. asm
  357. dbar 0
  358. end;
  359. procedure WriteBarrier; assembler; nostackframe;
  360. asm
  361. dbar 0
  362. end;
  363. {$define FPC_SYSTEM_HAS_MOVE}
  364. procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE']; assembler; nostackframe;
  365. asm
  366. blez $a2, .Lret
  367. beq $a0, $a1, .Lret
  368. move $t0, $a0
  369. add.d $t1, $a1, $a2
  370. bgt $t0, $t1, .Lprefast_tail
  371. sub.d $t1, $a1, $a2
  372. blt $t0, $t1, .Lprefast_tail
  373. bgt $a0, $a1, .Lgeneric_head
  374. add.d $a0, $a0, $a2
  375. add.d $a1, $a1, $a2
  376. .Lgeneric_tail:
  377. ld.b $t0, $a0, -1
  378. st.b $t0, $a1, -1
  379. addi.d $a0, $a0, -1
  380. addi.d $a1, $a1, -1
  381. addi.d $a2, $a2, -1
  382. bgtz $a2, .Lgeneric_tail
  383. b .Lret
  384. .Lgeneric_head:
  385. ld.b $t0, $a0, 0
  386. st.b $t0, $a1, 0
  387. addi.d $a0, $a0, 1
  388. addi.d $a1, $a1, 1
  389. addi.d $a2, $a2, -1
  390. bgtz $a2, .Lgeneric_head
  391. b .Lret
  392. .Lprefast_tail:
  393. add.d $a0, $a0, $a2
  394. add.d $a1, $a1, $a2
  395. ori $a3, $zero, 64
  396. blt $a2, $a3, .Lgeneric_tail
  397. .Lfast_tail:
  398. ld.d $t0, $a0, -8
  399. ld.d $t1, $a0, -16
  400. ld.d $t2, $a0, -24
  401. ld.d $t3, $a0, -32
  402. ld.d $t4, $a0, -40
  403. ld.d $t5, $a0, -48
  404. ld.d $t6, $a0, -56
  405. ld.d $t7, $a0, -64
  406. st.d $t0, $a1, -8
  407. st.d $t1, $a1, -16
  408. st.d $t2, $a1, -24
  409. st.d $t3, $a1, -32
  410. st.d $t4, $a1, -40
  411. st.d $t5, $a1, -48
  412. st.d $t6, $a1, -56
  413. st.d $t7, $a1, -64
  414. addi.d $a0, $a0, -64
  415. addi.d $a1, $a1, -64
  416. addi.d $a2, $a2, -64
  417. bge $a2, $a3, .Lfast_tail
  418. bnez $a2, .Lgeneric_tail
  419. .Lret:
  420. jr $ra
  421. end;
  422. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  423. procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
  424. {$ifdef FPUFD}
  425. var
  426. cw: TNativeFPUControlWord;
  427. {$endif}
  428. begin
  429. softfloat_exception_flags:=[];
  430. softfloat_exception_mask:=[exPrecision,exUnderflow];
  431. {$ifdef FPUFD}
  432. cw:=GetNativeFPUControlWord;
  433. cw.cw:=0;
  434. { round to nearest }
  435. cw.rndmode:=0;
  436. SetNativeFPUControlWord(cw);
  437. {$endif}
  438. end;