mips.inc 13 KB

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