mips.inc 13 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. 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. {$define FPC_SYSTEM_HAS_GET_FRAME}
  62. function get_frame:pointer;assembler;nostackframe;
  63. asm
  64. { we need to use the information of the .pdr section to do this properly:
  65. 0 proc. start adress
  66. 4 regmask
  67. 8 reg. offset
  68. 12 fmask
  69. 16 foffset
  70. 20 frame size
  71. 24 stack reg
  72. 28 link reg
  73. Further, we need to know the pc
  74. }
  75. // lw $2,0($sp)
  76. move $2,$30
  77. end;
  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,addr : pointer);
  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. {$define FPC_SYSTEM_HAS_ABS_LONGINT}
  353. function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif}nostackframe;
  354. asm
  355. sra $1,$4,31 // $at,$4,31
  356. xor $2,$4,$1 // $2,$4,$at
  357. sub $2,$2,$1 // $2,$2,$at
  358. end;
  359. var
  360. fpc_system_lock : longint; export name 'fpc_system_lock';
  361. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  362. function declocked(var l : longint) : boolean;assembler;nostackframe;
  363. { input: address of l in $4 }
  364. { output: boolean indicating whether l is zero after decrementing }
  365. asm
  366. sw $4,0($23)
  367. sw $5,-4($23)
  368. sw $6,-8($23)
  369. sw $7,-12($23)
  370. sw $8,-16($23)
  371. sw $9,-20($23)
  372. sw $10,-24($23)
  373. sw $11,-28($23)
  374. sw $12,-32($23)
  375. sw $13,-36($23)
  376. sw $14,-40($23)
  377. addiu $23,$23,-44
  378. .Ldeclocked1:
  379. lui $5,%hi(fpc_system_lock)
  380. addiu $5,$5,%lo(fpc_system_lock)
  381. ll $6,0($5)
  382. ori $7,$6,1
  383. beq $7,$6,.Ldeclocked1
  384. nop
  385. sc $7,0($5)
  386. beq $7,$0,.Ldeclocked1
  387. nop
  388. lw $5,0($4)
  389. addiu $5,$5,-1
  390. sw $5,0($4)
  391. seq $2,$5,$0
  392. { unlock }
  393. lui $5,%hi(fpc_system_lock)
  394. addiu $5,$5,%lo(fpc_system_lock)
  395. sw $0,0($5)
  396. addiu $23,$23,44
  397. lw $4,0($23)
  398. lw $5,-4($23)
  399. lw $6,-8($23)
  400. lw $7,-12($23)
  401. lw $8,-16($23)
  402. lw $9,-20($23)
  403. lw $10,-24($23)
  404. lw $11,-28($23)
  405. lw $12,-32($23)
  406. lw $13,-36($23)
  407. lw $14,-40($23)
  408. end;
  409. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  410. procedure inclocked(var l : longint);assembler;nostackframe;
  411. asm
  412. { usually, we shouldn't lock here so saving the stack frame for these extra intructions is
  413. worse the effort, especially while waiting :)
  414. }
  415. { unlock }
  416. sw $4,0($23)
  417. sw $5,-4($23)
  418. sw $6,-8($23)
  419. sw $7,-12($23)
  420. sw $8,-16($23)
  421. sw $9,-20($23)
  422. sw $10,-24($23)
  423. sw $11,-28($23)
  424. sw $12,-32($23)
  425. sw $13,-36($23)
  426. sw $14,-40($23)
  427. addiu $23,$23,-44
  428. .Ldeclocked1:
  429. lui $5,%hi(fpc_system_lock)
  430. addiu $5,$5,%lo(fpc_system_lock)
  431. ll $6,0($5)
  432. ori $7,$6,1
  433. beq $7,$6,.Ldeclocked1
  434. nop
  435. sc $7,0($5)
  436. beq $7,$0,.Ldeclocked1
  437. nop
  438. lw $5,0($4)
  439. addiu $5,$5,1
  440. sw $5,0($4)
  441. { unlock }
  442. lui $5,%hi(fpc_system_lock)
  443. addiu $5,$5,%lo(fpc_system_lock)
  444. sw $0,0($5)
  445. addiu $23,$23,44
  446. lw $4,0($23)
  447. lw $5,-4($23)
  448. lw $6,-8($23)
  449. lw $7,-12($23)
  450. lw $8,-16($23)
  451. lw $9,-20($23)
  452. lw $10,-24($23)
  453. lw $11,-28($23)
  454. lw $12,-32($23)
  455. lw $13,-36($23)
  456. lw $14,-40($23)
  457. end;
  458. {$endif def USE_MIPS_STK2_ASM}
  459. function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
  460. asm
  461. {$warning FIXME: This implementation of InterLockedDecrement in not yet ThreadSafe }
  462. // must return value after decrement
  463. lw $v0,($a0)
  464. addi $v0,$v0,-1
  465. sw $v0,($a0)
  466. end;
  467. function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
  468. asm
  469. {$warning FIXME: This implementation of InterLockedIncrement in not yet ThreadSafe }
  470. // must return value after increment
  471. lw $v0,($a0)
  472. addi $v0,$v0,1
  473. sw $v0,($a0)
  474. end;
  475. function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  476. asm
  477. {$warning FIXME: This implementation of InterLockedExchange in not yet ThreadSafe }
  478. lw $v0,($a0)
  479. sw $a1,($a0)
  480. end;
  481. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  482. asm
  483. {$warning FIXME: This implementation of InterLockedExchangeAdd in not yet ThreadSafe }
  484. lw $v0,($a0)
  485. add $a1,$v0,$a1
  486. sw $a1,($a0)
  487. end;
  488. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
  489. asm
  490. {$warning FIXME: This implementation of InterLockedCompareAdd in not yet ThreadSafe }
  491. { put old value of Target into $v0, result register }
  492. lw $v0,($a0)
  493. { copy to t0 register }
  494. move $t0,$v0
  495. move $v1,$a2
  496. xor $t0,$t0,$v1
  497. beq $t0,$zero,.L1
  498. b .L2
  499. .L1:
  500. {store NewValue (in $a1) into Target in ($(a0)) }
  501. sw $a1,($a0)
  502. .L2:
  503. end;