3
This file is part of the Free Pascal run time library.
4
Copyright (c) 2000-2006 by the Free Pascal development team.
6
Portions Copyright (c) 2000 by Casey Duncan (casey.duncan@state.co.us)
8
Processor dependent implementation for the system unit for
11
See the file COPYING.FPC, included in this distribution,
12
for details about the copyright.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
**********************************************************************}
24
{****************************************************************************
25
PowerPC specific stuff
26
****************************************************************************}
30
ppc_fpu_overflow = (1 shl (32-3));
31
ppc_fpu_underflow = (1 shl (32-4));
32
ppc_fpu_divbyzero = (1 shl (32-5));
33
ppc_fpu_inexact = (1 shl (32-6));
34
ppc_fpu_invalid_snan = (1 shl (32-7));
37
procedure fpc_enable_ppc_fpu_exceptions;
38
assembler; nostackframe;
40
{ clear all "exception happened" flags we care about}
49
{ enable invalid operations and division by zero exceptions. }
50
{ No overflow/underflow, since those give some spurious }
56
procedure fpc_cpuinit;
58
fpc_enable_ppc_fpu_exceptions;
62
function fpc_get_ppc_fpscr: cardinal;
65
temp: record a,b:longint; end;
70
{ clear all exception flags }
79
{ This function is never called directly, it's a dummy to hold the register save/
121
procedure saverestorereg;assembler; nostackframe;
125
_restfpr_14_x: lfd f14, -144(r11)
127
_restfpr_15_x: lfd f15, -136(r11)
129
_restfpr_16_x: lfd f16, -128(r11)
131
_restfpr_17_x: lfd f17, -120(r11)
133
_restfpr_18_x: lfd f18, -112(r11)
135
_restfpr_19_x: lfd f19, -104(r11)
137
_restfpr_20_x: lfd f20, -96(r11)
139
_restfpr_21_x: lfd f21, -88(r11)
141
_restfpr_22_x: lfd f22, -80(r11)
143
_restfpr_23_x: lfd f23, -72(r11)
145
_restfpr_24_x: lfd f24, -64(r11)
147
_restfpr_25_x: lfd f25, -56(r11)
149
_restfpr_26_x: lfd f26, -48(r11)
151
_restfpr_27_x: lfd f27, -40(r11)
153
_restfpr_28_x: lfd f28, -32(r11)
155
_restfpr_29_x: lfd f29, -24(r11)
157
_restfpr_30_x: lfd f30, -16(r11)
159
_restfpr_31_x: lwz r0, 4(r11)
165
{ exit with restoring lr }
167
_restfpr_14_l: lfd f14, -144(r11)
169
_restfpr_15_l: lfd f15, -136(r11)
171
_restfpr_16_l: lfd f16, -128(r11)
173
_restfpr_17_l: lfd f17, -120(r11)
175
_restfpr_18_l: lfd f18, -112(r11)
177
_restfpr_19_l: lfd f19, -104(r11)
179
_restfpr_20_l: lfd f20, -96(r11)
181
_restfpr_21_l: lfd f21, -88(r11)
183
_restfpr_22_l: lfd f22, -80(r11)
185
_restfpr_23_l: lfd f23, -72(r11)
187
_restfpr_24_l: lfd f24, -64(r11)
189
_restfpr_25_l: lfd f25, -56(r11)
191
_restfpr_26_l: lfd f26, -48(r11)
193
_restfpr_27_l: lfd f27, -40(r11)
195
_restfpr_28_l: lfd f28, -32(r11)
197
_restfpr_29_l: lfd f29, -24(r11)
199
_restfpr_30_l: lfd f30, -16(r11)
201
_restfpr_31_l: lwz r0, 4(r11)
209
{****************************************************************************
211
****************************************************************************}
213
{$ifndef FPC_SYSTEM_HAS_MOVE}
214
{$define FPC_SYSTEM_HAS_MOVE}
215
procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler; nostackframe;
219
{ check if we have to do the move backwards because of overlap }
221
{ carry := boolean(dest-source < count) = boolean(overlap) }
224
{ count < 15 ? (to decide whether we will move dwords or bytes }
227
{ if overlap, then r10 := -1 else r10 := 0 }
230
{ count < 63 ? (32 + max. alignment (31) }
233
{ if count <= 0, stop }
236
{ load the begin of the source in the data cache }
238
{ and the dest as well }
241
{ if overlap, then r0 := count else r0 := 0 }
243
{ if overlap, then point source and dest to the end }
246
{ if overlap, then r6 := 0, else r6 := -1 }
248
{ if overlap, then r10 := -2, else r10 := 0 }
250
{ if overlap, then r10 := -1, else r10 := 1 }
253
{ if count < 15, copy everything byte by byte }
256
{ if no overlap, then source/dest += -1, otherwise they stay }
257
{ After the next instruction, r3/r4 + r10 = next position to }
258
{ load/store from/to }
262
{ otherwise, guarantee 4 byte alignment for dest for starters }
263
.LMove4ByteAlignLoop:
266
{ is dest now 4 aligned? }
269
{ while not aligned, continue }
270
bne cr0,.LMove4ByteAlignLoop
273
{ check for 32 byte alignment }
276
{ we are going to copy one byte again (the one at the newly }
277
{ aligned address), so increase count byte 1 }
279
{ count div 4 for number of dwords to copy }
281
{ if 11 <= count < 63, copy using dwords }
285
{ # of dwords to copy to reach 32 byte alignment (*4) }
286
{ (depends on forward/backward copy) }
288
{ if forward copy, r6 = -1 -> r8 := 32 }
289
{ if backward copy, r6 = 0 -> r8 := 0 }
290
rlwinm r8,r6,0,31-6+1,31-6+1
291
{ if forward copy, we have to copy 32 - unaligned count bytes }
292
{ if backward copy unaligned count bytes }
294
{ if backward copy, the calculated value is now negate -> }
295
{ make it positive again }
301
{ multiply the update count with 4 }
304
{ and adapt the source and dest }
309
beq cr0,.LMove32BytesAligned
310
.L32BytesAlignMoveLoop:
311
{ count >= 39 -> align to 8 byte boundary and then use the FPU }
312
{ since we're already at 4 byte alignment, use dword store }
317
bne .L32BytesAlignMoveLoop
319
.LMove32BytesAligned:
320
{ count div 32 ( >= 1, since count was >=63 }
324
{ to decide if we will do some dword stores (instead of only }
325
{ byte stores) afterwards or not }
333
{ r0 := count div 4, will be moved to ctr when copying dwords }
337
{ adjust the update count: it will now be 8 or -8 depending on overlap }
340
{ adjust source and dest pointers: because of the above loop, dest is now }
341
{ aligned to 8 bytes. So if we add r6 we will still have an 8 bytes }
348
{ the dcbz offset must give a 32 byte aligned address when added }
349
{ to the current dest address and its address must point to the }
350
{ bytes that will be overwritten in the current iteration. In case }
351
{ of a forward loop, the dest address has currently an offset of }
352
{ -8 compared to the bytes that will be overwritten (and r6 = -8). }
353
{ In case of a backward of a loop, the dest address currently has }
354
{ an offset of +32 compared to the bytes that will be overwritten }
355
{ (and r6 = 0). So the forward dcbz offset must become +8 and the }
356
{ backward -32 -> (-r6 * 5) - 32 gives the correct offset }
368
{ must be done only now, in case source and dest are less than }
376
bdnz .LMove32ByteDcbz
377
.LMove32ByteLoopDone:
388
bdnz .LMove16ByteLoop
391
{ cr0*4+eq is true if "count and 31" = 0 }
394
{ make r10 again -1 or 1, but first adjust source/dest pointers }
405
{ cr1 contains whether count <= 11 }
420
bdnz .LMoveDWordsLoop
423
{ make r10 again -1 or 1 }
438
{$endif FPC_SYSTEM_HAS_MOVE}
441
{$ifndef FPC_SYSTEM_HAS_FILLCHAR}
442
{$define FPC_SYSTEM_HAS_FILLCHAR}
444
Procedure FillChar(var x;count:longint;value:byte);assembler;
445
{ input: x in r3, count in r4, value in r5 }
447
{$ifndef FPC_ABI_AIX}
448
{ in the AIX ABI, we can use te red zone for temp storage, otherwise we have }
449
{ to explicitely allocate room }
460
{ less than 15 bytes? }
462
{ less than 64 bytes? }
464
{ fill r5 with ValueValueValueValue }
466
{ setup for aligning x to multiple of 4}
467
rlwinm r10,r3,0,31-2+1,31
469
ble cr6,.LFillCharDone
470
{ get the start of the data in the cache (and mark it as "will be }
474
blt cr7,.LFillCharVerySmall
475
{ just store 4 bytes instead of using a loop to align (there are }
476
{ plenty of other instructions now to keep the processor busy }
477
{ while it handles the (possibly unaligned) store) }
479
{ r3 := align(r3,4) }
481
{ decrease count with number of bytes already stored }
483
blt cr1,.LFillCharSmall
485
{ if we have to fill with 0 (which happens a lot), we can simply use }
486
{ dcbz for the most part, which is very fast, so make a special case }
490
{ align to a multiple of 32 (and immediately check whether we aren't }
491
{ already 32 byte aligned) }
492
rlwinm. r10,r3,0,31-5+1,31
493
{ setup r3 for using update forms of store instructions }
495
{ get number of bytes to store }
497
{ if already 32byte aligned, skip align loop }
498
beq .L32ByteAlignLoopDone
499
{ substract from the total count }
502
{ we were already aligned to 4 byres, so this will count down to }
506
bne .L32ByteAlignLoop
507
.L32ByteAlignLoopDone:
508
{ get the amount of 32 byte blocks }
510
{ and keep the rest in r4 (recording whether there is any rest) }
511
rlwinm. r4,r4,0,31-5+1,31
514
{ check how many rest there is (to decide whether we'll use }
515
{ FillCharSmall or FillCharVerySmall) }
518
{ if filling with zero, only use dcbz }
519
bne cr1, .LFillCharNoZero
520
{ make r3 point again to the actual store position }
525
bdnz .LFillCharDCBZLoop
526
{ if there was no rest, we're finished }
528
b .LFillCharVerySmall
540
{ make r3 point to address-8, so we're able to use fp double stores }
541
{ with update (it's already -4 now) }
544
{ load r10 with 8, so that dcbz uses the correct address }
547
.LFillChar32ByteLoop:
555
bdnz .LFillChar32ByteLoop
556
{ if there was no rest, we're finished }
558
{ make r3 point again to the actual next byte that must be written }
560
b .LFillCharVerySmall
562
{ when we arrive here, we're already 4 byte aligned }
563
{ get count div 4 to store dwords }
565
{ get ready for use of update stores }
568
rlwinm. r4,r4,0,31-2+1,31
571
bdnz .LFillCharSmallLoop
572
{ if nothing left, stop }
574
{ get ready to store bytes }
579
.LFillCharVerySmallLoop:
581
bdnz .LFillCharVerySmallLoop
584
{$endif FPC_SYSTEM_HAS_FILLCHAR}
587
{$ifndef FPC_SYSTEM_HAS_FILLDWORD}
588
{$define FPC_SYSTEM_HAS_FILLDWORD}
589
procedure filldword(var x;count : longint;value : dword);
590
assembler; nostackframe;
600
ble .LFillDWordEnd //if count<=0 Then Exit
606
{$endif FPC_SYSTEM_HAS_FILLDWORD}
609
{$ifndef FPC_SYSTEM_HAS_INDEXBYTE}
610
{$define FPC_SYSTEM_HAS_INDEXBYTE}
611
function IndexByte(const buf;len:longint;b:byte):longint; assembler; nostackframe;
612
{ input: r3 = buf, r4 = len, r5 = b }
613
{ output: r3 = position of b in buf (-1 if not found) }
615
{ load the begin of the buffer in the data cache }
627
bdnzf cr0*4+eq,.LIndexByteLoop
628
{ r3 still contains -1 here }
633
{$endif FPC_SYSTEM_HAS_INDEXBYTE}
636
{$ifndef FPC_SYSTEM_HAS_INDEXWORD}
637
{$define FPC_SYSTEM_HAS_INDEXWORD}
638
function IndexWord(const buf;len:longint;b:word):longint; assembler; nostackframe;
639
{ input: r3 = buf, r4 = len, r5 = b }
640
{ output: r3 = position of b in buf (-1 if not found) }
642
{ load the begin of the buffer in the data cache }
654
bdnzf cr0*4+eq,.LIndexWordLoop
655
{ r3 still contains -1 here }
661
{$endif FPC_SYSTEM_HAS_INDEXWORD}
664
{$ifndef FPC_SYSTEM_HAS_INDEXDWORD}
665
{$define FPC_SYSTEM_HAS_INDEXDWORD}
666
function IndexDWord(const buf;len:longint;b:DWord):longint; assembler; nostackframe;
667
{ input: r3 = buf, r4 = len, r5 = b }
668
{ output: r3 = position of b in buf (-1 if not found) }
670
{ load the begin of the buffer in the data cache }
682
bdnzf cr0*4+eq, .LIndexDWordLoop
683
{ r3 still contains -1 here }
689
{$endif FPC_SYSTEM_HAS_INDEXDWORD}
692
{$ifndef FPC_SYSTEM_HAS_COMPAREBYTE}
693
{$define FPC_SYSTEM_HAS_COMPAREBYTE}
694
function CompareByte(const buf1,buf2;len:longint):longint; assembler; nostackframe;
695
{ input: r3 = buf1, r4 = buf2, r5 = len }
696
{ output: r3 = 0 if equal, < 0 if buf1 < str2, > 0 if buf1 > str2 }
697
{ note: almost direct copy of strlcomp() from strings.inc }
699
{ load the begin of the first buffer in the data cache }
701
{ use r0 instead of r3 for buf1 since r3 contains result }
712
{ calculate difference }
714
{ if chars not equal or at the end, we're ready }
715
bdnzt cr0*4+eq, .LCompByteLoop
718
{$endif FPC_SYSTEM_HAS_COMPAREBYTE}
721
{$ifndef FPC_SYSTEM_HAS_COMPAREWORD}
722
{$define FPC_SYSTEM_HAS_COMPAREWORD}
723
function CompareWord(const buf1,buf2;len:longint):longint; assembler; nostackframe;
724
{ input: r3 = buf1, r4 = buf2, r5 = len }
725
{ output: r3 = 0 if equal, < 0 if buf1 < str2, > 0 if buf1 > str2 }
726
{ note: almost direct copy of strlcomp() from strings.inc }
728
{ load the begin of the first buffer in the data cache }
730
{ use r0 instead of r3 for buf1 since r3 contains result }
741
{ calculate difference }
743
{ if chars not equal or at the end, we're ready }
744
bdnzt cr0*4+eq, .LCompWordLoop
747
{$endif FPC_SYSTEM_HAS_COMPAREWORD}
750
{$ifndef FPC_SYSTEM_HAS_COMPAREDWORD}
751
{$define FPC_SYSTEM_HAS_COMPAREDWORD}
752
function CompareDWord(const buf1,buf2;len:longint):longint; assembler; nostackframe;
753
{ input: r3 = buf1, r4 = buf2, r5 = len }
754
{ output: r3 = 0 if equal, < 0 if buf1 < str2, > 0 if buf1 > str2 }
755
{ note: almost direct copy of strlcomp() from strings.inc }
757
{ load the begin of the first buffer in the data cache }
759
{ use r0 instead of r3 for buf1 since r3 contains result }
770
{ calculate difference }
772
{ if chars not equal or at the end, we're ready }
773
bdnzt cr0*4+eq, .LCompDWordLoop
776
{$endif FPC_SYSTEM_HAS_COMPAREDWORD}
779
{$ifndef FPC_SYSTEM_HAS_INDEXCHAR0}
780
{$define FPC_SYSTEM_HAS_INDEXCHAR0}
781
function IndexChar0(const buf;len:longint;b:Char):longint; assembler; nostackframe;
782
{ input: r3 = buf, r4 = len, r5 = b }
783
{ output: r3 = position of found position (-1 if not found) }
785
{ load the begin of the buffer in the data cache }
794
{ if yes, do nothing }
800
beq cr1,.LIndexChar0Done
801
bdnzf cr0*4+eq, .LIndexChar0Loop
806
{$endif FPC_SYSTEM_HAS_INDEXCHAR0}
809
{****************************************************************************
811
****************************************************************************}
813
{$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
814
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
815
function fpc_shortstr_to_shortstr(len:longint; const sstr: shortstring): shortstring; [public,alias: 'FPC_SHORTSTR_TO_SHORTSTR']; compilerproc;
816
assembler; nostackframe;
817
{ input: r3: pointer to result, r4: len, r5: sstr }
819
{ load length source }
821
{ load the begin of the dest buffer in the data cache }
824
{ put min(length(sstr),len) in r4 }
825
subfc r7,r10,r4 { r0 := r4 - r10 }
826
subfe r4,r4,r4 { if r3 >= r4 then r3' := 0 else r3' := -1 }
827
and r7,r7,r4 { if r3 >= r4 then r3' := 0 else r3' := r3-r10 }
828
add r4,r10,r7 { if r3 >= r4 then r3' := r10 else r3' := r3 }
831
{ put length in ctr }
834
beq .LShortStrCopyDone
838
bdnz .LShortStrCopyLoop
843
procedure fpc_shortstr_assign(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_ASSIGN'];
844
assembler; nostackframe;
845
{ input: r3: len, r4: sstr, r5: dstr }
847
{ load length source }
849
{ load the begin of the dest buffer in the data cache }
852
{ put min(length(sstr),len) in r3 }
853
subc r0,r3,r10 { r0 := r3 - r10 }
854
subfe r3,r3,r3 { if r3 >= r4 then r3' := 0 else r3' := -1 }
855
and r3,r0,r3 { if r3 >= r4 then r3' := 0 else r3' := r3-r10 }
856
add r3,r3,r10 { if r3 >= r4 then r3' := r10 else r3' := r3 }
859
{ put length in ctr }
862
beq .LShortStrCopyDone2
866
bdnz .LShortStrCopyLoop2
869
{$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
871
{$ifndef STR_CONCAT_PROCS}
874
{$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
875
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
877
function fpc_shortstr_concat(const s1, s2: shortstring): shortstring; compilerproc; [public, alias: 'FPC_SHORTSTR_CONCAT'];
878
{ expects that (r3) contains a pointer to the result r4 to s1, r5 to s2 }
887
{ length 255 for s1? }
891
{ calculate min(length(s2),255-length(s1)) }
892
subc r8,r7,r10 { r8 := r7 - r10 }
893
cror 4*6+2,4*1+2,4*7+2
894
subfe r7,r7,r7 { if r7 >= r10 then r7' := 0 else r7' := -1 }
896
and r7,r8,r7 { if r7 >= r10 then r7' := 0 else r7' := r7-r10 }
897
add r7,r7,r10 { if r7 >= r10 then r7' := r10 else r7' := r7 }
901
{ calculate length of final string }
904
beq cr7, .Lcopys1loopDone
911
beq cr6, .LconcatDone
917
{$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
920
{$ifndef FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
921
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
923
procedure fpc_shortstr_append_shortstr(var s1: shortstring; const s2: shortstring); compilerproc;
924
{ expects that results (r3) contains a pointer to the current string s1, r4 }
925
{ high(s1) and (r5) a pointer to the one that has to be concatenated }
926
assembler; nostackframe;
936
{ calculate min(length(s2),high(result)-length(result)) }
938
subc r8,r9,r10 { r8 := r9 - r10 }
939
cror 4*7+2,4*0+2,4*1+2
940
subfe r9,r9,r9 { if r9 >= r10 then r9' := 0 else r9' := -1 }
941
and r9,r8,r9 { if r9 >= r10 then r9' := 0 else r9' := r9-r10 }
942
add r9,r9,r10 { if r9 >= r10 then r9' := r10 else r9' := r9 }
944
{ calculate new length }
946
{ load value to copy in ctr }
950
{ go to last current character of result }
953
{ if nothing to do, exit }
954
beq cr7, .LShortStrAppendDone
956
.LShortStrAppendLoop:
959
bdnz .LShortStrAppendLoop
960
.LShortStrAppendDone:
962
{$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_APPEND_SHORTSTR}
964
{$endif STR_CONCAT_PROCS}
967
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
968
function fpc_shortstr_compare(const dstr,sstr:shortstring): longint; [public,alias:'FPC_SHORTSTR_COMPARE']; compilerproc;
975
{ save their difference for later and }
976
{ calculate min(length(sstr),length(dstr)) }
977
subfc r7,r10,r9 { r0 := r9 - r10 }
978
subfe r9,r9,r9 { if r9 >= r10 then r9' := 0 else r9' := -1 }
979
and r7,r7,r9 { if r9 >= r10 then r9' := 0 else r9' := r9-r8 }
980
add r9,r10,r7 { if r9 >= r10 then r9' := r10 else r9' := r9 }
982
{ first compare dwords (length/4) }
984
{ keep length mod 4 for the ends }
986
{ already check whether length mod 4 = 0 }
988
{ so we can load r3 with 0, in case the strings both have length 0 }
991
{ length div 4 in ctr for loop }
993
{ if length < 3, goto byte comparing }
994
beq LShortStrCompare1
995
{ setup for use of update forms of load/store with dwords }
998
LShortStrCompare4Loop:
1002
bdnzt cr0+eq,LShortStrCompare4Loop
1003
{ r3 contains result if we stopped because of "ne" flag }
1004
bne LShortStrCompareDone
1005
{ setup for use of update forms of load/store with bytes }
1009
{ if comparelen mod 4 = 0, skip this and return the difference in }
1011
beq cr1,LShortStrCompareLen
1013
LShortStrCompare1Loop:
1017
bdnzt cr0+eq,LShortStrCompare1Loop
1018
bne LShortStrCompareDone
1019
LShortStrCompareLen:
1020
{ also return result in flags, maybe we can use this in the CG }
1022
LShortStrCompareDone:
1027
{$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
1028
{$define FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
1029
function fpc_pchar_to_shortstr(p:pchar):shortstring;[public,alias:'FPC_PCHAR_TO_SHORTSTR']; compilerproc;
1030
assembler; nostackframe;
1031
{$include strpas.inc}
1032
{$endif FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
1035
{$ifndef FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
1036
{$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
1037
function fpc_pchar_length(p:pchar):longint;assembler;[public,alias:'FPC_PCHAR_LENGTH']; compilerproc; nostackframe;
1038
{$include strlen.inc}
1039
{$endif FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
1042
{$define FPC_SYSTEM_HAS_GET_FRAME}
1043
function get_frame:pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1045
{ all abi's I know use r1 as stack pointer }
1049
{NOTE: On MACOS, 68000 code might call powerpc code, through the MixedMode manager,
1050
(even in the OS in system 9). The pointer to the switching stack frame is then
1051
indicated by the first bit set to 1. This is checked below.}
1053
{Both routines below assumes that framebp is a valid framepointer or nil.}
1055
{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
1056
function get_caller_addr(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1059
beq .Lcaller_addr_invalid
1062
beq .Lcaller_addr_invalid
1064
rlwinm r4,r3,0,31,31
1066
bne cr0,.Lcaller_addr_invalid
1068
{$ifdef FPC_ABI_AIX}
1072
{$endif FPC_ABI_AIX}
1074
.Lcaller_addr_invalid:
1079
{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
1080
function get_caller_frame(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1083
beq .Lcaller_frame_invalid
1086
rlwinm r4,r3,0,31,31
1088
bne cr0,.Lcaller_frame_invalid
1091
.Lcaller_frame_invalid:
1095
{$define FPC_SYSTEM_HAS_ABS_LONGINT}
1096
function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1104
{****************************************************************************
1106
****************************************************************************}
1108
{$define FPC_SYSTEM_HAS_ODD_LONGINT}
1109
function odd(l:longint):boolean;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1111
rlwinm r3,r3,0,31,31
1115
{$define FPC_SYSTEM_HAS_SQR_LONGINT}
1116
function sqr(l:longint):longint;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1122
{$define FPC_SYSTEM_HAS_SPTR}
1123
Function Sptr : Pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif} nostackframe;
1129
{****************************************************************************
1131
****************************************************************************}
1133
{ int_str: generic implementation is used for now }
1136
{****************************************************************************
1138
****************************************************************************}
1140
{ do a thread save inc/dec }
1142
{$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
1143
function declocked(var l : longint) : boolean;assembler;nostackframe;
1144
{ input: address of l in r3 }
1145
{ output: boolean indicating whether l is zero after decrementing }
1151
bne- .LDecLockedLoop
1156
{$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
1157
procedure inclocked(var l : longint);assembler;nostackframe;
1163
bne- .LIncLockedLoop
1167
function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
1168
{ input: address of target in r3 }
1169
{ output: target-1 in r3 }
1170
{ side-effect: target := target-1 }
1172
.LInterLockedDecLoop:
1176
bne .LInterLockedDecLoop
1181
function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
1182
{ input: address of target in r3 }
1183
{ output: target+1 in r3 }
1184
{ side-effect: target := target+1 }
1186
.LInterLockedIncLoop:
1190
bne .LInterLockedIncLoop
1195
function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
1196
{ input: address of target in r3, source in r4 }
1197
{ output: target in r3 }
1198
{ side-effect: target := source }
1200
.LInterLockedXchgLoop:
1203
bne .LInterLockedXchgLoop
1208
function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
1210
.LInterLockedXchgAddLoop:
1214
bne .LInterLockedXchgAddLoop
1219
function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
1220
{ input: address of target in r3, newvalue in r4, comparand in r5 }
1221
{ output: value stored in target before entry of the function }
1222
{ side-effect: NewValue stored in target if (target = comparand) }
1224
.LInterlockedCompareExchangeLoop:
1233
bne .LInterlockedCompareExchangeLoop
1238
{ this is only required for MorphOS }
1239
{$define FPC_SYSTEM_HAS_SYSRESETFPU}
1240
procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
1241
var tmp: array[0..1] of dword;
1244
{ setting fpu to round to nearest mode }
1251
{ powerpc might use softfloat code }
1252
softfloat_exception_flags:=0;
1253
softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;