mips.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  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. {$if defined(FPUMIPS2) or defined(FPUMIPS3)}
  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 FPUMIPS2 or FPUMIPS3}
  55. procedure fpc_cpuinit;
  56. begin
  57. {$ifndef FPUNONE}
  58. SysResetFPU;
  59. if (not IsLibrary) then
  60. SysInitFPU;
  61. {$endif FPUNONE}
  62. end;
  63. {$ifndef INTERNAL_BACKTRACE}
  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. {$endif INTERNAL_BACKTRACE}
  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 : pointer; var addr : codepointer);
  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. {$ifndef FPC_SYSTEM_HAS_FILLCHAR}
  180. {$define FPC_SYSTEM_HAS_FILLCHAR}
  181. procedure FillChar(var x;count:SizeInt;value:byte);assembler;nostackframe;
  182. // x=$a0, count=$a1, value=$a2
  183. // $t0 and $t1 used as temps
  184. asm
  185. // correctness of this routine depends on instructions in delay slots!!
  186. slti $t1, $a1, 8
  187. bne $t1, $0, .Lless8
  188. andi $a2, 0xff
  189. beq $a2, $0, .L1 // if value is zero, expansion can be skipped
  190. sll $t1, $a2, 8
  191. or $a2, $t1
  192. sll $t1, $a2, 16
  193. or $a2, $t1
  194. .L1:
  195. subu $t1, $0, $a0 // negate
  196. andi $t1, 3 // misalignment 0..3
  197. beq $t1, $0, .L2
  198. subu $a1, $t1 // decrease count (if branching, this is no-op because $t1=0)
  199. {$ifdef ENDIAN_BIG}
  200. swl $a2, 0($a0)
  201. {$else ENDIAN_BIG}
  202. swr $a2, 0($a0)
  203. {$endif ENDIAN_BIG}
  204. addu $a0, $t1 // add misalignment to address, making it dword-aligned
  205. .L2:
  206. andi $t1, $a1, 7 // $t1=count mod 8
  207. beq $t1, $a1, .L3 // (count and 7)=count => (count and (not 7))=0
  208. subu $t0, $a1, $t1 // $t0=count div 8
  209. addu $t0, $a0 // $t0=last loop address
  210. move $a1, $t1
  211. .Lloop8: // do 2 dwords per iteration
  212. addiu $a0, 8
  213. sw $a2, -8($a0)
  214. bne $a0, $t0, .Lloop8
  215. sw $a2, -4($a0)
  216. .L3:
  217. andi $t1, $a1, 4 // handle a single dword separately
  218. beq $t1, $0, .Lless8
  219. subu $a1, $t1
  220. sw $a2, 0($a0)
  221. addiu $a0, 4
  222. .Lless8:
  223. ble $a1, $0, .Lexit
  224. addu $t0, $a1, $a0
  225. .L4:
  226. addiu $a0, 1
  227. bne $a0, $t0, .L4
  228. sb $a2, -1($a0)
  229. .Lexit:
  230. end;
  231. {$endif FPC_SYSTEM_HAS_FILLCHAR}
  232. {$ifdef USE_MIPS_STK2_ASM}
  233. {$ifndef FPC_SYSTEM_HAS_MOVE}
  234. (* Disabled for now
  235. {$define FPC_SYSTEM_HAS_MOVE}
  236. procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler;
  237. asm
  238. {
  239. Registers:
  240. $7 temp. to do copying
  241. $8 inc/decrement
  242. $9/l0/l1/l2 qword move
  243. }
  244. sw $4,0($23)
  245. sw $5,-4($23)
  246. sw $6,-8($23)
  247. sw $7,-12($23)
  248. sw $8,-16($23)
  249. sw $9,-20($23)
  250. sw $10,-24($23)
  251. sw $11,-28($23)
  252. sw $12,-32($23)
  253. sw $13,-36($23)
  254. sw $14,-40($23)
  255. addiu $23,$23,-44
  256. // count <= 0 ?
  257. ble $6,$0,.Lmoveexit
  258. nop
  259. // source = dest ?
  260. beq $4,$5,.Lmoveexit
  261. nop
  262. // possible overlap?
  263. bgt $4,$5,.Lnopossibleoverlap
  264. nop
  265. // source < dest ....
  266. addu $7,$6,$4
  267. // overlap?
  268. // source+count < dest ?
  269. blt $7,$5,.Lnopossibleoverlap
  270. nop
  271. .Lcopybackward:
  272. // check alignment of source and dest
  273. or $2,$4,$5
  274. // move src and dest to the end of the blocks
  275. // assuming 16 byte block size
  276. addiu $3,$6,-1
  277. addu $4,$4,$3
  278. addu $5,$5,$3
  279. b .Lmovebytewise
  280. li $3,-1
  281. .Lnopossibleoverlap:
  282. // check alignment of source and dest
  283. or $2,$4,$5
  284. // everything 16 byte aligned ?
  285. andi $13,$2,15
  286. beq $13,$0,.Lmovetwordwise
  287. // load direction in delay slot
  288. li $3,16
  289. andi $13,$2,7
  290. beq $13,$0,.Lmoveqwordwise
  291. li $3,8
  292. andi $13,$2,3
  293. beq $13,$0,.Lmovedwordwise
  294. li $3,4
  295. andi $13,$2,1
  296. beq $13,$0,.Lmovewordwise
  297. li $3,2
  298. b .Lmovebytewise
  299. li $3,1
  300. .Lmovetwordwise:
  301. srl $13,$6,4
  302. sll $14,$13,4
  303. beq $14,$0,.Lmoveqwordwise_shift
  304. nop
  305. .Lmovetwordwise_loop:
  306. lw $9,0($4)
  307. lw $10,4($4)
  308. addiu $13,$13,-1
  309. lw $11,8($4)
  310. lw $12,12($4)
  311. addu $4,$4,$3
  312. sw $9,0($5)
  313. sw $10,4($5)
  314. sw $11,8($5)
  315. sw $12,12($5)
  316. addu $5,$5,$3
  317. bne $13,$0,.Lmovetwordwise_loop
  318. nop
  319. subu $6,$6,$14
  320. beq $6,$0,.Lmoveexit
  321. nop
  322. .Lmoveqwordwise_shift:
  323. sra $3,$3,1
  324. .Lmoveqwordwise:
  325. srl $13,$6,3
  326. sll $14,$13,3
  327. beq $14,$0,.Lmovedwordwise_shift
  328. nop
  329. .Lmoveqwordwise_loop:
  330. lw $9,0($4)
  331. lw $10,4($4)
  332. addiu $13,$13,-1
  333. addu $4,$3,$4
  334. sw $9,0($5)
  335. sw $10,4($5)
  336. addu $5,$3,$5
  337. bne $13,$0,.Lmoveqwordwise_loop
  338. nop
  339. subu $6,$6,$14
  340. beq $6,$0,.Lmoveexit
  341. nop
  342. .Lmovedwordwise_shift:
  343. sra $3,$3,1
  344. .Lmovedwordwise:
  345. srl $13,$6,2
  346. sll $14,$13,2
  347. beq $14,$0,.Lmovewordwise_shift
  348. nop
  349. .Lmovedwordwise_loop:
  350. lw $9,0($4)
  351. addiu $13,$13,-1
  352. addu $4,$4,$3
  353. sw $9,0($5)
  354. addu $5,$5,$3
  355. bne $13,$0,.Lmovedwordwise_loop
  356. nop
  357. subu $6,$6,$14
  358. beq $6,$0,.Lmoveexit
  359. nop
  360. .Lmovewordwise_shift:
  361. sra $3,$3,1
  362. .Lmovewordwise:
  363. srl $13,$6,1
  364. sll $14,$13,1
  365. beq $14,$0, .Lmovebytewise_shift
  366. nop
  367. .Lmovewordwise_loop:
  368. lhu $9,0($4)
  369. addiu $13,$13,-1
  370. addu $4,$4,$3
  371. sh $9,0($5)
  372. addu $5,$5,$3
  373. bne $13,$0,.Lmovewordwise_loop
  374. nop
  375. subu $6,$6,$14
  376. beq $6,$0, .Lmoveexit
  377. nop
  378. .Lmovebytewise_shift:
  379. sra $3,$3,1
  380. .Lmovebytewise:
  381. beq $6,$0, .Lmoveexit
  382. nop
  383. lbu $9,0($4)
  384. addiu $6,$6,-1
  385. addu $4,$4,$3
  386. sb $9,0($5)
  387. addu $5,$5,$3
  388. bne $6,$0,.Lmovebytewise
  389. nop
  390. .Lmoveexit:
  391. addiu $23,$23,44
  392. lw $4,0($23)
  393. lw $5,-4($23)
  394. lw $6,-8($23)
  395. lw $7,-12($23)
  396. lw $8,-16($23)
  397. lw $9,-20($23)
  398. lw $10,-24($23)
  399. lw $11,-28($23)
  400. lw $12,-32($23)
  401. lw $13,-36($23)
  402. lw $14,-40($23)
  403. end;
  404. *)
  405. {$endif FPC_SYSTEM_HAS_MOVE}
  406. {$endif def USE_MIPS_STK2_ASM}
  407. {$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
  408. function declocked(var l: longint) : boolean; inline;
  409. begin
  410. Result:=InterLockedDecrement(l) = 0;
  411. end;
  412. {$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
  413. procedure inclocked(var l: longint); inline;
  414. begin
  415. InterLockedIncrement(l);
  416. end;
  417. function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
  418. asm
  419. sync
  420. .L1:
  421. ll $v0,($a0)
  422. addiu $v1,$v0,-1
  423. move $v0,$v1 // must return value after decrement
  424. sc $v1,($a0)
  425. beq $v1,$0,.L1
  426. nop
  427. sync
  428. end;
  429. function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
  430. asm
  431. sync
  432. .L1:
  433. ll $v0,($a0)
  434. addiu $v1,$v0,1
  435. move $v0,$v1 // must return value after increment
  436. sc $v1,($a0)
  437. beq $v1,$0,.L1
  438. nop
  439. sync
  440. end;
  441. function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  442. asm
  443. sync
  444. .L1:
  445. ll $v0,($a0)
  446. move $v1,$a1
  447. sc $v1,($a0)
  448. beq $v1,$0,.L1
  449. nop
  450. sync
  451. end;
  452. function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
  453. asm
  454. sync
  455. .L1:
  456. ll $v0,($a0)
  457. addu $v1,$v0,$a1
  458. sc $v1,($a0)
  459. beq $v1,$0,.L1
  460. nop
  461. sync
  462. end;
  463. function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
  464. asm
  465. sync
  466. .L1:
  467. ll $v0,($a0)
  468. bne $v0,$a2,.L2
  469. nop
  470. move $v1,$a1
  471. sc $v1,($a0)
  472. beq $v1,$0,.L1
  473. nop
  474. sync
  475. .L2:
  476. end;
  477. {$ifndef FPC_SYSTEM_HAS_SAR_QWORD}
  478. {$ifdef ENDIAN_BIG}
  479. {$define FPC_SYSTEM_HAS_SAR_QWORD}
  480. function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64; [Public,Alias:'FPC_SARINT64']; compilerproc; assembler; nostackframe;
  481. asm
  482. { $a0=high(AValue) $a1=low(AValue), result: $v0:$v1 }
  483. andi $a2,$a2,63
  484. sltiu $t0,$a2,32
  485. beq $t0,$0,.L1
  486. nop
  487. srlv $v1,$a1,$a2
  488. srav $v0,$a0,$a2
  489. beq $a2,$0,.Lexit
  490. nop
  491. subu $t0,$0,$a2
  492. sllv $t0,$a0,$t0
  493. or $v1,$v1,$t0
  494. b .Lexit
  495. nop
  496. .L1:
  497. sra $v0,$a0,31
  498. srav $v1,$a0,$a2
  499. .Lexit:
  500. end;
  501. {$endif ENDIAN_BIG}
  502. {$endif FPC_SYSTEM_HAS_SAR_QWORD}