mips.inc 12 KB

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