mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 13:38:31 +02:00
569 lines
13 KiB
PHP
569 lines
13 KiB
PHP
{
|
|
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2008 by the Free Pascal development team.
|
|
|
|
Processor dependent implementation for the system unit for
|
|
RiscV64
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
|
|
const
|
|
fpu_i = 1 shl 0;
|
|
fpu_u = 1 shl 1;
|
|
fpu_o = 1 shl 2;
|
|
fpu_z = 1 shl 3;
|
|
fpu_v = 1 shl 4;
|
|
|
|
|
|
function getrm: dword; nostackframe; assembler;
|
|
asm
|
|
movfcsr2gr $a0, $r3
|
|
srli.w $a0, $a0, 8
|
|
end;
|
|
|
|
|
|
procedure __setrm(val: dword); nostackframe; assembler;
|
|
asm
|
|
slli.w $a0, $a0, 8
|
|
movgr2fcsr $r3, $a0
|
|
end;
|
|
|
|
procedure setrm(val: dword);
|
|
begin
|
|
DefaultFPUControlWord.rndmode:=val;
|
|
__setrm(val);
|
|
end;
|
|
|
|
|
|
function getenables: dword; nostackframe; assembler;
|
|
asm
|
|
movfcsr2gr $a0, $r1
|
|
end;
|
|
|
|
|
|
procedure __setenables(enables : dword); nostackframe; assembler;
|
|
asm
|
|
movgr2fcsr $r1, $a0
|
|
end;
|
|
|
|
|
|
procedure setenables(enables : dword);
|
|
begin
|
|
DefaultFPUControlWord.cw:=enables;
|
|
__setenables(enables);
|
|
end;
|
|
|
|
|
|
function getcause: dword; nostackframe; assembler;
|
|
asm
|
|
movfcsr2gr $a0, $r2
|
|
srli.w $a0, $a0, 24
|
|
end;
|
|
|
|
|
|
procedure setcause(cause : dword); nostackframe; assembler;
|
|
asm
|
|
slli.w $a0, $a0, 24
|
|
movgr2fcsr $r2, $a0
|
|
end;
|
|
|
|
|
|
function GetNativeFPUControlWord: TNativeFPUControlWord;
|
|
begin
|
|
result.cw:=getenables;
|
|
result.rndmode:=getrm;
|
|
end;
|
|
|
|
|
|
procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
|
|
begin
|
|
setenables(cw.cw);
|
|
setrm(cw.rndmode);
|
|
end;
|
|
|
|
|
|
procedure RaisePendingExceptions;
|
|
var
|
|
cause : dword;
|
|
f: TFPUException;
|
|
begin
|
|
cause:=getcause;
|
|
if (cause and fpu_i) <> 0 then
|
|
float_raise(exPrecision);
|
|
if (cause and fpu_u) <> 0 then
|
|
float_raise(exUnderflow);
|
|
if (cause and fpu_o) <> 0 then
|
|
float_raise(exOverflow);
|
|
if (cause and fpu_z) <> 0 then
|
|
float_raise(exZeroDivide);
|
|
if (cause and fpu_v) <> 0 then
|
|
float_raise(exInvalidOp);
|
|
{ now the soft float exceptions }
|
|
for f in softfloat_exception_flags do
|
|
float_raise(f);
|
|
end;
|
|
|
|
|
|
procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
|
|
var
|
|
cause : dword;
|
|
begin
|
|
cause:=getcause;
|
|
{ check, if the exception is masked }
|
|
if ((cause and fpu_i) <> 0) and (exPrecision in softfloat_exception_mask) then
|
|
cause:=cause and not(fpu_i);
|
|
if ((cause and fpu_u) <> 0) and (exUnderflow in softfloat_exception_mask) then
|
|
cause:=cause and not(fpu_u);
|
|
if ((cause and fpu_o) <> 0) and (exOverflow in softfloat_exception_mask) then
|
|
cause:=cause and not(fpu_o);
|
|
if ((cause and fpu_z) <> 0) and (exZeroDivide in softfloat_exception_mask) then
|
|
cause:=cause and not(fpu_z);
|
|
if ((cause and fpu_v) <> 0) and (exInvalidOp in softfloat_exception_mask) then
|
|
cause:=cause and not(fpu_v);
|
|
setcause(cause);
|
|
if cause<>0 then
|
|
RaisePendingExceptions;
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_SYSINITFPU}
|
|
procedure SysInitFPU;
|
|
begin
|
|
setrm(0);
|
|
setcause(0);
|
|
setenables(fpu_z or fpu_v or fpu_o);
|
|
softfloat_exception_mask:=[exPrecision,exUnderflow];
|
|
softfloat_exception_flags:=[];
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
Math Routines
|
|
****************************************************************************}
|
|
|
|
{$define FPC_SYSTEM_HAS_SWAPENDIAN}
|
|
{TODO It may be better to use the inline method}
|
|
{signed 16bit}
|
|
function SwapEndian(const AValue: SmallInt): SmallInt;assembler; nostackframe;
|
|
asm
|
|
revb.2h $a0, $a0
|
|
ext.w.h $a0, $a0
|
|
end;
|
|
{unsigned 16bit}
|
|
function SwapEndian(const AValue: Word): Word;assembler; nostackframe;
|
|
asm
|
|
revb.2h $a0, $a0
|
|
bstrpick.d $a0, $a0, 15, 0
|
|
end;
|
|
|
|
{signed 32bit}
|
|
function SwapEndian(const AValue: LongInt): LongInt; assembler; nostackframe;
|
|
asm
|
|
revb.2w $a0, $a0
|
|
addi.w $a0, $a0, 0
|
|
end;
|
|
|
|
{unsigned 32bit}
|
|
function SwapEndian(const AValue: DWord): DWord; assembler; nostackframe;
|
|
asm
|
|
revb.2w $a0, $a0
|
|
bstrpick.d $a0, $a0, 31, 0
|
|
end;
|
|
|
|
{signed 64bit}
|
|
function SwapEndian(const AValue: Int64): Int64; assembler; nostackframe;
|
|
asm
|
|
revb.d $a0, $a0
|
|
end;
|
|
|
|
{unsigned 64bit}
|
|
function SwapEndian(const AValue: QWord): QWord; assembler; nostackframe;
|
|
asm
|
|
revb.d $a0, $a0
|
|
end;
|
|
{****************************************************************************
|
|
stack frame related stuff
|
|
****************************************************************************}
|
|
|
|
{$IFNDEF INTERNAL_BACKTRACE}
|
|
{$define FPC_SYSTEM_HAS_GET_FRAME}
|
|
function get_frame:pointer;assembler;nostackframe;
|
|
asm
|
|
ori $a0, $fp, 0
|
|
end;
|
|
{$ENDIF not INTERNAL_BACKTRACE}
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
|
|
function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler;
|
|
asm
|
|
ld.d $a0, $a0, -8
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
|
|
function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler;
|
|
asm
|
|
ld.d $a0, $a0, -16
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_SPTR}
|
|
Function Sptr : pointer;assembler;nostackframe;
|
|
asm
|
|
ori $a0, $sp, 0
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_DEC_32}
|
|
function fpc_atomic_dec_32 (var Target: longint) : longint; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
addi.w $a1, $zero, -1
|
|
amadd_db.w $a2, $a1, $a0
|
|
add.w $a0, $a1, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.w $a1, $a0, 0
|
|
addi.w $a2, $a1, -1
|
|
sc.w $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
addi.w $a0, $a1, -1
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_INC_32}
|
|
function fpc_atomic_inc_32 (var Target: longint) : longint; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
addi.w $a1, $zero, 1
|
|
amadd_db.w $a2, $a1, $a0
|
|
add.w $a0, $a1, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.w $a1, $a0, 0
|
|
addi.w $a2, $a1, 1
|
|
sc.w $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
addi.w $a0, $a1, 1
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_XCHG_32}
|
|
function fpc_atomic_xchg_32 (var Target: longint;Source : longint) : longint; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
dbar 0
|
|
.LLoop:
|
|
ll.w $a3, $a0, 0
|
|
ori $a2, $a1, 0
|
|
sc.w $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
ori $a0, $a3, 0
|
|
dbar 0
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_32}
|
|
function fpc_atomic_cmp_xchg_32 (var Target: longint; NewValue: longint; Comparand: longint) : longint; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
dbar 0
|
|
.LLoop:
|
|
ll.w $a3, $a0, 0
|
|
bne $a3, $a2, .LFail
|
|
ori $a4, $a1, 0
|
|
sc.w $a4, $a0, 0
|
|
beqz $a4, .LLoop
|
|
.LFail:
|
|
ori $a0, $a3, 0
|
|
dbar 0
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_ADD_32}
|
|
function fpc_atomic_add_32 (var Target: longint;Value : longint) : longint; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
amadd_db.w $a2, $a1, $a0
|
|
move $a0, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.w $a2, $a0, 0
|
|
add.w $a3, $a1, $a2
|
|
sc.w $a3, $a0, 0
|
|
beqz $a3, .LLoop
|
|
move $a0, $a2
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedDecrement64 (var Target: int64) : int64; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_DEC_64}
|
|
function fpc_atomic_dec_64 (var Target: int64) : int64; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
addi.d $a1, $zero, -1
|
|
amadd_db.d $a2, $a1, $a0
|
|
add.d $a0, $a1, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.d $a1, $a0, 0
|
|
addi.d $a2, $a1, -1
|
|
sc.d $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
addi.d $a0, $a1, -1
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedIncrement64 (var Target: int64) : int64; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_INC_64}
|
|
function fpc_atomic_inc_64 (var Target: int64) : int64; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
addi.d $a1, $zero, 1
|
|
amadd_db.d $a2, $a1, $a0
|
|
add.d $a0, $a1, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.d $a1, $a0, 0
|
|
addi.d $a2, $a1, 1
|
|
sc.d $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
addi.d $a0, $a1, 1
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchange64 (var Target: int64;Source : int64) : int64; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_XCHG_64}
|
|
function fpc_atomic_xchg_64 (var Target: int64;Source : int64) : int64; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
dbar 0
|
|
.LLoop:
|
|
ll.d $a3, $a0, 0
|
|
ori $a2, $a1, 0
|
|
sc.d $a2, $a0, 0
|
|
beqz $a2, .LLoop
|
|
ori $a0, $a3, 0
|
|
dbar 0
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_64}
|
|
function fpc_atomic_cmp_xchg_64 (var Target: int64; NewValue: int64; Comparand: int64) : int64; [public,alias:'FPC_ATOMIC_CMP_XCHG_64']; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
dbar 0
|
|
.LLoop:
|
|
ll.d $a3, $a0, 0
|
|
bne $a3, $a2, .LFail
|
|
ori $a4, $a1, 0
|
|
sc.d $a4, $a0, 0
|
|
beqz $a4, .LLoop
|
|
.LFail:
|
|
ori $a0, $a3, 0
|
|
dbar 0
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchangeAdd64 (var Target: int64;Source : int64) : int64; assembler; nostackframe;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_ADD_64}
|
|
function fpc_atomic_add_64 (var Target: int64;Value : int64) : int64; assembler; nostackframe;
|
|
{$endif VER3_2}
|
|
asm
|
|
{$ifdef CPULOONGARCH_HAS_ATOMIC}
|
|
amadd_db.d $a2, $a1, $a0
|
|
add.d $a0, $a1, $a2
|
|
{$else CPULOONGARCH_HAS_ATOMIC}
|
|
dbar 0
|
|
.LLoop:
|
|
ll.d $a2, $a0, 0
|
|
add.d $a3, $a1, $a2
|
|
sc.d $a3, $a0, 0
|
|
beqz $a3, .LLoop
|
|
add.d $a0, $a1, $a2
|
|
dbar 0
|
|
{$endif CPULOONGARCH_HAS_ATOMIC}
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
|
|
function declocked(var l: longint) : boolean; inline;
|
|
begin
|
|
Result:=InterLockedDecrement(l) = 0;
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
|
|
procedure inclocked(var l: longint); inline;
|
|
begin
|
|
InterLockedIncrement(l);
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_DECLOCKED_INT64}
|
|
function declocked(var l:int64):boolean;
|
|
begin
|
|
Result:=InterLockedDecrement64(l) = 0;
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_INCLOCKED_INT64}
|
|
procedure inclocked(var l:int64);
|
|
begin
|
|
InterLockedIncrement64(l);
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_MEM_BARRIER}
|
|
|
|
procedure ReadBarrier; assembler; nostackframe;
|
|
asm
|
|
dbar 0
|
|
end;
|
|
|
|
|
|
procedure ReadDependencyBarrier;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
begin
|
|
end;
|
|
|
|
procedure ReadWriteBarrier; assembler; nostackframe;
|
|
asm
|
|
dbar 0
|
|
end;
|
|
|
|
procedure WriteBarrier; assembler; nostackframe;
|
|
asm
|
|
dbar 0
|
|
end;
|
|
|
|
{$ifndef FPC_SYSTEM_HAS_MOVE}
|
|
{$define FPC_SYSTEM_HAS_MOVE}
|
|
procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE']; assembler; nostackframe;
|
|
asm
|
|
blez $a2, .Lret
|
|
beq $a0, $a1, .Lret
|
|
|
|
move $t0, $a0
|
|
add.d $t1, $a1, $a2
|
|
bgt $t0, $t1, .Lprefast_tail
|
|
sub.d $t1, $a1, $a2
|
|
blt $t0, $t1, .Lprefast_tail
|
|
bgt $a0, $a1, .Lgeneric_head
|
|
|
|
add.d $a0, $a0, $a2
|
|
add.d $a1, $a1, $a2
|
|
.Lgeneric_tail:
|
|
ld.b $t0, $a0, -1
|
|
st.b $t0, $a1, -1
|
|
addi.d $a0, $a0, -1
|
|
addi.d $a1, $a1, -1
|
|
addi.d $a2, $a2, -1
|
|
bgtz $a2, .Lgeneric_tail
|
|
b .Lret
|
|
|
|
.Lgeneric_head:
|
|
ld.b $t0, $a0, 0
|
|
st.b $t0, $a1, 0
|
|
addi.d $a0, $a0, 1
|
|
addi.d $a1, $a1, 1
|
|
addi.d $a2, $a2, -1
|
|
bgtz $a2, .Lgeneric_head
|
|
b .Lret
|
|
|
|
.Lprefast_tail:
|
|
add.d $a0, $a0, $a2
|
|
add.d $a1, $a1, $a2
|
|
ori $a3, $zero, 64
|
|
blt $a2, $a3, .Lgeneric_tail
|
|
.Lfast_tail:
|
|
ld.d $t0, $a0, -8
|
|
ld.d $t1, $a0, -16
|
|
ld.d $t2, $a0, -24
|
|
ld.d $t3, $a0, -32
|
|
ld.d $t4, $a0, -40
|
|
ld.d $t5, $a0, -48
|
|
ld.d $t6, $a0, -56
|
|
ld.d $t7, $a0, -64
|
|
st.d $t0, $a1, -8
|
|
st.d $t1, $a1, -16
|
|
st.d $t2, $a1, -24
|
|
st.d $t3, $a1, -32
|
|
st.d $t4, $a1, -40
|
|
st.d $t5, $a1, -48
|
|
st.d $t6, $a1, -56
|
|
st.d $t7, $a1, -64
|
|
addi.d $a0, $a0, -64
|
|
addi.d $a1, $a1, -64
|
|
addi.d $a2, $a2, -64
|
|
bge $a2, $a3, .Lfast_tail
|
|
bnez $a2, .Lgeneric_tail
|
|
|
|
.Lret:
|
|
jr $ra
|
|
end;
|
|
{$endif ndef FPC_SYSTEM_HAS_MOVE}
|
|
|
|
{$define FPC_SYSTEM_HAS_SYSRESETFPU}
|
|
procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
begin
|
|
softfloat_exception_flags:=[];
|
|
softfloat_exception_mask:=[exPrecision,exUnderflow];
|
|
{$ifdef FPUFD}
|
|
SetNativeFPUControlWord(DefaultFPUControlWord);
|
|
{$endif}
|
|
end;
|