mips.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006-2007 by David Zhang
  4. Processor dependent implementation for the system unit for MIPS
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. MIPS specific stuff
  13. ****************************************************************************}
  14. {$if not defined(FPUNONE) and not defined(FPUSOFT)}
  15. function get_fsr : dword;assembler;nostackframe;[public, alias: 'FPC_GETFSR'];
  16. asm
  17. cfc1 $2,$31
  18. end;
  19. procedure set_fsr(fsr : dword);[public, alias: 'FPC_SETFSR'];
  20. begin
  21. DefaultFPUControlWord:=fsr;
  22. asm
  23. lw $4,fsr
  24. ctc1 $4,$31
  25. end;
  26. end;
  27. function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
  28. begin
  29. result:=get_fsr;
  30. end;
  31. procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
  32. begin
  33. set_fsr(cw);
  34. end;
  35. function get_got_z : pointer;assembler;nostackframe;[public, alias: 'FPC_GETGOT_Z'];
  36. asm
  37. move $2,$28
  38. end;
  39. const
  40. { FPU enable exception bits for FCSR register }
  41. fpu_enable_inexact = $80;
  42. fpu_enable_underflow = $100;
  43. fpu_enable_overflow = $200;
  44. fpu_enable_div_zero = $400;
  45. fpu_enable_invalid = $800;
  46. fpu_enable_mask = $F80;
  47. default_fpu_enable = fpu_enable_div_zero or fpu_enable_invalid;
  48. fpu_flags_mask = $7C;
  49. fpu_cause_mask = $3F000;
  50. { FPU rounding mask and values }
  51. fpu_rounding_mask = $3;
  52. fpu_rounding_nearest = 0;
  53. fpu_rounding_towards_zero = 1;
  54. fpu_rounding_plus_inf = 2;
  55. fpu_rounding_minus_inf = 3;
  56. fpu_all_bits = fpu_enable_mask or fpu_flags_mask or fpu_cause_mask or fpu_rounding_mask;
  57. {$endif}
  58. {$if defined(FPUMIPS2) or defined(FPUMIPS3)}
  59. {$define FPC_SYSTEM_HAS_SYSINITFPU}
  60. procedure SysInitFPU;
  61. begin
  62. set_fsr(get_fsr and (not fpu_all_bits) or (default_fpu_enable or fpu_rounding_nearest));
  63. softfloat_exception_mask:=[float_flag_inexact,float_flag_denormal];
  64. softfloat_exception_flags:=[];
  65. end;
  66. {$endif FPUMIPS2 or FPUMIPS3}
  67. {$ifndef INTERNAL_BACKTRACE}
  68. {$define FPC_SYSTEM_HAS_GET_FRAME}
  69. function get_frame:pointer;assembler;nostackframe;
  70. asm
  71. { we need to use the information of the .pdr section to do this properly:
  72. 0 proc. start adress
  73. 4 regmask
  74. 8 reg. offset
  75. 12 fmask
  76. 16 foffset
  77. 20 frame size
  78. 24 stack reg
  79. 28 link reg
  80. Further, we need to know the pc
  81. }
  82. // lw $2,0($sp)
  83. move $2,$30
  84. end;
  85. {$endif INTERNAL_BACKTRACE}
  86. { Try to find previous $fp,$ra register pair
  87. reset both to nil if failure }
  88. {$define FPC_SYSTEM_HAS_GET_CALLER_STACKINFO}
  89. procedure get_caller_stackinfo(var framebp : pointer; var addr : codepointer);
  90. const
  91. instr_size = 4;
  92. MAX_INSTRUCTIONS = 64000;
  93. type
  94. instr_p = pdword;
  95. reg_p = ppointer;
  96. var
  97. instr,stackpos : dword;
  98. i,LocalSize : longint;
  99. ra_offset, s8_offset : longint;
  100. current_ra : pointer;
  101. begin
  102. { Here we need to use GDB approach,
  103. starting at addr
  104. go back to lower $ra values until we find a
  105. position with ADDIU $sp,$sp,-LocalSize
  106. }
  107. if addr=nil then
  108. begin
  109. framebp:=nil;
  110. exit;
  111. end;
  112. Try
  113. current_ra:=addr;
  114. ra_offset:=-1;
  115. s8_offset:=-1;
  116. i:=0;
  117. LocalSize:=0;
  118. repeat
  119. inc(i);
  120. dec(current_ra,4);
  121. instr:=instr_p(current_ra)^;
  122. if (instr shr 16 = $27bd) then
  123. begin
  124. { we found the instruction,
  125. local size is the lo part }
  126. LocalSize:=smallint(instr and $ffff);
  127. break;
  128. end;
  129. until i> MAX_INSTRUCTIONS;
  130. if LocalSize <> 0 then
  131. begin
  132. repeat
  133. inc(current_ra,4);
  134. instr:=instr_p(current_ra)^;
  135. if (instr shr 16 = $afbf) then
  136. ra_offset:=smallint(instr and $ffff)
  137. else if (instr shr 16 = $afbe) then
  138. s8_offset:=smallint(instr and $ffff);
  139. until (current_ra >= addr)
  140. or ((ra_offset<>-1) and (s8_offset<>-1));
  141. if ra_offset<>-1 then
  142. begin
  143. stackpos:=dword(framebp+LocalSize+ra_offset);
  144. addr:=reg_p(stackpos)^;
  145. end
  146. else
  147. addr:=nil;
  148. if s8_offset<>-1 then
  149. begin
  150. stackpos:=dword(framebp+LocalSize+s8_offset);
  151. framebp:=reg_p(stackpos)^;
  152. end
  153. else
  154. framebp:=nil;
  155. end;
  156. Except
  157. framebp:=nil;
  158. addr:=nil;
  159. end;
  160. end;
  161. {$define FPC_SYSTEM_HAS_GET_PC_ADDR}
  162. function get_pc_addr : pointer;assembler;nostackframe;
  163. asm
  164. move $2,$31
  165. end;
  166. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  167. function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
  168. begin
  169. get_caller_stackinfo(framebp,addr);
  170. get_caller_addr:=addr;
  171. end;
  172. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  173. function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;
  174. begin
  175. get_caller_stackinfo(framebp,addr);
  176. get_caller_frame:=framebp;
  177. end;
  178. {$define FPC_SYSTEM_HAS_SPTR}
  179. function Sptr:Pointer;assembler;nostackframe;
  180. asm
  181. move $2,$sp
  182. end;
  183. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  184. {$define FPC_SYSTEM_HAS_FILLCHAR}
  185. procedure FillChar(var x;count:SizeInt;value:byte);assembler;nostackframe;
  186. // x=$a0, count=$a1, value=$a2
  187. // $t0 and $t1 used as temps
  188. asm
  189. // correctness of this routine depends on instructions in delay slots!!
  190. slti $t1, $a1, 8
  191. bne $t1, $0, .Lless8
  192. andi $a2, 0xff
  193. beq $a2, $0, .L1 // if value is zero, expansion can be skipped
  194. sll $t1, $a2, 8
  195. or $a2, $t1
  196. sll $t1, $a2, 16
  197. or $a2, $t1
  198. .L1:
  199. subu $t1, $0, $a0 // negate
  200. andi $t1, 3 // misalignment 0..3
  201. beq $t1, $0, .L2
  202. subu $a1, $t1 // decrease count (if branching, this is no-op because $t1=0)
  203. {$ifdef ENDIAN_BIG}
  204. swl $a2, 0($a0)
  205. {$else ENDIAN_BIG}
  206. swr $a2, 0($a0)
  207. {$endif ENDIAN_BIG}
  208. addu $a0, $t1 // add misalignment to address, making it dword-aligned
  209. .L2:
  210. andi $t1, $a1, 7 // $t1=count mod 8
  211. beq $t1, $a1, .L3 // (count and 7)=count => (count and (not 7))=0
  212. subu $t0, $a1, $t1 // $t0=count div 8
  213. addu $t0, $a0 // $t0=last loop address
  214. move $a1, $t1
  215. .Lloop8: // do 2 dwords per iteration
  216. addiu $a0, 8
  217. sw $a2, -8($a0)
  218. bne $a0, $t0, .Lloop8
  219. sw $a2, -4($a0)
  220. .L3:
  221. andi $t1, $a1, 4 // handle a single dword separately
  222. beq $t1, $0, .Lless8
  223. subu $a1, $t1
  224. sw $a2, 0($a0)
  225. addiu $a0, 4
  226. .Lless8:
  227. ble $a1, $0, .Lexit
  228. addu $t0, $a1, $a0
  229. .L4:
  230. addiu $a0, 1
  231. bne $a0, $t0, .L4
  232. sb $a2, -1($a0)
  233. .Lexit:
  234. end;
  235. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  236. {$ifdef USE_MIPS_STK2_ASM}
  237. {$ifndef FPC_SYSTEM_HAS_MOVE}
  238. (* Disabled for now
  239. {$define FPC_SYSTEM_HAS_MOVE}
  240. procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler;
  241. asm
  242. {
  243. Registers:
  244. $7 temp. to do copying
  245. $8 inc/decrement
  246. $9/l0/l1/l2 qword move
  247. }
  248. sw $4,0($23)
  249. sw $5,-4($23)
  250. sw $6,-8($23)
  251. sw $7,-12($23)
  252. sw $8,-16($23)
  253. sw $9,-20($23)
  254. sw $10,-24($23)
  255. sw $11,-28($23)
  256. sw $12,-32($23)
  257. sw $13,-36($23)
  258. sw $14,-40($23)
  259. addiu $23,$23,-44
  260. // count <= 0 ?
  261. ble $6,$0,.Lmoveexit
  262. nop
  263. // source = dest ?
  264. beq $4,$5,.Lmoveexit
  265. nop
  266. // possible overlap?
  267. bgt $4,$5,.Lnopossibleoverlap
  268. nop
  269. // source < dest ....
  270. addu $7,$6,$4
  271. // overlap?
  272. // source+count < dest ?
  273. blt $7,$5,.Lnopossibleoverlap
  274. nop
  275. .Lcopybackward:
  276. // check alignment of source and dest
  277. or $2,$4,$5
  278. // move src and dest to the end of the blocks
  279. // assuming 16 byte block size
  280. addiu $3,$6,-1
  281. addu $4,$4,$3
  282. addu $5,$5,$3
  283. b .Lmovebytewise
  284. li $3,-1
  285. .Lnopossibleoverlap:
  286. // check alignment of source and dest
  287. or $2,$4,$5
  288. // everything 16 byte aligned ?
  289. andi $13,$2,15
  290. beq $13,$0,.Lmovetwordwise
  291. // load direction in delay slot
  292. li $3,16
  293. andi $13,$2,7
  294. beq $13,$0,.Lmoveqwordwise
  295. li $3,8
  296. andi $13,$2,3
  297. beq $13,$0,.Lmovedwordwise
  298. li $3,4
  299. andi $13,$2,1
  300. beq $13,$0,.Lmovewordwise
  301. li $3,2
  302. b .Lmovebytewise
  303. li $3,1
  304. .Lmovetwordwise:
  305. srl $13,$6,4
  306. sll $14,$13,4
  307. beq $14,$0,.Lmoveqwordwise_shift
  308. nop
  309. .Lmovetwordwise_loop:
  310. lw $9,0($4)
  311. lw $10,4($4)
  312. addiu $13,$13,-1
  313. lw $11,8($4)
  314. lw $12,12($4)
  315. addu $4,$4,$3
  316. sw $9,0($5)
  317. sw $10,4($5)
  318. sw $11,8($5)
  319. sw $12,12($5)
  320. addu $5,$5,$3
  321. bne $13,$0,.Lmovetwordwise_loop
  322. nop
  323. subu $6,$6,$14
  324. beq $6,$0,.Lmoveexit
  325. nop
  326. .Lmoveqwordwise_shift:
  327. sra $3,$3,1
  328. .Lmoveqwordwise:
  329. srl $13,$6,3
  330. sll $14,$13,3
  331. beq $14,$0,.Lmovedwordwise_shift
  332. nop
  333. .Lmoveqwordwise_loop:
  334. lw $9,0($4)
  335. lw $10,4($4)
  336. addiu $13,$13,-1
  337. addu $4,$3,$4
  338. sw $9,0($5)
  339. sw $10,4($5)
  340. addu $5,$3,$5
  341. bne $13,$0,.Lmoveqwordwise_loop
  342. nop
  343. subu $6,$6,$14
  344. beq $6,$0,.Lmoveexit
  345. nop
  346. .Lmovedwordwise_shift:
  347. sra $3,$3,1
  348. .Lmovedwordwise:
  349. srl $13,$6,2
  350. sll $14,$13,2
  351. beq $14,$0,.Lmovewordwise_shift
  352. nop
  353. .Lmovedwordwise_loop:
  354. lw $9,0($4)
  355. addiu $13,$13,-1
  356. addu $4,$4,$3
  357. sw $9,0($5)
  358. addu $5,$5,$3
  359. bne $13,$0,.Lmovedwordwise_loop
  360. nop
  361. subu $6,$6,$14
  362. beq $6,$0,.Lmoveexit
  363. nop
  364. .Lmovewordwise_shift:
  365. sra $3,$3,1
  366. .Lmovewordwise:
  367. srl $13,$6,1
  368. sll $14,$13,1
  369. beq $14,$0, .Lmovebytewise_shift
  370. nop
  371. .Lmovewordwise_loop:
  372. lhu $9,0($4)
  373. addiu $13,$13,-1
  374. addu $4,$4,$3
  375. sh $9,0($5)
  376. addu $5,$5,$3
  377. bne $13,$0,.Lmovewordwise_loop
  378. nop
  379. subu $6,$6,$14
  380. beq $6,$0, .Lmoveexit
  381. nop
  382. .Lmovebytewise_shift:
  383. sra $3,$3,1
  384. .Lmovebytewise:
  385. beq $6,$0, .Lmoveexit
  386. nop
  387. lbu $9,0($4)
  388. addiu $6,$6,-1
  389. addu $4,$4,$3
  390. sb $9,0($5)
  391. addu $5,$5,$3
  392. bne $6,$0,.Lmovebytewise
  393. nop
  394. .Lmoveexit:
  395. addiu $23,$23,44
  396. lw $4,0($23)
  397. lw $5,-4($23)
  398. lw $6,-8($23)
  399. lw $7,-12($23)
  400. lw $8,-16($23)
  401. lw $9,-20($23)
  402. lw $10,-24($23)
  403. lw $11,-28($23)
  404. lw $12,-32($23)
  405. lw $13,-36($23)
  406. lw $14,-40($23)
  407. end;
  408. *)
  409. {$endif FPC_SYSTEM_HAS_MOVE}
  410. {$endif def USE_MIPS_STK2_ASM}
  411. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  412. function declocked(var l: longint) : boolean; inline;
  413. begin
  414. Result:=InterLockedDecrement(l) = 0;
  415. end;
  416. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  417. procedure inclocked(var l: longint); inline;
  418. begin
  419. InterLockedIncrement(l);
  420. end;
  421. {$IFDEF VER3_2}
  422. function InterLockedDecrement (var Target: longint) : longint;
  423. {$ELSE VER3_2}
  424. {$DEFINE FPC_SYSTEM_HAS_ATOMIC_DEC_32}
  425. function fpc_atomic_dec_32 (var Target: longint) : longint;
  426. {$ENDIF VER3_2}
  427. {$IFDEF CPUMIPS1}
  428. begin
  429. Target:= Target - 1;
  430. Result:=Target;
  431. {$ELSE}
  432. assembler; nostackframe;
  433. asm
  434. sync
  435. .L1:
  436. ll $v0,($a0)
  437. addiu $v1,$v0,-1
  438. move $v0,$v1 // must return value after decrement
  439. sc $v1,($a0)
  440. beq $v1,$0,.L1
  441. nop
  442. sync
  443. {$ENDIF}
  444. end;
  445. {$IFDEF VER3_2}
  446. function InterLockedIncrement (var Target: longint) : longint;
  447. {$ELSE VER3_2}
  448. {$DEFINE FPC_SYSTEM_HAS_ATOMIC_INC_32}
  449. function fpc_atomic_inc_32 (var Target: longint) : longint;
  450. {$ENDIF VER3_2}
  451. {$IFDEF CPUMIPS1}
  452. begin
  453. Target:= Target + 1;
  454. Result:=Target;
  455. {$ELSE}
  456. assembler; nostackframe;
  457. asm
  458. sync
  459. .L1:
  460. ll $v0,($a0)
  461. addiu $v1,$v0,1
  462. move $v0,$v1 // must return value after increment
  463. sc $v1,($a0)
  464. beq $v1,$0,.L1
  465. nop
  466. sync
  467. {$ENDIF}
  468. end;
  469. {$IFDEF VER3_2}
  470. function InterLockedExchange (var Target: longint;Source : longint) : longint;
  471. {$ELSE VER3_2}
  472. {$DEFINE FPC_SYSTEM_HAS_ATOMIC_XCHG_32}
  473. function fpc_atomic_xchg_32 (var Target: longint;Source : longint) : longint;
  474. {$ENDIF VER3_2}
  475. {$IFDEF CPUMIPS1}
  476. begin
  477. Result:=Target;
  478. Target:=Source;
  479. {$ELSE}
  480. assembler; nostackframe;
  481. asm
  482. sync
  483. .L1:
  484. ll $v0,($a0)
  485. move $v1,$a1
  486. sc $v1,($a0)
  487. beq $v1,$0,.L1
  488. nop
  489. sync
  490. {$ENDIF}
  491. end;
  492. {$IFDEF VER3_2}
  493. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint;
  494. {$ELSE VER3_2}
  495. {$DEFINE FPC_SYSTEM_HAS_ATOMIC_ADD_32}
  496. function fpc_atomic_add_32 (var Target: longint;Value : longint) : longint;
  497. {$ENDIF VER3_2}
  498. {$IFDEF CPUMIPS1}
  499. begin
  500. Result:=Target;
  501. {$IFDEF VER3_2}
  502. Target:= Target + Source;
  503. {$ELSE VER3_2}
  504. Target:= Target + Value;
  505. {$ENDIF VER3_2}
  506. {$ELSE}
  507. assembler; nostackframe;
  508. asm
  509. sync
  510. .L1:
  511. ll $v0,($a0)
  512. addu $v1,$v0,$a1
  513. sc $v1,($a0)
  514. beq $v1,$0,.L1
  515. nop
  516. sync
  517. {$ENDIF}
  518. end;
  519. {$IFDEF VER3_2}
  520. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint;
  521. {$ELSE VER3_2}
  522. {$DEFINE FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_32}
  523. function fpc_atomic_cmp_xchg_32 (var Target: longint; NewValue: longint; Comparand: longint) : longint; [public,alias:'FPC_ATOMIC_CMP_XCHG_32'];
  524. {$ENDIF VER3_2}
  525. {$IFDEF CPUMIPS1}
  526. begin
  527. Result:= Target;
  528. {$IFDEF VER3_2}
  529. if Target = Comperand then
  530. {$ELSE VER3_2}
  531. if Target = Comparand then
  532. {$ENDIF VER3_2}
  533. Target:= NewValue;
  534. {$ELSE}
  535. assembler; nostackframe;
  536. asm
  537. sync
  538. .L1:
  539. ll $v0,($a0)
  540. bne $v0,$a2,.L2
  541. nop
  542. move $v1,$a1
  543. sc $v1,($a0)
  544. beq $v1,$0,.L1
  545. nop
  546. sync
  547. .L2:
  548. {$ENDIF}
  549. end;
  550. {$ifndef FPC_SYSTEM_HAS_SAR_QWORD}
  551. {$ifdef ENDIAN_BIG}
  552. {$define FPC_SYSTEM_HAS_SAR_QWORD}
  553. function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64; [Public,Alias:'FPC_SARINT64']; compilerproc; assembler; nostackframe;
  554. asm
  555. { $a0=high(AValue) $a1=low(AValue), result: $v0:$v1 }
  556. andi $a2,$a2,63
  557. sltiu $t0,$a2,32
  558. beq $t0,$0,.L1
  559. nop
  560. srlv $v1,$a1,$a2
  561. srav $v0,$a0,$a2
  562. beq $a2,$0,.Lexit
  563. nop
  564. subu $t0,$0,$a2
  565. sllv $t0,$a0,$t0
  566. or $v1,$v1,$t0
  567. b .Lexit
  568. nop
  569. .L1:
  570. sra $v0,$a0,31
  571. srav $v1,$a0,$a2
  572. .Lexit:
  573. end;
  574. {$endif ENDIAN_BIG}
  575. {$endif FPC_SYSTEM_HAS_SAR_QWORD}