mips.inc 12 KB

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