mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 10:28:16 +02:00
396 lines
9.4 KiB
PHP
396 lines
9.4 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
|
|
AVR
|
|
|
|
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.
|
|
|
|
**********************************************************************}
|
|
|
|
{$asmmode gas}
|
|
|
|
const
|
|
{$i cpuinnr.inc}
|
|
|
|
{ Reads SREG and then disables interrupts, returns contents of SREG }
|
|
function avr_save: byte;[INTERNPROC: in_avr_save];
|
|
{ Restores SREG }
|
|
procedure avr_restore(old_sreg: byte); [INTERNPROC: in_avr_restore];
|
|
|
|
{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
|
|
procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
begin
|
|
end;
|
|
|
|
|
|
{$if not(defined(CPUAVR_16_REGS)) and defined(CPUAVR_HAS_MOVW)}
|
|
{$define FPC_SYSTEM_HAS_MOVE}
|
|
procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE']; assembler; nostackframe;
|
|
asm
|
|
push r28
|
|
push r29
|
|
|
|
movw r26, r24 // Src=X
|
|
movw r28, r22 // Dest=Y
|
|
movw r30, r20 // Count=Z
|
|
cp r1, r30
|
|
cpc r1, r31
|
|
brge .Lexit // if 0 >= Count
|
|
cp r28, r26
|
|
cpc r29, r27
|
|
breq .Lexit // if dest = source
|
|
brlo .LForwardMove // if dest < source
|
|
|
|
// Add count to both pointers
|
|
add r26, r30
|
|
adc r27, r31
|
|
add r28, r30
|
|
adc r29, r31
|
|
.LBackwardMove:
|
|
ld r18, -X
|
|
st -Y, r18
|
|
sbiw r30, 1
|
|
brne .LBackwardMove
|
|
rjmp .Lexit
|
|
|
|
.LForwardMove:
|
|
ld r18, X+
|
|
st Y+, r18
|
|
sbiw r30, 1
|
|
brne .LForwardMove
|
|
.Lexit:
|
|
|
|
pop r29
|
|
pop r28
|
|
end;
|
|
{$endif not(defined(CPUAVR_16_REGS)) and defined(CPUAVR_HAS_MOVW)}
|
|
|
|
{$define FPC_SYSTEM_HAS_FILLCHAR}
|
|
Procedure FillChar(var x;count:SizeInt;value:byte);
|
|
var
|
|
pdest,pend : pbyte;
|
|
v : ptruint;
|
|
begin
|
|
if count <= 0 then
|
|
exit;
|
|
pdest:=@x;
|
|
pend:=pdest+count;
|
|
while pdest<pend do
|
|
begin
|
|
pdest^:=value;
|
|
inc(pdest);
|
|
end;
|
|
end;
|
|
|
|
|
|
{$IFNDEF INTERNAL_BACKTRACE}
|
|
{$define FPC_SYSTEM_HAS_GET_FRAME}
|
|
{ this is never going to work on avr properly this way, so inline and return nil so the compiler
|
|
can optimize it }
|
|
function get_frame:pointer;inline;
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
{$ENDIF not INTERNAL_BACKTRACE}
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
|
|
{ this is never going to work on avr properly this way, so inline and return nil so the compiler
|
|
can optimize it }
|
|
function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;inline;
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
|
|
{ this is never going to work on avr properly this way, so inline and return nil so the compiler
|
|
can optimize it }
|
|
function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;inline;
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_SPTR}
|
|
Function Sptr : pointer;assembler;nostackframe;
|
|
asm
|
|
in r24, 0x3d
|
|
in r25, 0x3e
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedDecrement (var Target: longint) : longint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_DEC_32}
|
|
function fpc_atomic_dec_32 (var Target: longint) : longint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target-1;
|
|
Target:=Result;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedIncrement (var Target: longint) : longint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_INC_32}
|
|
function fpc_atomic_inc_32 (var Target: longint) : longint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target+1;
|
|
Target:=Result;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchange (var Target: longint;Source : longint) : longint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_XCHG_32}
|
|
function fpc_atomic_xchg_32 (var Target: longint;Source : longint) : longint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
Target:=Source;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint;
|
|
{$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;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
if Result={$ifdef VER3_2}Comperand{$else}Comparand{$endif} then
|
|
Target:=NewValue;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_ADD_32}
|
|
function fpc_atomic_add_32 (var Target: longint;Value : longint) : longint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
Target:=Result+{$ifdef VER3_2}Source{$else}Value{$endif};
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedDecrement (var Target: smallint) : smallint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_DEC_16}
|
|
function fpc_atomic_dec_16 (var Target: smallint) : smallint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target-1;
|
|
Target:=Result;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedIncrement (var Target: smallint) : smallint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_INC_16}
|
|
function fpc_atomic_inc_16 (var Target: smallint) : smallint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target+1;
|
|
Target:=Result;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchange (var Target: smallint;Source : smallint) : smallint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_XCHG_16}
|
|
function fpc_atomic_xchg_16 (var Target: smallint;Source : smallint) : smallint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
Target:=Source;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterlockedCompareExchange(var Target: smallint; NewValue: smallint; Comperand: smallint): smallint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_16}
|
|
function fpc_atomic_cmp_xchg_16 (var Target: smallint; NewValue: smallint; Comparand: smallint) : smallint; [public,alias:'FPC_ATOMIC_CMP_XCHG_16'];
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
if Result={$ifdef VER3_2}Comperand{$else}Comparand{$endif} then
|
|
Target:=NewValue;
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
|
|
{$ifdef VER3_2}
|
|
function InterLockedExchangeAdd (var Target: smallint;Source : smallint) : smallint;
|
|
{$else VER3_2}
|
|
{$define FPC_SYSTEM_HAS_ATOMIC_ADD_16}
|
|
function fpc_atomic_add_16 (var Target: smallint;Value : smallint) : smallint;
|
|
{$endif VER3_2}
|
|
var
|
|
temp_sreg : byte;
|
|
begin
|
|
{ block interrupts }
|
|
temp_sreg:=avr_save();
|
|
|
|
Result:=Target;
|
|
Target:=Result+{$ifdef VER3_2}Source{$else}Value{$endif};
|
|
|
|
{ release interrupts }
|
|
avr_restore(temp_sreg);
|
|
end;
|
|
|
|
{$define FPC_HAS_SHORTSTR_SHORTSTR_INTERN_CHARMOVE}
|
|
procedure fpc_shortstr_shortstr_intern_charmove(const src: shortstring; const srcindex: byte; var dst: shortstring; const dstindex, len: byte); {$ifdef SYSTEMINLINE}inline;{$endif}
|
|
begin
|
|
move(src[srcindex],dst[dstindex],len);
|
|
end;
|
|
|
|
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT_MULTI}
|
|
procedure fpc_shortstr_concat_multi(var dests:shortstring;const sarr:array of pshortstring);compilerproc;
|
|
var
|
|
s2l, tmpindex : byte;
|
|
i,
|
|
Len : ObjpasInt;
|
|
relocatedstringindex: byte;
|
|
p : pshortstring;
|
|
begin
|
|
if high(sarr)=0 then
|
|
begin
|
|
DestS:='';
|
|
exit;
|
|
end;
|
|
{ for s := s1 + s + ..., relocate s to the correct first position in dests
|
|
and remember this position for possible subsequent occurences of s }
|
|
Len:=1;
|
|
i:=low(sarr);
|
|
while (i<=high(sarr)) and (@dests<>sarr[i]) and (Len<=high(dests)) do
|
|
begin
|
|
Len:=Len+length(sarr[i]^);
|
|
inc(i);
|
|
end;
|
|
|
|
if Len<=high(dests) then
|
|
begin
|
|
relocatedstringindex:=Len;
|
|
s2l:=length(dests);
|
|
if uint16(s2l)+uint16(relocatedstringindex) > high(dests) then
|
|
s2l:=high(dests)-relocatedstringindex+1;
|
|
fpc_shortstr_shortstr_intern_charmove(dests,1,dests,relocatedstringindex,s2l);
|
|
end;
|
|
|
|
Len:=0;
|
|
for i:=low(sarr) to high(sarr) do
|
|
begin
|
|
p:=sarr[i];
|
|
if assigned(p) then
|
|
begin
|
|
s2l:=length(p^);
|
|
if Len+s2l>high(dests) then
|
|
s2l:=high(dests)-Len;
|
|
|
|
{ Use relocated string position if src = dests }
|
|
if (p=@dests) then
|
|
tmpindex:=relocatedstringindex
|
|
else
|
|
tmpindex:=1;
|
|
|
|
fpc_shortstr_shortstr_intern_charmove(p^,tmpindex,dests,Len+1,s2l);
|
|
inc(Len,s2l);
|
|
end;
|
|
end;
|
|
dests[0]:=Chr(Len);
|
|
end;
|
|
|
|
{include hand-optimized assembler code}
|
|
{$i math.inc}
|