mips.inc 12 KB

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