diff --git a/rtl/m68k/m68k.inc b/rtl/m68k/m68k.inc index 02cc70dc54..57349b8ea4 100644 --- a/rtl/m68k/m68k.inc +++ b/rtl/m68k/m68k.inc @@ -376,3 +376,176 @@ function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comp if Target = Comperand then Target := NewValue; end; + +{$if defined(CPUM68K_HAS_BYTEREV) or defined(CPUM68K_HAS_ROLROR)} +{ Disabled for now, because not all cases below were tested. (KB) } +{.$define FPC_SYSTEM_HAS_SWAPENDIAN} +{$endif} + +{$if defined(FPC_SYSTEM_HAS_SWAPENDIAN)} +function SwapEndian(const AValue: SmallInt): SmallInt; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.w avalue, d0 + ror.w #8, d0 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.w avalue, d0 + byterev d0 + swap d0 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + clr.l d0 + move.w avalue, d0 + move.w d0, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 +{$endif} +end; + + +function SwapEndian(const AValue: Word): Word; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.w avalue, d0 + ror.w #8, d0 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.w avalue, d0 + byterev d0 + swap d0 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + clr.l d0 + move.w avalue, d0 + move.w d0, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 +{$endif} +end; + + +function SwapEndian(const AValue: LongInt): LongInt; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.l avalue, d0 + ror.w #8, d0 + swap d0 + ror.w #8, d0 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.l avalue, d0 + byterev d0 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + move.l avalue, d0 + move.l d0, d1 + andi.l #$ff00ff00, d0 + andi.l #$00ff00ff, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 + swap d0 +{$endif} +end; + +function SwapEndian(const AValue: DWord): DWord; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.l avalue, d0 + ror.w #8, d0 + swap d0 + ror.w #8, d0 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.l avalue, d0 + byterev d0 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + move.l avalue, d0 + move.l d0, d1 + andi.l #$ff00ff00, d0 + andi.l #$00ff00ff, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 + swap d0 +{$endif} +end; + +function SwapEndian(const AValue: Int64): Int64; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.l avalue+4, d0 + ror.w #8, d0 + swap d0 + ror.w #8, d0 + move.l avalue, d1 + ror.w #8, d1 + swap d1 + ror.w #8, d1 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.l avalue+4, d0 + move.l avalue, d1 + byterev d0 + byterev d1 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + move.l d2, -(sp) + move.l avalue+4, d0 + move.l d0, d1 + andi.l #$ff00ff00, d0 + andi.l #$00ff00ff, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 + swap d0 + move.l avalue, d1 + move.l d1, d2 + andi.l #$ff00ff00, d1 + andi.l #$00ff00ff, d2 + lsr.l #8, d1 + lsl.l #8, d2 + or.l d2, d1 + swap d1 + move.l (sp)+, d2 +{$endif} +end; + +function SwapEndian(const AValue: QWord): QWord; assembler; nostackframe; +asm +{$if defined(CPUM68K_HAS_ROLROR)} + move.l avalue+4, d0 + ror.w #8, d0 + swap d0 + ror.w #8, d0 + move.l avalue, d1 + ror.w #8, d1 + swap d1 + ror.w #8, d1 +{$elseif defined(CPUM68K_HAS_BYTEREV)} + move.l avalue+4, d0 + move.l avalue, d1 + byterev d0 + byterev d1 +{$else} + // only ISA A/B ColdFire can end in this branch, so use long ops everywhere + move.l d2, -(sp) + move.l avalue+4, d0 + move.l d0, d1 + andi.l #$ff00ff00, d0 + andi.l #$00ff00ff, d1 + lsr.l #8, d0 + lsl.l #8, d1 + or.l d1, d0 + swap d0 + move.l avalue, d1 + move.l d1, d2 + andi.l #$ff00ff00, d1 + andi.l #$00ff00ff, d2 + lsr.l #8, d1 + lsl.l #8, d2 + or.l d2, d1 + swap d1 + move.l (sp)+, d2 +{$endif} +end; +{$endif FPC_SYSTEM_HAS_SWAPENDIAN}