mips.inc 13 KB

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