mips.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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. function get_fsr : dword;assembler;nostackframe;[public, alias: 'FPC_GETFSR'];
  15. asm
  16. cfc1 $2,$31
  17. end;
  18. procedure set_fsr(fsr : dword);assembler;nostackframe;[public, alias: 'FPC_SETFSR'];
  19. asm
  20. ctc1 $4,$31
  21. end;
  22. function get_got_z : pointer;assembler;nostackframe;[public, alias: 'FPC_GETGOT_Z'];
  23. asm
  24. move $2,$28
  25. end;
  26. const
  27. { FPU enable exception bits for FCSR register }
  28. fpu_enable_inexact = $80;
  29. fpu_enable_underflow = $100;
  30. fpu_enable_overflow = $200;
  31. fpu_enable_div_zero = $400;
  32. fpu_enable_invalid = $800;
  33. fpu_enable_mask = $F80;
  34. default_fpu_enable = fpu_enable_div_zero or fpu_enable_invalid;
  35. fpu_flags_mask = $7C;
  36. fpu_cause_mask = $3F000;
  37. { FPU rounding mask and values }
  38. fpu_rounding_mask = $3;
  39. fpu_rounding_nearest = 0;
  40. fpu_rounding_towards_zero = 1;
  41. fpu_rounding_plus_inf = 2;
  42. fpu_rounding_minus_inf = 3;
  43. procedure fpc_cpuinit;
  44. var
  45. tmp32: longint;
  46. begin
  47. { don't let libraries influence the FPU cw set by the host program }
  48. if not IsLibrary then
  49. begin
  50. tmp32 := get_fsr();
  51. { enable div by 0 and invalid operation fpu exceptions,
  52. disable the other exceptions }
  53. tmp32 := (tmp32 and not fpu_enable_mask) or default_fpu_enable;
  54. { Reset flags and cause }
  55. tmp32 := tmp32 and not (fpu_flags_mask or fpu_cause_mask);
  56. { round towards nearest; ieee compliant arithmetics }
  57. tmp32 := (tmp32 and not fpu_rounding_mask) or fpu_rounding_nearest;
  58. set_fsr(tmp32);
  59. end;
  60. end;
  61. {$ifndef INTERNAL_BACKTRACE}
  62. {$define FPC_SYSTEM_HAS_GET_FRAME}
  63. function get_frame:pointer;assembler;nostackframe;
  64. asm
  65. { we need to use the information of the .pdr section to do this properly:
  66. 0 proc. start adress
  67. 4 regmask
  68. 8 reg. offset
  69. 12 fmask
  70. 16 foffset
  71. 20 frame size
  72. 24 stack reg
  73. 28 link reg
  74. Further, we need to know the pc
  75. }
  76. // lw $2,0($sp)
  77. move $2,$30
  78. end;
  79. {$endif INTERNAL_BACKTRACE}
  80. { Try to find previous $fp,$ra register pair
  81. reset both to nil if failure }
  82. {$define FPC_SYSTEM_HAS_GET_CALLER_STACKINFO}
  83. procedure get_caller_stackinfo(var framebp : pointer; var addr : codepointer);
  84. const
  85. instr_size = 4;
  86. MAX_INSTRUCTIONS = 64000;
  87. type
  88. instr_p = pdword;
  89. reg_p = ppointer;
  90. var
  91. instr,stackpos : dword;
  92. i,LocalSize : longint;
  93. ra_offset, s8_offset : longint;
  94. current_ra : pointer;
  95. begin
  96. { Here we need to use GDB approach,
  97. starting at addr
  98. go back to lower $ra values until we find a
  99. position with ADDIU $sp,$sp,-LocalSize
  100. }
  101. if addr=nil then
  102. begin
  103. framebp:=nil;
  104. exit;
  105. end;
  106. Try
  107. current_ra:=addr;
  108. ra_offset:=-1;
  109. s8_offset:=-1;
  110. i:=0;
  111. LocalSize:=0;
  112. repeat
  113. inc(i);
  114. dec(current_ra,4);
  115. instr:=instr_p(current_ra)^;
  116. if (instr shr 16 = $27bd) then
  117. begin
  118. { we found the instruction,
  119. local size is the lo part }
  120. LocalSize:=smallint(instr and $ffff);
  121. break;
  122. end;
  123. until i> MAX_INSTRUCTIONS;
  124. if LocalSize <> 0 then
  125. begin
  126. repeat
  127. inc(current_ra,4);
  128. instr:=instr_p(current_ra)^;
  129. if (instr shr 16 = $afbf) then
  130. ra_offset:=smallint(instr and $ffff)
  131. else if (instr shr 16 = $afbe) then
  132. s8_offset:=smallint(instr and $ffff);
  133. until (current_ra >= addr)
  134. or ((ra_offset<>-1) and (s8_offset<>-1));
  135. if ra_offset<>-1 then
  136. begin
  137. stackpos:=dword(framebp+LocalSize+ra_offset);
  138. addr:=reg_p(stackpos)^;
  139. end
  140. else
  141. addr:=nil;
  142. if s8_offset<>-1 then
  143. begin
  144. stackpos:=dword(framebp+LocalSize+s8_offset);
  145. framebp:=reg_p(stackpos)^;
  146. end
  147. else
  148. framebp:=nil;
  149. end;
  150. Except
  151. framebp:=nil;
  152. addr:=nil;
  153. end;
  154. end;
  155. {$define FPC_SYSTEM_HAS_GET_PC_ADDR}
  156. function get_pc_addr : pointer;assembler;nostackframe;
  157. asm
  158. move $2,$31
  159. end;
  160. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  161. function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
  162. begin
  163. get_caller_stackinfo(framebp,addr);
  164. get_caller_addr:=addr;
  165. end;
  166. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  167. function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;
  168. begin
  169. get_caller_stackinfo(framebp,addr);
  170. get_caller_frame:=framebp;
  171. end;
  172. {$define FPC_SYSTEM_HAS_SPTR}
  173. function Sptr:Pointer;assembler;nostackframe;
  174. asm
  175. move $2,$sp
  176. end;
  177. {$ifdef USE_MIPS_STK2_ASM}
  178. {$ifndef FPC_SYSTEM_HAS_MOVE}
  179. (* Disabled for now
  180. {$define FPC_SYSTEM_HAS_MOVE}
  181. procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler;
  182. asm
  183. {
  184. Registers:
  185. $7 temp. to do copying
  186. $8 inc/decrement
  187. $9/l0/l1/l2 qword move
  188. }
  189. sw $4,0($23)
  190. sw $5,-4($23)
  191. sw $6,-8($23)
  192. sw $7,-12($23)
  193. sw $8,-16($23)
  194. sw $9,-20($23)
  195. sw $10,-24($23)
  196. sw $11,-28($23)
  197. sw $12,-32($23)
  198. sw $13,-36($23)
  199. sw $14,-40($23)
  200. addiu $23,$23,-44
  201. // count <= 0 ?
  202. ble $6,$0,.Lmoveexit
  203. nop
  204. // source = dest ?
  205. beq $4,$5,.Lmoveexit
  206. nop
  207. // possible overlap?
  208. bgt $4,$5,.Lnopossibleoverlap
  209. nop
  210. // source < dest ....
  211. addu $7,$6,$4
  212. // overlap?
  213. // source+count < dest ?
  214. blt $7,$5,.Lnopossibleoverlap
  215. nop
  216. .Lcopybackward:
  217. // check alignment of source and dest
  218. or $2,$4,$5
  219. // move src and dest to the end of the blocks
  220. // assuming 16 byte block size
  221. addiu $3,$6,-1
  222. addu $4,$4,$3
  223. addu $5,$5,$3
  224. b .Lmovebytewise
  225. li $3,-1
  226. .Lnopossibleoverlap:
  227. // check alignment of source and dest
  228. or $2,$4,$5
  229. // everything 16 byte aligned ?
  230. andi $13,$2,15
  231. beq $13,$0,.Lmovetwordwise
  232. // load direction in delay slot
  233. li $3,16
  234. andi $13,$2,7
  235. beq $13,$0,.Lmoveqwordwise
  236. li $3,8
  237. andi $13,$2,3
  238. beq $13,$0,.Lmovedwordwise
  239. li $3,4
  240. andi $13,$2,1
  241. beq $13,$0,.Lmovewordwise
  242. li $3,2
  243. b .Lmovebytewise
  244. li $3,1
  245. .Lmovetwordwise:
  246. srl $13,$6,4
  247. sll $14,$13,4
  248. beq $14,$0,.Lmoveqwordwise_shift
  249. nop
  250. .Lmovetwordwise_loop:
  251. lw $9,0($4)
  252. lw $10,4($4)
  253. addiu $13,$13,-1
  254. lw $11,8($4)
  255. lw $12,12($4)
  256. addu $4,$4,$3
  257. sw $9,0($5)
  258. sw $10,4($5)
  259. sw $11,8($5)
  260. sw $12,12($5)
  261. addu $5,$5,$3
  262. bne $13,$0,.Lmovetwordwise_loop
  263. nop
  264. subu $6,$6,$14
  265. beq $6,$0,.Lmoveexit
  266. nop
  267. .Lmoveqwordwise_shift:
  268. sra $3,$3,1
  269. .Lmoveqwordwise:
  270. srl $13,$6,3
  271. sll $14,$13,3
  272. beq $14,$0,.Lmovedwordwise_shift
  273. nop
  274. .Lmoveqwordwise_loop:
  275. lw $9,0($4)
  276. lw $10,4($4)
  277. addiu $13,$13,-1
  278. addu $4,$3,$4
  279. sw $9,0($5)
  280. sw $10,4($5)
  281. addu $5,$3,$5
  282. bne $13,$0,.Lmoveqwordwise_loop
  283. nop
  284. subu $6,$6,$14
  285. beq $6,$0,.Lmoveexit
  286. nop
  287. .Lmovedwordwise_shift:
  288. sra $3,$3,1
  289. .Lmovedwordwise:
  290. srl $13,$6,2
  291. sll $14,$13,2
  292. beq $14,$0,.Lmovewordwise_shift
  293. nop
  294. .Lmovedwordwise_loop:
  295. lw $9,0($4)
  296. addiu $13,$13,-1
  297. addu $4,$4,$3
  298. sw $9,0($5)
  299. addu $5,$5,$3
  300. bne $13,$0,.Lmovedwordwise_loop
  301. nop
  302. subu $6,$6,$14
  303. beq $6,$0,.Lmoveexit
  304. nop
  305. .Lmovewordwise_shift:
  306. sra $3,$3,1
  307. .Lmovewordwise:
  308. srl $13,$6,1
  309. sll $14,$13,1
  310. beq $14,$0, .Lmovebytewise_shift
  311. nop
  312. .Lmovewordwise_loop:
  313. lhu $9,0($4)
  314. addiu $13,$13,-1
  315. addu $4,$4,$3
  316. sh $9,0($5)
  317. addu $5,$5,$3
  318. bne $13,$0,.Lmovewordwise_loop
  319. nop
  320. subu $6,$6,$14
  321. beq $6,$0, .Lmoveexit
  322. nop
  323. .Lmovebytewise_shift:
  324. sra $3,$3,1
  325. .Lmovebytewise:
  326. beq $6,$0, .Lmoveexit
  327. nop
  328. lbu $9,0($4)
  329. addiu $6,$6,-1
  330. addu $4,$4,$3
  331. sb $9,0($5)
  332. addu $5,$5,$3
  333. bne $6,$0,.Lmovebytewise
  334. nop
  335. .Lmoveexit:
  336. addiu $23,$23,44
  337. lw $4,0($23)
  338. lw $5,-4($23)
  339. lw $6,-8($23)
  340. lw $7,-12($23)
  341. lw $8,-16($23)
  342. lw $9,-20($23)
  343. lw $10,-24($23)
  344. lw $11,-28($23)
  345. lw $12,-32($23)
  346. lw $13,-36($23)
  347. lw $14,-40($23)
  348. end;
  349. *)
  350. {$endif FPC_SYSTEM_HAS_MOVE}
  351. {****************************************************************************
  352. Integer math
  353. ****************************************************************************}
  354. {$define FPC_SYSTEM_HAS_ABS_LONGINT}
  355. function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif}nostackframe;
  356. asm
  357. sra $1,$4,31 // $at,$4,31
  358. xor $2,$4,$1 // $2,$4,$at
  359. sub $2,$2,$1 // $2,$2,$at
  360. end;
  361. var
  362. fpc_system_lock : longint; export name 'fpc_system_lock';
  363. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  364. function declocked(var l : longint) : boolean;assembler;nostackframe;
  365. { input: address of l in $4 }
  366. { output: boolean indicating whether l is zero after decrementing }
  367. asm
  368. sw $4,0($23)
  369. sw $5,-4($23)
  370. sw $6,-8($23)
  371. sw $7,-12($23)
  372. sw $8,-16($23)
  373. sw $9,-20($23)
  374. sw $10,-24($23)
  375. sw $11,-28($23)
  376. sw $12,-32($23)
  377. sw $13,-36($23)
  378. sw $14,-40($23)
  379. addiu $23,$23,-44
  380. .Ldeclocked1:
  381. lui $5,%hi(fpc_system_lock)
  382. addiu $5,$5,%lo(fpc_system_lock)
  383. ll $6,0($5)
  384. ori $7,$6,1
  385. beq $7,$6,.Ldeclocked1
  386. nop
  387. sc $7,0($5)
  388. beq $7,$0,.Ldeclocked1
  389. nop
  390. lw $5,0($4)
  391. addiu $5,$5,-1
  392. sw $5,0($4)
  393. seq $2,$5,$0
  394. { unlock }
  395. lui $5,%hi(fpc_system_lock)
  396. addiu $5,$5,%lo(fpc_system_lock)
  397. sw $0,0($5)
  398. addiu $23,$23,44
  399. lw $4,0($23)
  400. lw $5,-4($23)
  401. lw $6,-8($23)
  402. lw $7,-12($23)
  403. lw $8,-16($23)
  404. lw $9,-20($23)
  405. lw $10,-24($23)
  406. lw $11,-28($23)
  407. lw $12,-32($23)
  408. lw $13,-36($23)
  409. lw $14,-40($23)
  410. end;
  411. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  412. procedure inclocked(var l : longint);assembler;nostackframe;
  413. asm
  414. { usually, we shouldn't lock here so saving the stack frame for these extra intructions is
  415. worse the effort, especially while waiting :)
  416. }
  417. { unlock }
  418. sw $4,0($23)
  419. sw $5,-4($23)
  420. sw $6,-8($23)
  421. sw $7,-12($23)
  422. sw $8,-16($23)
  423. sw $9,-20($23)
  424. sw $10,-24($23)
  425. sw $11,-28($23)
  426. sw $12,-32($23)
  427. sw $13,-36($23)
  428. sw $14,-40($23)
  429. addiu $23,$23,-44
  430. .Ldeclocked1:
  431. lui $5,%hi(fpc_system_lock)
  432. addiu $5,$5,%lo(fpc_system_lock)
  433. ll $6,0($5)
  434. ori $7,$6,1
  435. beq $7,$6,.Ldeclocked1
  436. nop
  437. sc $7,0($5)
  438. beq $7,$0,.Ldeclocked1
  439. nop
  440. lw $5,0($4)
  441. addiu $5,$5,1
  442. sw $5,0($4)
  443. { unlock }
  444. lui $5,%hi(fpc_system_lock)
  445. addiu $5,$5,%lo(fpc_system_lock)
  446. sw $0,0($5)
  447. addiu $23,$23,44
  448. lw $4,0($23)
  449. lw $5,-4($23)
  450. lw $6,-8($23)
  451. lw $7,-12($23)
  452. lw $8,-16($23)
  453. lw $9,-20($23)
  454. lw $10,-24($23)
  455. lw $11,-28($23)
  456. lw $12,-32($23)
  457. lw $13,-36($23)
  458. lw $14,-40($23)
  459. end;
  460. {$endif def USE_MIPS_STK2_ASM}
  461. function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
  462. asm
  463. sync
  464. .L1:
  465. ll $v0,($a0)
  466. addiu $v1,$v0,-1
  467. move $v0,$v1 // must return value after decrement
  468. sc $v1,($a0)
  469. beq $v1,$0,.L1
  470. nop
  471. sync
  472. end;
  473. function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
  474. asm
  475. sync
  476. .L1:
  477. ll $v0,($a0)
  478. addiu $v1,$v0,1
  479. move $v0,$v1 // must return value after increment
  480. sc $v1,($a0)
  481. beq $v1,$0,.L1
  482. nop
  483. sync
  484. end;
  485. function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  486. asm
  487. sync
  488. .L1:
  489. ll $v0,($a0)
  490. move $v1,$a1
  491. sc $v1,($a0)
  492. beq $v1,$0,.L1
  493. nop
  494. sync
  495. end;
  496. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  497. asm
  498. sync
  499. .L1:
  500. ll $v0,($a0)
  501. addu $v1,$v0,$a1
  502. sc $v1,($a0)
  503. beq $v1,$0,.L1
  504. nop
  505. sync
  506. end;
  507. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
  508. asm
  509. sync
  510. .L1:
  511. ll $v0,($a0)
  512. bne $v0,$a2,.L2
  513. nop
  514. move $v1,$a1
  515. sc $v1,($a0)
  516. beq $v1,$0,.L1
  517. nop
  518. sync
  519. .L2:
  520. end;
  521. {$ifndef FPC_SYSTEM_HAS_SAR_QWORD}
  522. {$ifdef ENDIAN_BIG}
  523. {$define FPC_SYSTEM_HAS_SAR_QWORD}
  524. function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64; [Public,Alias:'FPC_SARINT64']; compilerproc; assembler; nostackframe;
  525. asm
  526. { $a0=high(AValue) $a1=low(AValue), result: $v0:$v1 }
  527. andi $a2,$a2,63
  528. sltiu $t0,$a2,32
  529. beq $t0,$0,.L1
  530. nop
  531. srlv $v1,$a1,$a2
  532. srav $v0,$a0,$a2
  533. beq $a2,$0,.Lexit
  534. nop
  535. subu $t0,$0,$a2
  536. sllv $t0,$a0,$t0
  537. or $v1,$v1,$t0
  538. b .Lexit
  539. nop
  540. .L1:
  541. sra $v0,$a0,31
  542. srav $v1,$a0,$a2
  543. .Lexit:
  544. end;
  545. {$endif ENDIAN_BIG}
  546. {$endif FPC_SYSTEM_HAS_SAR_QWORD}