mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 15:39:29 +02:00
Merged revisions 5891-10167,10169-10180 via svnmerge from
http://svn.freepascal.org/svn/fpc/branches/avr ........ r5891 | florian | 2007-01-11 17:30:12 +0100 (Do, 11 Jan 2007) | 2 lines + some initial work ........ r10170 | florian | 2008-02-03 11:02:04 +0100 (So, 03 Feb 2008) | 2 lines * continued to work on avr port ........ r10180 | florian | 2008-02-03 15:29:30 +0100 (So, 03 Feb 2008) | 2 lines + a lot of skeleton code for avr added ........ git-svn-id: trunk@10186 -
This commit is contained in:
parent
a259154511
commit
bc73f9021c
23
.gitattributes
vendored
23
.gitattributes
vendored
@ -75,6 +75,28 @@ compiler/arm/rarmstd.inc svneol=native#text/plain
|
||||
compiler/arm/rarmsup.inc svneol=native#text/plain
|
||||
compiler/arm/rgcpu.pas svneol=native#text/plain
|
||||
compiler/assemble.pas svneol=native#text/plain
|
||||
compiler/avr/aasmcpu.pas svneol=native#text/plain
|
||||
compiler/avr/aoptcpu.pas svneol=native#text/plain
|
||||
compiler/avr/aoptcpub.pas svneol=native#text/plain
|
||||
compiler/avr/aoptcpud.pas svneol=native#text/plain
|
||||
compiler/avr/avrreg.dat svneol=native#text/plain
|
||||
compiler/avr/cgcpu.pas svneol=native#text/plain
|
||||
compiler/avr/cpubase.pas svneol=native#text/plain
|
||||
compiler/avr/cpuinfo.pas svneol=native#text/plain
|
||||
compiler/avr/cpunode.pas svneol=native#text/plain
|
||||
compiler/avr/cpupara.pas svneol=native#text/plain
|
||||
compiler/avr/cpupi.pas svneol=native#text/plain
|
||||
compiler/avr/cputarg.pas svneol=native#text/plain
|
||||
compiler/avr/ravrcon.inc svneol=native#text/plain
|
||||
compiler/avr/ravrdwa.inc svneol=native#text/plain
|
||||
compiler/avr/ravrnor.inc svneol=native#text/plain
|
||||
compiler/avr/ravrnum.inc svneol=native#text/plain
|
||||
compiler/avr/ravrrni.inc svneol=native#text/plain
|
||||
compiler/avr/ravrsri.inc svneol=native#text/plain
|
||||
compiler/avr/ravrsta.inc svneol=native#text/plain
|
||||
compiler/avr/ravrstd.inc svneol=native#text/plain
|
||||
compiler/avr/ravrsup.inc svneol=native#text/plain
|
||||
compiler/avr/rgcpu.pas svneol=native#text/plain
|
||||
compiler/browcol.pas svneol=native#text/plain
|
||||
compiler/bsdcompile -text
|
||||
compiler/catch.pas svneol=native#text/plain
|
||||
@ -521,6 +543,7 @@ compiler/utils/gppc386.pp svneol=native#text/plain
|
||||
compiler/utils/mk68kreg.pp svneol=native#text/plain
|
||||
compiler/utils/mkarmins.pp svneol=native#text/plain
|
||||
compiler/utils/mkarmreg.pp svneol=native#text/plain
|
||||
compiler/utils/mkavrreg.pp svneol=native#text/plain
|
||||
compiler/utils/mkmpsreg.pp svneol=native#text/plain
|
||||
compiler/utils/mkppcreg.pp svneol=native#text/plain
|
||||
compiler/utils/mkspreg.pp svneol=native#text/plain
|
||||
|
257
compiler/avr/aasmcpu.pas
Normal file
257
compiler/avr/aasmcpu.pas
Normal file
@ -0,0 +1,257 @@
|
||||
{
|
||||
Copyright (c) 1999-2008 by Mazen Neifer and Florian Klaempfl
|
||||
|
||||
Contains the assembler object for the AVR
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
unit aasmcpu;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
cclasses,
|
||||
globtype,globals,verbose,
|
||||
aasmbase,aasmtai,aasmdata,aasmsym,
|
||||
cgbase,cgutils,cpubase,cpuinfo;
|
||||
|
||||
const
|
||||
{ "mov reg,reg" source operand number }
|
||||
O_MOV_SOURCE = 1;
|
||||
{ "mov reg,reg" source operand number }
|
||||
O_MOV_DEST = 0;
|
||||
|
||||
type
|
||||
taicpu = class(tai_cpu_abstract_sym)
|
||||
constructor op_none(op : tasmop);
|
||||
|
||||
constructor op_reg(op : tasmop;_op1 : tregister);
|
||||
constructor op_const(op : tasmop;_op1 : LongInt);
|
||||
constructor op_ref(op : tasmop;const _op1 : treference);
|
||||
|
||||
constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
|
||||
constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
|
||||
constructor op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt);
|
||||
constructor op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister);
|
||||
constructor op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
|
||||
|
||||
{ this is for Jmp instructions }
|
||||
constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
|
||||
constructor op_sym(op : tasmop;_op1 : tasmsymbol);
|
||||
constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
|
||||
procedure loadbool(opidx:longint;_b:boolean);
|
||||
{ register allocation }
|
||||
function is_same_reg_move(regtype: Tregistertype):boolean; override;
|
||||
|
||||
{ register spilling code }
|
||||
function spilling_get_operation_type(opnr: longint): topertype;override;
|
||||
end;
|
||||
|
||||
tai_align = class(tai_align_abstract)
|
||||
{ nothing to add }
|
||||
end;
|
||||
|
||||
procedure InitAsm;
|
||||
procedure DoneAsm;
|
||||
|
||||
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
|
||||
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
|
||||
|
||||
implementation
|
||||
|
||||
{*****************************************************************************
|
||||
taicpu Constructors
|
||||
*****************************************************************************}
|
||||
|
||||
procedure taicpu.loadbool(opidx:longint;_b:boolean);
|
||||
begin
|
||||
if opidx>=ops then
|
||||
ops:=opidx+1;
|
||||
with oper[opidx]^ do
|
||||
begin
|
||||
if typ=top_ref then
|
||||
dispose(ref);
|
||||
b:=_b;
|
||||
typ:=top_bool;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_none(op : tasmop);
|
||||
begin
|
||||
inherited create(op);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=1;
|
||||
loadreg(0,_op1);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=1;
|
||||
loadref(0,_op1);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_const(op : tasmop;_op1 : LongInt);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=1;
|
||||
loadconst(0,_op1);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=2;
|
||||
loadreg(0,_op1);
|
||||
loadreg(1,_op2);
|
||||
end;
|
||||
|
||||
constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=2;
|
||||
loadreg(0,_op1);
|
||||
loadconst(1,_op2);
|
||||
end;
|
||||
|
||||
constructor taicpu.op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=2;
|
||||
loadconst(0,_op1);
|
||||
loadreg(1,_op2);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=2;
|
||||
loadreg(0,_op1);
|
||||
loadref(1,_op2);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=2;
|
||||
loadref(0,_op1);
|
||||
loadreg(1,_op2);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
|
||||
begin
|
||||
inherited create(op);
|
||||
is_jmp:=op in jmp_instructions;
|
||||
condition:=cond;
|
||||
ops:=1;
|
||||
loadsymbol(0,_op1,0);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
|
||||
begin
|
||||
inherited create(op);
|
||||
is_jmp:=op in jmp_instructions;
|
||||
ops:=1;
|
||||
loadsymbol(0,_op1,0);
|
||||
end;
|
||||
|
||||
|
||||
constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
|
||||
begin
|
||||
inherited create(op);
|
||||
ops:=1;
|
||||
loadsymbol(0,_op1,_op1ofs);
|
||||
end;
|
||||
|
||||
|
||||
function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
|
||||
begin
|
||||
result:=(
|
||||
((opcode in [A_MOV,A_MOVW]) and (regtype = R_INTREGISTER))
|
||||
) and
|
||||
(ops=2) and
|
||||
(oper[0]^.typ=top_reg) and
|
||||
(oper[1]^.typ=top_reg) and
|
||||
(oper[0]^.reg=oper[1]^.reg);
|
||||
end;
|
||||
|
||||
|
||||
function taicpu.spilling_get_operation_type(opnr: longint): topertype;
|
||||
begin
|
||||
result := operand_read;
|
||||
case opcode of
|
||||
A_CP,A_CPC,A_CPI :
|
||||
;
|
||||
else
|
||||
begin
|
||||
if opnr=ops-1 then
|
||||
result := operand_write;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
|
||||
begin
|
||||
case getregtype(r) of
|
||||
R_INTREGISTER :
|
||||
result:=taicpu.op_ref_reg(A_LD,ref,r);
|
||||
else
|
||||
internalerror(200401041);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
|
||||
begin
|
||||
case getregtype(r) of
|
||||
R_INTREGISTER :
|
||||
result:=taicpu.op_reg_ref(A_ST,r,ref);
|
||||
else
|
||||
internalerror(200401041);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure InitAsm;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure DoneAsm;
|
||||
begin
|
||||
end;
|
||||
|
||||
begin
|
||||
cai_cpu:=taicpu;
|
||||
cai_align:=tai_align;
|
||||
end.
|
64
compiler/avr/aoptcpu.pas
Normal file
64
compiler/avr/aoptcpu.pas
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit implements the ARM optimizer object
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
|
||||
|
||||
Unit aoptcpu;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
Interface
|
||||
|
||||
uses cpubase, aasmtai, aopt, aoptcpub;
|
||||
|
||||
Type
|
||||
TCpuAsmOptimizer = class(TAsmOptimizer)
|
||||
{ uses the same constructor as TAopObj }
|
||||
function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
|
||||
procedure PeepHoleOptPass2;override;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
uses
|
||||
aasmbase,aasmcpu;
|
||||
|
||||
function CanBeCond(p : tai) : boolean;
|
||||
begin
|
||||
result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
|
||||
var
|
||||
next1: tai;
|
||||
begin
|
||||
result := false;
|
||||
end;
|
||||
|
||||
procedure TCpuAsmOptimizer.PeepHoleOptPass2;
|
||||
begin
|
||||
end;
|
||||
|
||||
begin
|
||||
casmoptimizer:=TCpuAsmOptimizer;
|
||||
End.
|
120
compiler/avr/aoptcpub.pas
Normal file
120
compiler/avr/aoptcpub.pas
Normal file
@ -0,0 +1,120 @@
|
||||
{
|
||||
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit contains several types and constants necessary for the
|
||||
optimizer to work on the ARM architecture
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
{ enable the following define if memory references can have both a base and }
|
||||
{ index register in 1 operand }
|
||||
|
||||
{$define RefsHaveIndexReg}
|
||||
|
||||
{ enable the following define if memory references can have a scaled index }
|
||||
|
||||
{ define RefsHaveScale}
|
||||
|
||||
{ enable the following define if memory references can have a segment }
|
||||
{ override }
|
||||
|
||||
{ define RefsHaveSegment}
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
cpubase,aasmcpu,AOptBase;
|
||||
|
||||
Type
|
||||
|
||||
{ type of a normal instruction }
|
||||
TInstr = Taicpu;
|
||||
PInstr = ^TInstr;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TCondRegs ********************************** }
|
||||
{ ************************************************************************* }
|
||||
{ Info about the conditional registers }
|
||||
TCondRegs = Object
|
||||
Constructor Init;
|
||||
Destructor Done;
|
||||
End;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TAoptBaseCpu ******************************* }
|
||||
{ ************************************************************************* }
|
||||
|
||||
TAoptBaseCpu = class(TAoptBase)
|
||||
End;
|
||||
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ ******************************* Constants ******************************* }
|
||||
{ ************************************************************************* }
|
||||
Const
|
||||
|
||||
{ the maximum number of things (registers, memory, ...) a single instruction }
|
||||
{ changes }
|
||||
|
||||
MaxCh = 2;
|
||||
|
||||
{ the maximum number of operands an instruction has }
|
||||
|
||||
MaxOps = 2;
|
||||
|
||||
{Oper index of operand that contains the source (reference) with a load }
|
||||
{instruction }
|
||||
|
||||
LoadSrc = 1;
|
||||
|
||||
{Oper index of operand that contains the destination (register) with a load }
|
||||
{instruction }
|
||||
|
||||
LoadDst = 0;
|
||||
|
||||
{Oper index of operand that contains the source (register) with a store }
|
||||
{instruction }
|
||||
|
||||
StoreSrc = 1;
|
||||
|
||||
{Oper index of operand that contains the destination (reference) with a load }
|
||||
{instruction }
|
||||
|
||||
StoreDst = 0;
|
||||
|
||||
aopt_uncondjmp = A_JMP;
|
||||
aopt_condjmp = A_BRxx;
|
||||
|
||||
Implementation
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TCondRegs ********************************** }
|
||||
{ ************************************************************************* }
|
||||
Constructor TCondRegs.init;
|
||||
Begin
|
||||
End;
|
||||
|
||||
Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
|
||||
Begin
|
||||
End;
|
||||
|
||||
End.
|
40
compiler/avr/aoptcpud.pas
Normal file
40
compiler/avr/aoptcpud.pas
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit contains the processor specific implementation of the
|
||||
assembler optimizer data flow analyzer.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
Unit aoptcpud;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
Interface
|
||||
|
||||
uses
|
||||
AOptDA;
|
||||
|
||||
Type
|
||||
TAOptDFACpu = class(TAOptDFA)
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
|
||||
End.
|
41
compiler/avr/avrreg.dat
Normal file
41
compiler/avr/avrreg.dat
Normal file
@ -0,0 +1,41 @@
|
||||
;
|
||||
; AVR registers
|
||||
;
|
||||
; layout
|
||||
; <name>,<type>,<value>,<stdname>,<stab idx>,<dwarf idx>
|
||||
;
|
||||
NO,$00,$00,INVALID,-1,-1
|
||||
|
||||
R0,$01,$00,r0,0,0
|
||||
R1,$01,$01,r1,1,1
|
||||
R2,$01,$02,r2,2,2
|
||||
R3,$01,$03,r3,3,3
|
||||
R4,$01,$04,r4,4,4
|
||||
R5,$01,$05,r5,5,5
|
||||
R6,$01,$06,r6,6,6
|
||||
R7,$01,$07,r7,7,7
|
||||
R8,$01,$08,r8,8,8
|
||||
R9,$01,$09,r9,9,9
|
||||
R10,$01,$0a,r10,10,10
|
||||
R11,$01,$0b,r11,11,11
|
||||
R12,$01,$0c,r12,12,12
|
||||
R13,$01,$0d,r13,13,13
|
||||
R14,$01,$0e,r14,14,14
|
||||
R15,$01,$0f,r15,15,15
|
||||
R16,$01,$10,r16,16,16
|
||||
R17,$01,$11,r17,17,17
|
||||
R18,$01,$12,r18,18,18
|
||||
R19,$01,$13,r19,19,19
|
||||
R20,$01,$14,r20,20,20
|
||||
R21,$01,$15,r21,21,21
|
||||
R22,$01,$16,r22,22,22
|
||||
R23,$01,$17,r23,23,23
|
||||
R24,$01,$18,r24,24,24
|
||||
R25,$01,$19,r25,25,25
|
||||
R26,$01,$1a,r26,26,26
|
||||
R27,$01,$1b,r27,27,27
|
||||
R28,$01,$1c,r28,28,28
|
||||
R29,$01,$1d,r29,29,29
|
||||
R30,$01,$1e,r30,30,30
|
||||
R31,$01,$1f,r31,31,31
|
||||
|
798
compiler/avr/cgcpu.pas
Normal file
798
compiler/avr/cgcpu.pas
Normal file
@ -0,0 +1,798 @@
|
||||
{
|
||||
|
||||
Copyright (c) 2008 by Florian Klaempfl
|
||||
Member of the Free Pascal development team
|
||||
|
||||
This unit implements the code generator for the AVR
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
unit cgcpu;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
globtype,symtype,symdef,
|
||||
cgbase,cgutils,cgobj,
|
||||
aasmbase,aasmcpu,aasmtai,aasmdata,
|
||||
parabase,
|
||||
cpubase,cpuinfo,node,cg64f32,rgcpu;
|
||||
|
||||
|
||||
type
|
||||
tcgavr = class(tcg)
|
||||
{ true, if the next arithmetic operation should modify the flags }
|
||||
cgsetflags : boolean;
|
||||
procedure init_register_allocators;override;
|
||||
procedure done_register_allocators;override;
|
||||
|
||||
procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
|
||||
procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
|
||||
procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
|
||||
|
||||
procedure a_call_name(list : TAsmList;const s : string);override;
|
||||
procedure a_call_reg(list : TAsmList;reg: tregister);override;
|
||||
procedure a_call_ref(list : TAsmList;ref: treference);override;
|
||||
|
||||
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
|
||||
procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
|
||||
|
||||
procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
|
||||
size: tcgsize; a: aint; src, dst: tregister); override;
|
||||
procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
|
||||
size: tcgsize; src1, src2, dst: tregister); override;
|
||||
procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
|
||||
procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
|
||||
|
||||
{ move instructions }
|
||||
procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
|
||||
procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
|
||||
procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
|
||||
procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
|
||||
function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
|
||||
function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
|
||||
|
||||
{ comparison operations }
|
||||
procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
|
||||
l : tasmlabel);override;
|
||||
procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
|
||||
|
||||
procedure a_jmp_name(list : TAsmList;const s : string); override;
|
||||
procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
|
||||
procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
|
||||
|
||||
procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
|
||||
|
||||
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
|
||||
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
|
||||
|
||||
procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
|
||||
|
||||
procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
|
||||
procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
|
||||
procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
|
||||
procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
|
||||
|
||||
procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
|
||||
procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
|
||||
|
||||
// procedure g_save_registers(list : TAsmList);override;
|
||||
// procedure g_restore_registers(list : TAsmList);override;
|
||||
|
||||
procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
|
||||
procedure fixref(list : TAsmList;var ref : treference);
|
||||
function handle_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference):treference;
|
||||
|
||||
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
|
||||
end;
|
||||
|
||||
tcg64favr = class(tcg64f32)
|
||||
procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
|
||||
procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
|
||||
procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
|
||||
procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
|
||||
procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
|
||||
procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
|
||||
end;
|
||||
|
||||
const
|
||||
OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
|
||||
C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
uses
|
||||
globals,verbose,systems,cutils,
|
||||
fmodule,
|
||||
symconst,symsym,
|
||||
tgobj,
|
||||
procinfo,cpupi,
|
||||
paramgr;
|
||||
|
||||
|
||||
procedure tcgavr.init_register_allocators;
|
||||
begin
|
||||
inherited init_register_allocators;
|
||||
{ currently, we save R14 always, so we can use it }
|
||||
rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
|
||||
[RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
|
||||
RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.done_register_allocators;
|
||||
begin
|
||||
rg[R_INTREGISTER].free;
|
||||
inherited done_register_allocators;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
|
||||
var
|
||||
ref: treference;
|
||||
begin
|
||||
paraloc.check_simple_location;
|
||||
case paraloc.location^.loc of
|
||||
LOC_REGISTER,LOC_CREGISTER:
|
||||
a_load_const_reg(list,size,a,paraloc.location^.register);
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
reference_reset(ref);
|
||||
ref.base:=paraloc.location^.reference.index;
|
||||
ref.offset:=paraloc.location^.reference.offset;
|
||||
a_load_const_ref(list,size,a,ref);
|
||||
end;
|
||||
else
|
||||
internalerror(2002081101);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
|
||||
var
|
||||
tmpref, ref: treference;
|
||||
location: pcgparalocation;
|
||||
sizeleft: aint;
|
||||
begin
|
||||
location := paraloc.location;
|
||||
tmpref := r;
|
||||
sizeleft := paraloc.intsize;
|
||||
while assigned(location) do
|
||||
begin
|
||||
case location^.loc of
|
||||
LOC_REGISTER,LOC_CREGISTER:
|
||||
a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
reference_reset_base(ref,location^.reference.index,location^.reference.offset);
|
||||
{ doubles in softemu mode have a strange order of registers and references }
|
||||
if location^.size=OS_32 then
|
||||
g_concatcopy(list,tmpref,ref,4)
|
||||
else
|
||||
begin
|
||||
g_concatcopy(list,tmpref,ref,sizeleft);
|
||||
if assigned(location^.next) then
|
||||
internalerror(2005010710);
|
||||
end;
|
||||
end;
|
||||
LOC_VOID:
|
||||
begin
|
||||
// nothing to do
|
||||
end;
|
||||
else
|
||||
internalerror(2002081103);
|
||||
end;
|
||||
inc(tmpref.offset,tcgsize2size[location^.size]);
|
||||
dec(sizeleft,tcgsize2size[location^.size]);
|
||||
location := location^.next;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
|
||||
var
|
||||
ref: treference;
|
||||
tmpreg: tregister;
|
||||
begin
|
||||
paraloc.check_simple_location;
|
||||
case paraloc.location^.loc of
|
||||
LOC_REGISTER,LOC_CREGISTER:
|
||||
a_loadaddr_ref_reg(list,r,paraloc.location^.register);
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
reference_reset(ref);
|
||||
ref.base := paraloc.location^.reference.index;
|
||||
ref.offset := paraloc.location^.reference.offset;
|
||||
tmpreg := getintregister(list,OS_ADDR);
|
||||
a_loadaddr_ref_reg(list,r,tmpreg);
|
||||
a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
|
||||
end;
|
||||
else
|
||||
internalerror(2002080701);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_call_name(list : TAsmList;const s : string);
|
||||
begin
|
||||
list.concat(taicpu.op_sym(A_RCALL,current_asmdata.RefAsmSymbol(s)));
|
||||
{
|
||||
the compiler does not properly set this flag anymore in pass 1, and
|
||||
for now we only need it after pass 2 (I hope) (JM)
|
||||
if not(pi_do_call in current_procinfo.flags) then
|
||||
internalerror(2003060703);
|
||||
}
|
||||
include(current_procinfo.flags,pi_do_call);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_call_reg(list : TAsmList;reg: tregister);
|
||||
begin
|
||||
a_reg_alloc(list,NR_ZLO);
|
||||
a_reg_alloc(list,NR_ZHI);
|
||||
list.concat(taicpu.op_reg_reg(A_MOV,NR_ZLO,reg));
|
||||
list.concat(taicpu.op_reg_reg(A_MOV,NR_ZHI,GetHigh(reg)));
|
||||
list.concat(taicpu.op_none(A_ICALL));
|
||||
a_reg_dealloc(list,NR_ZLO);
|
||||
a_reg_dealloc(list,NR_ZHI);
|
||||
|
||||
include(current_procinfo.flags,pi_do_call);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_call_ref(list : TAsmList;ref: treference);
|
||||
begin
|
||||
a_reg_alloc(list,NR_ZLO);
|
||||
a_reg_alloc(list,NR_ZHI);
|
||||
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_ZLO);
|
||||
list.concat(taicpu.op_none(A_ICALL));
|
||||
a_reg_dealloc(list,NR_ZLO);
|
||||
a_reg_dealloc(list,NR_ZHI);
|
||||
|
||||
include(current_procinfo.flags,pi_do_call);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
|
||||
begin
|
||||
a_op_const_reg_reg(list,op,size,a,reg,reg);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
|
||||
begin
|
||||
case op of
|
||||
OP_NEG:
|
||||
// !!!! list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
|
||||
;
|
||||
OP_NOT:
|
||||
begin
|
||||
// !!!! list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
|
||||
case size of
|
||||
OS_8 :
|
||||
;
|
||||
// !!!! a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
|
||||
OS_16 :
|
||||
// !!!! a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
|
||||
;
|
||||
end;
|
||||
end
|
||||
else
|
||||
a_op_reg_reg_reg(list,op,size,src,dst,dst);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
|
||||
size: tcgsize; a: aint; src, dst: tregister);
|
||||
var
|
||||
ovloc : tlocation;
|
||||
begin
|
||||
a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
|
||||
size: tcgsize; src1, src2, dst: tregister);
|
||||
var
|
||||
ovloc : tlocation;
|
||||
begin
|
||||
a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
|
||||
var
|
||||
so : tshifterop;
|
||||
tmpreg,overflowreg : tregister;
|
||||
asmop : tasmop;
|
||||
begin
|
||||
ovloc.loc:=LOC_VOID;
|
||||
case op of
|
||||
OP_NEG,OP_NOT,
|
||||
OP_DIV,OP_IDIV:
|
||||
internalerror(200308281);
|
||||
OP_SHL:
|
||||
begin
|
||||
end;
|
||||
OP_SHR:
|
||||
begin
|
||||
end;
|
||||
OP_SAR:
|
||||
begin
|
||||
end;
|
||||
OP_IMUL,
|
||||
OP_MUL:
|
||||
begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
|
||||
begin
|
||||
if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
|
||||
internalerror(2002090902);
|
||||
end;
|
||||
|
||||
|
||||
function tcgavr.handle_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference):treference;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
function tcgavr.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
function tcgavr.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure tcgavr.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
{ comparison operations }
|
||||
procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
|
||||
l : tasmlabel);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_jmp_name(list : TAsmList;const s : string);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_jmp_always(list : TAsmList;l: tasmlabel);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
|
||||
{
|
||||
var
|
||||
ref : treference;
|
||||
shift : byte;
|
||||
firstfloatreg,lastfloatreg,
|
||||
r : byte;
|
||||
regs : tcpuregisterset;
|
||||
}
|
||||
begin
|
||||
{
|
||||
LocalSize:=align(LocalSize,4);
|
||||
if not(nostackframe) then
|
||||
begin
|
||||
firstfloatreg:=RS_NO;
|
||||
{ save floating point registers? }
|
||||
for r:=RS_F0 to RS_F7 do
|
||||
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
|
||||
begin
|
||||
if firstfloatreg=RS_NO then
|
||||
firstfloatreg:=r;
|
||||
lastfloatreg:=r;
|
||||
end;
|
||||
a_reg_alloc(list,NR_STACK_POINTER_REG);
|
||||
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
|
||||
begin
|
||||
a_reg_alloc(list,NR_FRAME_POINTER_REG);
|
||||
a_reg_alloc(list,NR_R12);
|
||||
|
||||
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
|
||||
end;
|
||||
{ save int registers }
|
||||
reference_reset(ref);
|
||||
ref.index:=NR_STACK_POINTER_REG;
|
||||
ref.addressmode:=AM_PREINDEXED;
|
||||
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
|
||||
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
|
||||
regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
|
||||
else
|
||||
if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
|
||||
include(regs,RS_R14);
|
||||
if regs<>[] then
|
||||
list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
|
||||
|
||||
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
|
||||
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
|
||||
|
||||
{ allocate necessary stack size
|
||||
not necessary according to Yury Sidorov
|
||||
|
||||
{ don't use a_op_const_reg_reg here because we don't allow register allocations
|
||||
in the entry/exit code }
|
||||
if (target_info.system in [system_arm_wince]) and
|
||||
(localsize>=winstackpagesize) then
|
||||
begin
|
||||
if localsize div winstackpagesize<=5 then
|
||||
begin
|
||||
if is_shifter_const(localsize,shift) then
|
||||
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
|
||||
else
|
||||
begin
|
||||
a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
|
||||
end;
|
||||
|
||||
for i:=1 to localsize div winstackpagesize do
|
||||
begin
|
||||
if localsize-i*winstackpagesize<4096 then
|
||||
reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
|
||||
else
|
||||
begin
|
||||
a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
|
||||
reference_reset_base(href,NR_STACK_POINTER_REG,0);
|
||||
href.index:=NR_R12;
|
||||
end;
|
||||
{ the data stored doesn't matter }
|
||||
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
|
||||
end;
|
||||
a_reg_dealloc(list,NR_R12);
|
||||
reference_reset_base(href,NR_STACK_POINTER_REG,0);
|
||||
{ the data stored doesn't matter }
|
||||
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
|
||||
end
|
||||
else
|
||||
begin
|
||||
current_asmdata.getjumplabel(again);
|
||||
list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
|
||||
a_label(list,again);
|
||||
{ always shifterop }
|
||||
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
|
||||
reference_reset_base(href,NR_STACK_POINTER_REG,0);
|
||||
{ the data stored doesn't matter }
|
||||
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
|
||||
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
|
||||
a_jmp_cond(list,OC_NE,again);
|
||||
if is_shifter_const(localsize mod winstackpagesize,shift) then
|
||||
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
|
||||
else
|
||||
begin
|
||||
a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
|
||||
end;
|
||||
a_reg_dealloc(list,NR_R12);
|
||||
reference_reset_base(href,NR_STACK_POINTER_REG,0);
|
||||
{ the data stored doesn't matter }
|
||||
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
|
||||
end
|
||||
end
|
||||
else
|
||||
}
|
||||
if LocalSize<>0 then
|
||||
if not(is_shifter_const(localsize,shift)) then
|
||||
begin
|
||||
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
|
||||
a_reg_alloc(list,NR_R12);
|
||||
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
|
||||
a_reg_dealloc(list,NR_R12);
|
||||
end
|
||||
else
|
||||
begin
|
||||
a_reg_dealloc(list,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
|
||||
end;
|
||||
|
||||
if firstfloatreg<>RS_NO then
|
||||
begin
|
||||
reference_reset(ref);
|
||||
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
|
||||
begin
|
||||
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
|
||||
ref.base:=NR_R12;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ref.base:=current_procinfo.framepointer;
|
||||
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
|
||||
end;
|
||||
list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
|
||||
lastfloatreg-firstfloatreg+1,ref));
|
||||
end;
|
||||
end;
|
||||
}
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
|
||||
{
|
||||
var
|
||||
ref : treference;
|
||||
firstfloatreg,lastfloatreg,
|
||||
r : byte;
|
||||
shift : byte;
|
||||
regs : tcpuregisterset;
|
||||
LocalSize : longint;
|
||||
}
|
||||
begin
|
||||
{
|
||||
if not(nostackframe) then
|
||||
begin
|
||||
{ restore floating point register }
|
||||
firstfloatreg:=RS_NO;
|
||||
{ save floating point registers? }
|
||||
for r:=RS_F0 to RS_F7 do
|
||||
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
|
||||
begin
|
||||
if firstfloatreg=RS_NO then
|
||||
firstfloatreg:=r;
|
||||
lastfloatreg:=r;
|
||||
end;
|
||||
|
||||
if firstfloatreg<>RS_NO then
|
||||
begin
|
||||
reference_reset(ref);
|
||||
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
|
||||
begin
|
||||
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
|
||||
ref.base:=NR_R12;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ref.base:=current_procinfo.framepointer;
|
||||
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
|
||||
end;
|
||||
list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
|
||||
lastfloatreg-firstfloatreg+1,ref));
|
||||
end;
|
||||
|
||||
if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
|
||||
begin
|
||||
LocalSize:=current_procinfo.calc_stackframe_size;
|
||||
if LocalSize<>0 then
|
||||
if not(is_shifter_const(LocalSize,shift)) then
|
||||
begin
|
||||
a_reg_alloc(list,NR_R12);
|
||||
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
|
||||
a_reg_dealloc(list,NR_R12);
|
||||
end
|
||||
else
|
||||
begin
|
||||
list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
|
||||
end;
|
||||
|
||||
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
|
||||
if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
|
||||
begin
|
||||
exclude(regs,RS_R14);
|
||||
include(regs,RS_R15);
|
||||
end;
|
||||
if regs=[] then
|
||||
list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
|
||||
else
|
||||
begin
|
||||
reference_reset(ref);
|
||||
ref.index:=NR_STACK_POINTER_REG;
|
||||
ref.addressmode:=AM_PREINDEXED;
|
||||
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ restore int registers and return }
|
||||
reference_reset(ref);
|
||||
ref.index:=NR_FRAME_POINTER_REG;
|
||||
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
|
||||
end;
|
||||
end
|
||||
else
|
||||
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
|
||||
}
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.fixref(list : TAsmList;var ref : treference);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
|
||||
var
|
||||
paraloc1,paraloc2,paraloc3 : TCGPara;
|
||||
begin
|
||||
paraloc1.init;
|
||||
paraloc2.init;
|
||||
paraloc3.init;
|
||||
paramanager.getintparaloc(pocall_default,1,paraloc1);
|
||||
paramanager.getintparaloc(pocall_default,2,paraloc2);
|
||||
paramanager.getintparaloc(pocall_default,3,paraloc3);
|
||||
paramanager.allocparaloc(list,paraloc3);
|
||||
a_param_const(list,OS_INT,len,paraloc3);
|
||||
paramanager.allocparaloc(list,paraloc2);
|
||||
a_paramaddr_ref(list,dest,paraloc2);
|
||||
paramanager.allocparaloc(list,paraloc2);
|
||||
a_paramaddr_ref(list,source,paraloc1);
|
||||
paramanager.freeparaloc(list,paraloc3);
|
||||
paramanager.freeparaloc(list,paraloc2);
|
||||
paramanager.freeparaloc(list,paraloc1);
|
||||
alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
|
||||
a_call_name(list,'FPC_MOVE');
|
||||
dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
|
||||
paraloc3.done;
|
||||
paraloc2.done;
|
||||
paraloc1.done;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure tcgavr.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
|
||||
begin
|
||||
g_concatcopy_internal(list,source,dest,len,false);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
|
||||
begin
|
||||
if (source.alignment in [1..3]) or
|
||||
(dest.alignment in [1..3]) then
|
||||
g_concatcopy_internal(list,source,dest,len,false)
|
||||
else
|
||||
g_concatcopy_internal(list,source,dest,len,true);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
|
||||
var
|
||||
ovloc : tlocation;
|
||||
begin
|
||||
ovloc.loc:=LOC_VOID;
|
||||
g_overflowCheck_loc(list,l,def,ovloc);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
|
||||
begin
|
||||
end;
|
||||
|
||||
{
|
||||
procedure tcgavr.g_save_registers(list : TAsmList);
|
||||
begin
|
||||
{ this work is done in g_proc_entry }
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_restore_registers(list : TAsmList);
|
||||
begin
|
||||
{ this work is done in g_proc_exit }
|
||||
end;
|
||||
}
|
||||
|
||||
procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
|
||||
var
|
||||
ai : taicpu;
|
||||
begin
|
||||
ai:=Taicpu.Op_sym(A_BRxx,l);
|
||||
ai.SetCondition(OpCmp2AsmCond[cond]);
|
||||
ai.is_jmp:=true;
|
||||
list.concat(ai);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgavr.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
|
||||
begin
|
||||
a_op64_const_reg_reg(list,op,size,value,reg,reg);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
|
||||
var
|
||||
ovloc : tlocation;
|
||||
begin
|
||||
a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
|
||||
var
|
||||
ovloc : tlocation;
|
||||
begin
|
||||
a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg64favr.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
cg:=tcgavr.create;
|
||||
cg64:=tcg64favr.create;
|
||||
end.
|
484
compiler/avr/cpubase.pas
Normal file
484
compiler/avr/cpubase.pas
Normal file
@ -0,0 +1,484 @@
|
||||
{
|
||||
Copyright (c) 2006 by Florian Klaempfl
|
||||
|
||||
Contains the base types for the AVR
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
{# Base unit for processor information. This unit contains
|
||||
enumerations of registers, opcodes, sizes, and other
|
||||
such things which are processor specific.
|
||||
}
|
||||
unit cpubase;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
cutils,cclasses,
|
||||
globtype,globals,
|
||||
cpuinfo,
|
||||
aasmbase,
|
||||
cgbase
|
||||
;
|
||||
|
||||
|
||||
{*****************************************************************************
|
||||
Assembler Opcodes
|
||||
*****************************************************************************}
|
||||
|
||||
type
|
||||
TAsmOp=(A_None,
|
||||
A_ADD,A_ADC,A_ADIW,A_SUB,A_SUBI,A_SBC,A_SBCI,A_SBIW,A_AND,A_ANDI,
|
||||
A_OR,A_ORI,A_EOR,A_COM,A_NEG,A_SBR,A_CBR,A_INC,A_DEC,A_TST,A_CLR,
|
||||
A_SER,A_MUL,A_MULS,A_FMUL,A_FMULS,A_FMULSU,A_RJMP,A_IJMP,
|
||||
A_EIJMP,A_JMP,A_RCALL,A_ICALL,R_EICALL,A_CALL,A_RET,A_RETI,A_CPSE,
|
||||
A_CP,A_CPC,A_CPI,A_SBxx,A_BRxx,A_MOV,A_MOVW,A_LDI,A_LDS,A_LD,A_LDD,
|
||||
A_STS,A_ST,A_STD,A_LPM,A_ELPM,A_SPM,A_IN,A_OUT,A_PUSH,A_POP,
|
||||
A_LSL,A_LSR,A_ROL,A_ROR,A_ASR,A_SWAP,A_BSET,A_BCLR,A_SBI,A_CBI,
|
||||
A_BST,A_BLD,A_Sxx,A_Cxx,A_BRAK,A_NOP,A_SLEEP,A_WDR);
|
||||
|
||||
|
||||
{ This should define the array of instructions as string }
|
||||
op2strtable=array[tasmop] of string[11];
|
||||
|
||||
const
|
||||
{ First value of opcode enumeration }
|
||||
firstop = low(tasmop);
|
||||
{ Last value of opcode enumeration }
|
||||
lastop = high(tasmop);
|
||||
|
||||
jmp_instructions = [A_BRxx,A_SBxx,A_JMP,A_RCALL,A_ICALL,A_EIJMP,A_RJMP,A_CALL,A_RET,A_RETI,A_CPSE,A_IJMP];
|
||||
|
||||
{*****************************************************************************
|
||||
Registers
|
||||
*****************************************************************************}
|
||||
|
||||
type
|
||||
{ Number of registers used for indexing in tables }
|
||||
tregisterindex=0..{$i ravrnor.inc}-1;
|
||||
|
||||
const
|
||||
{ Available Superregisters }
|
||||
{$i ravrsup.inc}
|
||||
|
||||
{ No Subregisters }
|
||||
R_SUBWHOLE = R_SUBNONE;
|
||||
|
||||
{ Available Registers }
|
||||
{$i ravrcon.inc}
|
||||
|
||||
NR_XLO = NR_R26;
|
||||
NR_XHI = NR_R27;
|
||||
NR_YLO = NR_R28;
|
||||
NR_YHI = NR_R29;
|
||||
NR_ZLO = NR_R30;
|
||||
NR_ZHI = NR_R31;
|
||||
|
||||
{ Integer Super registers first and last }
|
||||
first_int_supreg = RS_R0;
|
||||
first_int_imreg = $10;
|
||||
|
||||
{ Float Super register first and last }
|
||||
first_fpu_supreg = RS_INVALID;
|
||||
first_fpu_imreg = RS_INVALID;
|
||||
|
||||
{ MM Super register first and last }
|
||||
first_mm_supreg = RS_INVALID;
|
||||
first_mm_imreg = RS_INVALID;
|
||||
|
||||
{$warning TODO Calculate bsstart}
|
||||
regnumber_count_bsstart = 64;
|
||||
|
||||
regnumber_table : array[tregisterindex] of tregister = (
|
||||
{$i ravrnum.inc}
|
||||
);
|
||||
|
||||
regstabs_table : array[tregisterindex] of shortint = (
|
||||
{$i ravrsta.inc}
|
||||
);
|
||||
|
||||
regdwarf_table : array[tregisterindex] of shortint = (
|
||||
{$i ravrdwa.inc}
|
||||
);
|
||||
{ registers which may be destroyed by calls }
|
||||
VOLATILE_INTREGISTERS = [RS_R18..RS_R27,RS_R30..RS_R31];
|
||||
VOLATILE_FPUREGISTERS = [];
|
||||
|
||||
type
|
||||
totherregisterset = set of tregisterindex;
|
||||
|
||||
{*****************************************************************************
|
||||
Conditions
|
||||
*****************************************************************************}
|
||||
|
||||
type
|
||||
TAsmCond=(C_None,
|
||||
C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
|
||||
C_GE,C_LT,C_GT,C_LE,C_AL,C_NV
|
||||
);
|
||||
|
||||
const
|
||||
cond2str : array[TAsmCond] of string[2]=('',
|
||||
'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
|
||||
'ge','lt','gt','le','al','nv'
|
||||
);
|
||||
|
||||
uppercond2str : array[TAsmCond] of string[2]=('',
|
||||
'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
|
||||
'GE','LT','GT','LE','AL','NV'
|
||||
);
|
||||
|
||||
{*****************************************************************************
|
||||
Flags
|
||||
*****************************************************************************}
|
||||
|
||||
type
|
||||
TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
|
||||
F_GE,F_LT,F_GT,F_LE);
|
||||
|
||||
{*****************************************************************************
|
||||
Operands
|
||||
*****************************************************************************}
|
||||
|
||||
taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
|
||||
tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
|
||||
|
||||
tupdatereg = (UR_None,UR_Update);
|
||||
|
||||
pshifterop = ^tshifterop;
|
||||
|
||||
tshifterop = record
|
||||
shiftmode : tshiftmode;
|
||||
rs : tregister;
|
||||
shiftimm : byte;
|
||||
end;
|
||||
|
||||
{*****************************************************************************
|
||||
Constants
|
||||
*****************************************************************************}
|
||||
|
||||
const
|
||||
max_operands = 4;
|
||||
|
||||
{# Constant defining possibly all registers which might require saving }
|
||||
ALL_OTHERREGISTERS = [];
|
||||
|
||||
general_superregisters = [RS_R0..RS_R31];
|
||||
|
||||
{# Table of registers which can be allocated by the code generator
|
||||
internally, when generating the code.
|
||||
}
|
||||
{ legend: }
|
||||
{ xxxregs = set of all possibly used registers of that type in the code }
|
||||
{ generator }
|
||||
{ usableregsxxx = set of all 32bit components of registers that can be }
|
||||
{ possible allocated to a regvar or using getregisterxxx (this }
|
||||
{ excludes registers which can be only used for parameter }
|
||||
{ passing on ABI's that define this) }
|
||||
{ c_countusableregsxxx = amount of registers in the usableregsxxx set }
|
||||
|
||||
maxintregs = 15;
|
||||
{ to determine how many registers to use for regvars }
|
||||
maxintscratchregs = 3;
|
||||
usableregsint = [RS_R4..RS_R10];
|
||||
c_countusableregsint = 7;
|
||||
|
||||
maxfpuregs = 0;
|
||||
fpuregs = [];
|
||||
usableregsfpu = [];
|
||||
c_countusableregsfpu = 0;
|
||||
|
||||
mmregs = [];
|
||||
usableregsmm = [];
|
||||
c_countusableregsmm = 0;
|
||||
|
||||
maxaddrregs = 0;
|
||||
addrregs = [];
|
||||
usableregsaddr = [];
|
||||
c_countusableregsaddr = 0;
|
||||
|
||||
{*****************************************************************************
|
||||
Operand Sizes
|
||||
*****************************************************************************}
|
||||
|
||||
type
|
||||
topsize = (S_NO,
|
||||
S_B,S_W,S_L,S_BW,S_BL,S_WL,
|
||||
S_IS,S_IL,S_IQ,
|
||||
S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
|
||||
);
|
||||
|
||||
{*****************************************************************************
|
||||
Constants
|
||||
*****************************************************************************}
|
||||
|
||||
const
|
||||
firstsaveintreg = RS_R4;
|
||||
lastsaveintreg = RS_R10;
|
||||
firstsavefpureg = RS_INVALID;
|
||||
lastsavefpureg = RS_INVALID;
|
||||
firstsavemmreg = RS_INVALID;
|
||||
lastsavemmreg = RS_INVALID;
|
||||
|
||||
maxvarregs = 7;
|
||||
varregs : Array [1..maxvarregs] of tsuperregister =
|
||||
(RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
|
||||
|
||||
maxfpuvarregs = 1;
|
||||
fpuvarregs : Array [1..maxfpuvarregs] of tsuperregister =
|
||||
(RS_INVALID);
|
||||
|
||||
{*****************************************************************************
|
||||
Default generic sizes
|
||||
*****************************************************************************}
|
||||
|
||||
{ Defines the default address size for a processor, }
|
||||
OS_ADDR = OS_16;
|
||||
{ the natural int size for a processor, }
|
||||
OS_INT = OS_16;
|
||||
OS_SINT = OS_S16;
|
||||
{ the maximum float size for a processor, }
|
||||
OS_FLOAT = OS_F64;
|
||||
{ the size of a vector register for a processor }
|
||||
OS_VECTOR = OS_M32;
|
||||
|
||||
{*****************************************************************************
|
||||
Generic Register names
|
||||
*****************************************************************************}
|
||||
|
||||
{ Stack pointer register }
|
||||
NR_STACK_POINTER_REG = NR_R13;
|
||||
RS_STACK_POINTER_REG = RS_R13;
|
||||
{ Frame pointer register }
|
||||
RS_FRAME_POINTER_REG = RS_R11;
|
||||
NR_FRAME_POINTER_REG = NR_R11;
|
||||
{ Register for addressing absolute data in a position independant way,
|
||||
such as in PIC code. The exact meaning is ABI specific. For
|
||||
further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
|
||||
}
|
||||
NR_PIC_OFFSET_REG = NR_R9;
|
||||
{ Results are returned in this register (32-bit values) }
|
||||
NR_FUNCTION_RETURN_REG = NR_R0;
|
||||
RS_FUNCTION_RETURN_REG = RS_R0;
|
||||
{ Low part of 64bit return value }
|
||||
NR_FUNCTION_RETURN64_LOW_REG = NR_R0;
|
||||
RS_FUNCTION_RETURN64_LOW_REG = RS_R0;
|
||||
{ High part of 64bit return value }
|
||||
NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
|
||||
RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
|
||||
{ The value returned from a function is available in this register }
|
||||
NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
|
||||
RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
|
||||
{ The lowh part of 64bit value returned from a function }
|
||||
NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
|
||||
RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
|
||||
{ The high part of 64bit value returned from a function }
|
||||
NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
|
||||
RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
|
||||
|
||||
NR_FPU_RESULT_REG = NR_NO;
|
||||
|
||||
NR_MM_RESULT_REG = NR_NO;
|
||||
|
||||
NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
|
||||
|
||||
{ Offset where the parent framepointer is pushed }
|
||||
PARENT_FRAMEPOINTER_OFFSET = 0;
|
||||
|
||||
{*****************************************************************************
|
||||
GCC /ABI linking information
|
||||
*****************************************************************************}
|
||||
|
||||
const
|
||||
{ Registers which must be saved when calling a routine declared as
|
||||
cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
|
||||
saved should be the ones as defined in the target ABI and / or GCC.
|
||||
|
||||
This value can be deduced from the CALLED_USED_REGISTERS array in the
|
||||
GCC source.
|
||||
}
|
||||
saved_standard_registers : array[0..6] of tsuperregister =
|
||||
(RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
|
||||
{ Required parameter alignment when calling a routine declared as
|
||||
stdcall and cdecl. The alignment value should be the one defined
|
||||
by GCC or the target ABI.
|
||||
|
||||
The value of this constant is equal to the constant
|
||||
PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
|
||||
}
|
||||
std_param_align = 4;
|
||||
|
||||
|
||||
{*****************************************************************************
|
||||
Helpers
|
||||
*****************************************************************************}
|
||||
|
||||
{ Returns the tcgsize corresponding with the size of reg.}
|
||||
function reg_cgsize(const reg: tregister) : tcgsize;
|
||||
function cgsize2subreg(s:Tcgsize):Tsubregister;
|
||||
procedure inverse_flags(var f: TResFlags);
|
||||
function flags_to_cond(const f: TResFlags) : TAsmCond;
|
||||
function findreg_by_number(r:Tregister):tregisterindex;
|
||||
function std_regnum_search(const s:string):Tregister;
|
||||
function std_regname(r:Tregister):string;
|
||||
|
||||
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
|
||||
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
|
||||
|
||||
function is_pc(const r : tregister) : boolean;
|
||||
|
||||
function dwarf_reg(r:tregister):byte;
|
||||
function GetHigh(const r : TRegister) : TRegister;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
rgBase,verbose;
|
||||
|
||||
|
||||
const
|
||||
std_regname_table : array[tregisterindex] of string[7] = (
|
||||
{$i ravrstd.inc}
|
||||
);
|
||||
|
||||
regnumber_index : array[tregisterindex] of tregisterindex = (
|
||||
{$i ravrrni.inc}
|
||||
);
|
||||
|
||||
std_regname_index : array[tregisterindex] of tregisterindex = (
|
||||
{$i ravrsri.inc}
|
||||
);
|
||||
|
||||
|
||||
function cgsize2subreg(s:Tcgsize):Tsubregister;
|
||||
begin
|
||||
cgsize2subreg:=R_SUBWHOLE;
|
||||
end;
|
||||
|
||||
|
||||
function reg_cgsize(const reg: tregister): tcgsize;
|
||||
const subreg2cgsize:array[Tsubregister] of Tcgsize =
|
||||
(OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO);
|
||||
begin
|
||||
case getregtype(reg) of
|
||||
R_INTREGISTER :
|
||||
reg_cgsize:=OS_32;
|
||||
R_FPUREGISTER :
|
||||
reg_cgsize:=OS_F80;
|
||||
else
|
||||
internalerror(200303181);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure inverse_flags(var f: TResFlags);
|
||||
const
|
||||
inv_flags: array[TResFlags] of TResFlags =
|
||||
(F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
|
||||
F_LT,F_GE,F_LE,F_GT);
|
||||
begin
|
||||
f:=inv_flags[f];
|
||||
end;
|
||||
|
||||
|
||||
function flags_to_cond(const f: TResFlags) : TAsmCond;
|
||||
const
|
||||
flag_2_cond: array[F_EQ..F_LE] of TAsmCond =
|
||||
(C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
|
||||
C_GE,C_LT,C_GT,C_LE);
|
||||
begin
|
||||
if f>high(flag_2_cond) then
|
||||
internalerror(200112301);
|
||||
result:=flag_2_cond[f];
|
||||
end;
|
||||
|
||||
|
||||
function findreg_by_number(r:Tregister):tregisterindex;
|
||||
begin
|
||||
result:=rgBase.findreg_by_number_table(r,regnumber_index);
|
||||
end;
|
||||
|
||||
|
||||
function std_regnum_search(const s:string):Tregister;
|
||||
begin
|
||||
result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
|
||||
end;
|
||||
|
||||
|
||||
function std_regname(r:Tregister):string;
|
||||
var
|
||||
p : tregisterindex;
|
||||
begin
|
||||
p:=findreg_by_number_table(r,regnumber_index);
|
||||
if p<>0 then
|
||||
result:=std_regname_table[p]
|
||||
else
|
||||
result:=generic_regname(r);
|
||||
end;
|
||||
|
||||
|
||||
procedure shifterop_reset(var so : tshifterop);
|
||||
begin
|
||||
FillChar(so,sizeof(so),0);
|
||||
end;
|
||||
|
||||
|
||||
function is_pc(const r : tregister) : boolean;
|
||||
begin
|
||||
is_pc:=(r=NR_R15);
|
||||
end;
|
||||
|
||||
|
||||
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
|
||||
const
|
||||
inverse: array[TAsmCond] of TAsmCond=(C_None,
|
||||
C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
|
||||
C_LT,C_GE,C_LE,C_GT,C_None,C_None
|
||||
);
|
||||
begin
|
||||
result := inverse[c];
|
||||
end;
|
||||
|
||||
|
||||
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
|
||||
begin
|
||||
result := c1 = c2;
|
||||
end;
|
||||
|
||||
|
||||
function rotl(d : dword;b : byte) : dword;
|
||||
begin
|
||||
result:=(d shr (32-b)) or (d shl b);
|
||||
end;
|
||||
|
||||
|
||||
function dwarf_reg(r:tregister):byte;
|
||||
begin
|
||||
result:=regdwarf_table[findreg_by_number(r)];
|
||||
if result=-1 then
|
||||
internalerror(200603251);
|
||||
end;
|
||||
|
||||
|
||||
function GetHigh(const r : TRegister) : TRegister;
|
||||
begin
|
||||
result:=TRegister(longint(r)+1)
|
||||
end;
|
||||
|
||||
end.
|
87
compiler/avr/cpuinfo.pas
Normal file
87
compiler/avr/cpuinfo.pas
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
Copyright (c) 1998-2002 by the Free Pascal development team
|
||||
|
||||
Basic Processor information for the ARM
|
||||
|
||||
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.
|
||||
|
||||
**********************************************************************}
|
||||
|
||||
Unit CPUInfo;
|
||||
|
||||
Interface
|
||||
|
||||
uses
|
||||
globtype;
|
||||
|
||||
Type
|
||||
bestreal = double;
|
||||
ts32real = single;
|
||||
ts64real = double;
|
||||
ts80real = type extended;
|
||||
ts128real = type extended;
|
||||
ts64comp = comp;
|
||||
|
||||
pbestreal=^bestreal;
|
||||
|
||||
{ possible supported processors for this target }
|
||||
tcputype =
|
||||
(cpu_none,
|
||||
cpu_avr
|
||||
);
|
||||
tfputype =
|
||||
(fpu_none,
|
||||
fpu_soft,
|
||||
fp_libgcc
|
||||
);
|
||||
|
||||
Const
|
||||
{# Size of native extended floating point type }
|
||||
extended_size = 12;
|
||||
{# Size of a multimedia register }
|
||||
mmreg_size = 16;
|
||||
{ target cpu string (used by compiler options) }
|
||||
target_cpu_string = 'arm';
|
||||
|
||||
{ calling conventions supported by the code generator }
|
||||
supported_calling_conventions : tproccalloptions = [
|
||||
pocall_internproc,
|
||||
pocall_safecall,
|
||||
pocall_stdcall,
|
||||
{ same as stdcall only different name mangling }
|
||||
pocall_cdecl,
|
||||
{ same as stdcall only different name mangling }
|
||||
pocall_cppdecl,
|
||||
{ same as stdcall but floating point numbers are handled like equal sized integers }
|
||||
pocall_softfloat
|
||||
];
|
||||
|
||||
cputypestr : array[tcputype] of string[5] = ('',
|
||||
'AVR'
|
||||
);
|
||||
|
||||
fputypestr : array[tfputype] of string[6] = ('',
|
||||
'SOFT',
|
||||
'LIBGCC'
|
||||
);
|
||||
|
||||
{ Supported optimizations, only used for information }
|
||||
supported_optimizerswitches = genericlevel1optimizerswitches+
|
||||
genericlevel2optimizerswitches+
|
||||
genericlevel3optimizerswitches-
|
||||
{ no need to write info about those }
|
||||
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
|
||||
[cs_opt_regvar,cs_opt_loopunroll,cs_opt_tailrecursion,cs_opt_stackframe];
|
||||
|
||||
level1optimizerswitches = genericlevel1optimizerswitches;
|
||||
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_regvar,cs_opt_stackframe,cs_opt_tailrecursion];
|
||||
level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
|
||||
|
||||
Implementation
|
||||
|
||||
end.
|
40
compiler/avr/cpunode.pas
Normal file
40
compiler/avr/cpunode.pas
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
Copyright (c) 2000-2008 by Florian Klaempfl
|
||||
|
||||
This unit includes the AVR code generator into the compiler
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
unit cpunode;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ generic nodes }
|
||||
ncgbas,ncgld,ncgflw,ncgcnv,ncgmem,ncgcon,ncgcal,ncgset,ncginl,ncgopt,ncgmat
|
||||
{ to be able to only parts of the generic code,
|
||||
the processor specific nodes must be included
|
||||
after the generic one (FK)
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
end.
|
490
compiler/avr/cpupara.pas
Normal file
490
compiler/avr/cpupara.pas
Normal file
@ -0,0 +1,490 @@
|
||||
{
|
||||
Copyright (c) 2008 by Florian Klaempfl
|
||||
|
||||
AVR specific calling conventions, it follows the GCC AVR calling conventions
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
****************************************************************************
|
||||
}
|
||||
{ ARM specific calling conventions are handled by this unit
|
||||
}
|
||||
unit cpupara;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
globtype,globals,
|
||||
aasmtai,aasmdata,
|
||||
cpuinfo,cpubase,cgbase,
|
||||
symconst,symbase,symtype,symdef,parabase,paramgr;
|
||||
|
||||
type
|
||||
tavrparamanager = class(tparamanager)
|
||||
function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
|
||||
function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
|
||||
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
|
||||
function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;override;
|
||||
procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
|
||||
function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
|
||||
function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
|
||||
private
|
||||
procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
|
||||
function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
|
||||
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
verbose,systems,
|
||||
rgobj,
|
||||
defutil,symsym,
|
||||
cgutils;
|
||||
|
||||
|
||||
function tavrparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
|
||||
begin
|
||||
result:=VOLATILE_INTREGISTERS;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
|
||||
begin
|
||||
result:=VOLATILE_FPUREGISTERS;
|
||||
end;
|
||||
|
||||
|
||||
procedure tavrparamanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
begin
|
||||
if nr<1 then
|
||||
internalerror(2002070801);
|
||||
cgpara.reset;
|
||||
cgpara.size:=OS_INT;
|
||||
cgpara.intsize:=tcgsize2size[OS_INT];
|
||||
cgpara.alignment:=std_param_align;
|
||||
paraloc:=cgpara.add_location;
|
||||
with paraloc^ do
|
||||
begin
|
||||
size:=OS_INT;
|
||||
{ the four first parameters are passed into registers }
|
||||
if nr<=4 then
|
||||
begin
|
||||
loc:=LOC_REGISTER;
|
||||
register:=newreg(R_INTREGISTER,RS_R0+nr-1,R_SUBWHOLE);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ the other parameters are passed on the stack }
|
||||
loc:=LOC_REFERENCE;
|
||||
reference.index:=NR_STACK_POINTER_REG;
|
||||
reference.offset:=(nr-5)*4;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function getparaloc(calloption : tproccalloption; p : tdef) : tcgloc;
|
||||
begin
|
||||
{ Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
|
||||
if push_addr_param for the def is true
|
||||
}
|
||||
case p.typ of
|
||||
orddef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
floatdef:
|
||||
if (calloption in [pocall_cdecl,pocall_cppdecl,pocall_softfloat]) or (cs_fp_emulation in current_settings.moduleswitches) then
|
||||
getparaloc:=LOC_REGISTER
|
||||
else
|
||||
getparaloc:=LOC_FPUREGISTER;
|
||||
enumdef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
pointerdef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
formaldef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
classrefdef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
recorddef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
objectdef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
stringdef:
|
||||
if is_shortstring(p) or is_longstring(p) then
|
||||
getparaloc:=LOC_REFERENCE
|
||||
else
|
||||
getparaloc:=LOC_REGISTER;
|
||||
procvardef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
filedef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
arraydef:
|
||||
getparaloc:=LOC_REFERENCE;
|
||||
setdef:
|
||||
if is_smallset(p) then
|
||||
getparaloc:=LOC_REGISTER
|
||||
else
|
||||
getparaloc:=LOC_REFERENCE;
|
||||
variantdef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
{ avoid problems with errornous definitions }
|
||||
errordef:
|
||||
getparaloc:=LOC_REGISTER;
|
||||
else
|
||||
internalerror(2002071001);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
|
||||
begin
|
||||
result:=false;
|
||||
if varspez in [vs_var,vs_out] then
|
||||
begin
|
||||
result:=true;
|
||||
exit;
|
||||
end;
|
||||
case def.typ of
|
||||
objectdef:
|
||||
result:=is_object(def) and ((varspez=vs_const) or (def.size=0));
|
||||
recorddef:
|
||||
result:=(varspez=vs_const) or (def.size=0);
|
||||
variantdef,
|
||||
formaldef:
|
||||
result:=true;
|
||||
arraydef:
|
||||
result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
|
||||
is_open_array(def) or
|
||||
is_array_of_const(def) or
|
||||
is_array_constructor(def);
|
||||
setdef :
|
||||
result:=(tsetdef(def).settype<>smallset);
|
||||
stringdef :
|
||||
result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
|
||||
begin
|
||||
case def.typ of
|
||||
recorddef:
|
||||
{ this is how gcc 4.0.4 on linux seems to do it, it doesn't look like being
|
||||
ARM ABI standard compliant
|
||||
}
|
||||
result:=not((trecorddef(def).symtable.SymList.count=1) and
|
||||
not(ret_in_param(tabstractvarsym(trecorddef(def).symtable.SymList[0]).vardef,calloption)));
|
||||
{
|
||||
objectdef
|
||||
arraydef:
|
||||
result:=not(def.size in [1,2,4]);
|
||||
}
|
||||
else
|
||||
result:=inherited ret_in_param(def,calloption);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tavrparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
|
||||
begin
|
||||
curintreg:=RS_R0;
|
||||
curfloatreg:=RS_INVALID;
|
||||
curmmreg:=RS_INVALID;
|
||||
cur_stack_offset:=0;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
|
||||
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
|
||||
|
||||
var
|
||||
nextintreg,nextfloatreg,nextmmreg : tsuperregister;
|
||||
paradef : tdef;
|
||||
paraloc : pcgparalocation;
|
||||
stack_offset : aword;
|
||||
hp : tparavarsym;
|
||||
loc : tcgloc;
|
||||
paracgsize : tcgsize;
|
||||
paralen : longint;
|
||||
i : integer;
|
||||
|
||||
procedure assignintreg;
|
||||
begin
|
||||
if nextintreg<=RS_R3 then
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
|
||||
inc(nextintreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,4);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
result:=0;
|
||||
nextintreg:=curintreg;
|
||||
nextfloatreg:=curfloatreg;
|
||||
nextmmreg:=curmmreg;
|
||||
stack_offset:=cur_stack_offset;
|
||||
|
||||
for i:=0 to paras.count-1 do
|
||||
begin
|
||||
hp:=tparavarsym(paras[i]);
|
||||
paradef:=hp.vardef;
|
||||
|
||||
hp.paraloc[side].reset;
|
||||
|
||||
{ currently only support C-style array of const,
|
||||
there should be no location assigned to the vararg array itself }
|
||||
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
|
||||
is_array_of_const(paradef) then
|
||||
begin
|
||||
paraloc:=hp.paraloc[side].add_location;
|
||||
{ hack: the paraloc must be valid, but is not actually used }
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=NR_R0;
|
||||
paraloc^.size:=OS_ADDR;
|
||||
break;
|
||||
end;
|
||||
|
||||
if (hp.varspez in [vs_var,vs_out]) or
|
||||
push_addr_param(hp.varspez,paradef,p.proccalloption) or
|
||||
is_open_array(paradef) or
|
||||
is_array_of_const(paradef) then
|
||||
begin
|
||||
paradef:=voidpointertype;
|
||||
loc:=LOC_REGISTER;
|
||||
paracgsize := OS_ADDR;
|
||||
paralen := tcgsize2size[OS_ADDR];
|
||||
end
|
||||
else
|
||||
begin
|
||||
if not is_special_array(paradef) then
|
||||
paralen := paradef.size
|
||||
else
|
||||
paralen := tcgsize2size[def_cgsize(paradef)];
|
||||
loc := getparaloc(p.proccalloption,paradef);
|
||||
if (paradef.typ in [objectdef,arraydef,recorddef]) and
|
||||
not is_special_array(paradef) and
|
||||
(hp.varspez in [vs_value,vs_const]) then
|
||||
paracgsize := int_cgsize(paralen)
|
||||
else
|
||||
begin
|
||||
paracgsize:=def_cgsize(paradef);
|
||||
{ for things like formaldef }
|
||||
if (paracgsize=OS_NO) then
|
||||
begin
|
||||
paracgsize:=OS_ADDR;
|
||||
paralen := tcgsize2size[OS_ADDR];
|
||||
end;
|
||||
end
|
||||
end;
|
||||
|
||||
hp.paraloc[side].size:=paracgsize;
|
||||
hp.paraloc[side].Alignment:=std_param_align;
|
||||
hp.paraloc[side].intsize:=paralen;
|
||||
|
||||
{$ifdef EXTDEBUG}
|
||||
if paralen=0 then
|
||||
internalerror(200410311);
|
||||
{$endif EXTDEBUG}
|
||||
while paralen>0 do
|
||||
begin
|
||||
paraloc:=hp.paraloc[side].add_location;
|
||||
|
||||
if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
|
||||
case paracgsize of
|
||||
OS_F32:
|
||||
paraloc^.size:=OS_32;
|
||||
OS_F64:
|
||||
paraloc^.size:=OS_32;
|
||||
else
|
||||
internalerror(2005082901);
|
||||
end
|
||||
else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
|
||||
paraloc^.size := OS_32
|
||||
else
|
||||
paraloc^.size:=paracgsize;
|
||||
case loc of
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
{ this is not abi compliant
|
||||
why? (FK) }
|
||||
if nextintreg<=RS_R3 then
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
|
||||
inc(nextintreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ LOC_REFERENCE covers always the overleft }
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.size:=int_cgsize(paralen);
|
||||
if (side=callerside) then
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,align(paralen,4));
|
||||
paralen:=0;
|
||||
end;
|
||||
end;
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
paraloc^.size:=OS_ADDR;
|
||||
if push_addr_param(hp.varspez,paradef,p.proccalloption) or
|
||||
is_open_array(paradef) or
|
||||
is_array_of_const(paradef) then
|
||||
assignintreg
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,hp.vardef.size);
|
||||
end;
|
||||
end;
|
||||
else
|
||||
internalerror(2002071002);
|
||||
end;
|
||||
if side=calleeside then
|
||||
begin
|
||||
if paraloc^.loc=LOC_REFERENCE then
|
||||
begin
|
||||
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
||||
inc(paraloc^.reference.offset,4);
|
||||
end;
|
||||
end;
|
||||
dec(paralen,tcgsize2size[paraloc^.size]);
|
||||
end;
|
||||
end;
|
||||
curintreg:=nextintreg;
|
||||
curfloatreg:=nextfloatreg;
|
||||
curmmreg:=nextmmreg;
|
||||
cur_stack_offset:=stack_offset;
|
||||
result:=cur_stack_offset;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
|
||||
var
|
||||
cur_stack_offset: aword;
|
||||
curintreg, curfloatreg, curmmreg: tsuperregister;
|
||||
retcgsize : tcgsize;
|
||||
begin
|
||||
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
|
||||
|
||||
result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
|
||||
|
||||
{ Constructors return self instead of a boolean }
|
||||
if (p.proctypeoption=potype_constructor) then
|
||||
retcgsize:=OS_ADDR
|
||||
else
|
||||
retcgsize:=def_cgsize(p.returndef);
|
||||
|
||||
location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
|
||||
p.funcretloc[side].size:=retcgsize;
|
||||
|
||||
{ void has no location }
|
||||
if is_void(p.returndef) then
|
||||
begin
|
||||
location_reset(p.funcretloc[side],LOC_VOID,OS_NO);
|
||||
exit;
|
||||
end;
|
||||
{ Return is passed as var parameter }
|
||||
if ret_in_param(p.returndef,p.proccalloption) then
|
||||
begin
|
||||
p.funcretloc[side].loc:=LOC_REFERENCE;
|
||||
p.funcretloc[side].size:=retcgsize;
|
||||
exit;
|
||||
end;
|
||||
{ Return in FPU register? }
|
||||
if p.returndef.typ=floatdef then
|
||||
begin
|
||||
if (p.proccalloption in [pocall_softfloat]) or (cs_fp_emulation in current_settings.moduleswitches) then
|
||||
begin
|
||||
case retcgsize of
|
||||
OS_64,
|
||||
OS_F64:
|
||||
begin
|
||||
{ low }
|
||||
p.funcretloc[side].loc:=LOC_REGISTER;
|
||||
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG;
|
||||
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG;
|
||||
p.funcretloc[side].size:=OS_64;
|
||||
end;
|
||||
OS_32,
|
||||
OS_F32:
|
||||
begin
|
||||
p.funcretloc[side].loc:=LOC_REGISTER;
|
||||
p.funcretloc[side].register:=NR_FUNCTION_RETURN_REG;
|
||||
p.funcretloc[side].size:=OS_32;
|
||||
end;
|
||||
else
|
||||
internalerror(2005082603);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
p.funcretloc[side].loc:=LOC_FPUREGISTER;
|
||||
p.funcretloc[side].register:=NR_FPU_RESULT_REG;
|
||||
end;
|
||||
end
|
||||
{ Return in register }
|
||||
else
|
||||
begin
|
||||
if retcgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
{ low }
|
||||
p.funcretloc[side].loc:=LOC_REGISTER;
|
||||
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG;
|
||||
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG;
|
||||
end
|
||||
else
|
||||
begin
|
||||
p.funcretloc[side].loc:=LOC_REGISTER;
|
||||
p.funcretloc[side].register:=NR_FUNCTION_RETURN_REG;
|
||||
end;
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tavrparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
|
||||
var
|
||||
cur_stack_offset: aword;
|
||||
curintreg, curfloatreg, curmmreg: tsuperregister;
|
||||
begin
|
||||
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
|
||||
|
||||
result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
|
||||
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
|
||||
{ just continue loading the parameters in the registers }
|
||||
result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset)
|
||||
else
|
||||
internalerror(200410231);
|
||||
end;
|
||||
|
||||
begin
|
||||
paramanager:=tavrparamanager.create;
|
||||
end.
|
84
compiler/avr/cpupi.pas
Normal file
84
compiler/avr/cpupi.pas
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
Copyright (c) 2008 by Florian Klaempfl
|
||||
|
||||
This unit contains the CPU specific part of tprocinfo
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
|
||||
{ This unit contains the CPU specific part of tprocinfo. }
|
||||
unit cpupi;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
globtype,cutils,
|
||||
procinfo,cpuinfo,psub;
|
||||
|
||||
type
|
||||
tavrprocinfo = class(tcgprocinfo)
|
||||
floatregstart : aint;
|
||||
// procedure handle_body_start;override;
|
||||
// procedure after_pass1;override;
|
||||
procedure set_first_temp_offset;override;
|
||||
function calc_stackframe_size:longint;override;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
globals,systems,
|
||||
cpubase,
|
||||
aasmtai,aasmdata,
|
||||
tgobj,
|
||||
symconst,symsym,paramgr,
|
||||
cgbase,
|
||||
cgobj;
|
||||
|
||||
procedure tavrprocinfo.set_first_temp_offset;
|
||||
begin
|
||||
{ We allocate enough space to save all registers because we can't determine
|
||||
the necessary space because the used registers aren't known before
|
||||
secondpass is run. Even worse, patching
|
||||
the local offsets after generating the code could cause trouble because
|
||||
"shifter" constants could change to non-"shifter" constants. This
|
||||
is especially a problem when taking the address of a local. For now,
|
||||
this extra memory should hurt less than generating all local contants with offsets
|
||||
>256 as non shifter constants }
|
||||
if tg.direction = -1 then
|
||||
tg.setfirsttemp(-12-28)
|
||||
else
|
||||
tg.setfirsttemp(maxpushedparasize);
|
||||
end;
|
||||
|
||||
|
||||
function tavrprocinfo.calc_stackframe_size:longint;
|
||||
var
|
||||
firstfloatreg,lastfloatreg,
|
||||
r : byte;
|
||||
floatsavesize : aword;
|
||||
begin
|
||||
maxpushedparasize:=align(maxpushedparasize,max(current_settings.alignment.localalignmin,4));
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
cprocinfo:=tavrprocinfo;
|
||||
end.
|
72
compiler/avr/cputarg.pas
Normal file
72
compiler/avr/cputarg.pas
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
Copyright (c) 2001-2008 by Peter Vreman
|
||||
|
||||
Includes the AVR dependent target units
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
unit cputarg;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
systems { prevent a syntax error when nothing is included }
|
||||
|
||||
{**************************************
|
||||
Targets
|
||||
**************************************}
|
||||
|
||||
{$ifndef NOTARGETEMBEDDED}
|
||||
,t_embed
|
||||
{$endif}
|
||||
|
||||
{**************************************
|
||||
Assemblers
|
||||
**************************************}
|
||||
|
||||
{$ifndef NOAGARMGAS}
|
||||
,agarmgas
|
||||
{$endif}
|
||||
|
||||
,ogcoff
|
||||
|
||||
{**************************************
|
||||
Assembler Readers
|
||||
**************************************}
|
||||
|
||||
{$ifndef NoRaarmgas}
|
||||
,raarmgas
|
||||
{$endif NoRaarmgas}
|
||||
|
||||
{**************************************
|
||||
Debuginfo
|
||||
**************************************}
|
||||
|
||||
{$ifndef NoDbgStabs}
|
||||
,dbgstabs
|
||||
{$endif NoDbgStabs}
|
||||
{$ifndef NoDbgDwarf}
|
||||
,dbgdwarf
|
||||
{$endif NoDbgDwarf}
|
||||
;
|
||||
|
||||
end.
|
34
compiler/avr/ravrcon.inc
Normal file
34
compiler/avr/ravrcon.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
NR_NO = tregister($00000000);
|
||||
NR_R0 = tregister($01000000);
|
||||
NR_R1 = tregister($01000001);
|
||||
NR_R2 = tregister($01000002);
|
||||
NR_R3 = tregister($01000003);
|
||||
NR_R4 = tregister($01000004);
|
||||
NR_R5 = tregister($01000005);
|
||||
NR_R6 = tregister($01000006);
|
||||
NR_R7 = tregister($01000007);
|
||||
NR_R8 = tregister($01000008);
|
||||
NR_R9 = tregister($01000009);
|
||||
NR_R10 = tregister($0100000a);
|
||||
NR_R11 = tregister($0100000b);
|
||||
NR_R12 = tregister($0100000c);
|
||||
NR_R13 = tregister($0100000d);
|
||||
NR_R14 = tregister($0100000e);
|
||||
NR_R15 = tregister($0100000f);
|
||||
NR_R16 = tregister($01000010);
|
||||
NR_R17 = tregister($01000011);
|
||||
NR_R18 = tregister($01000012);
|
||||
NR_R19 = tregister($01000013);
|
||||
NR_R20 = tregister($01000014);
|
||||
NR_R21 = tregister($01000015);
|
||||
NR_R22 = tregister($01000016);
|
||||
NR_R23 = tregister($01000017);
|
||||
NR_R24 = tregister($01000018);
|
||||
NR_R25 = tregister($01000019);
|
||||
NR_R26 = tregister($0100001a);
|
||||
NR_R27 = tregister($0100001b);
|
||||
NR_R28 = tregister($0100001c);
|
||||
NR_R29 = tregister($0100001d);
|
||||
NR_R30 = tregister($0100001e);
|
||||
NR_R31 = tregister($0100001f);
|
34
compiler/avr/ravrdwa.inc
Normal file
34
compiler/avr/ravrdwa.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31
|
2
compiler/avr/ravrnor.inc
Normal file
2
compiler/avr/ravrnor.inc
Normal file
@ -0,0 +1,2 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
33
|
34
compiler/avr/ravrnum.inc
Normal file
34
compiler/avr/ravrnum.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
tregister($00000000),
|
||||
tregister($01000000),
|
||||
tregister($01000001),
|
||||
tregister($01000002),
|
||||
tregister($01000003),
|
||||
tregister($01000004),
|
||||
tregister($01000005),
|
||||
tregister($01000006),
|
||||
tregister($01000007),
|
||||
tregister($01000008),
|
||||
tregister($01000009),
|
||||
tregister($0100000a),
|
||||
tregister($0100000b),
|
||||
tregister($0100000c),
|
||||
tregister($0100000d),
|
||||
tregister($0100000e),
|
||||
tregister($0100000f),
|
||||
tregister($01000010),
|
||||
tregister($01000011),
|
||||
tregister($01000012),
|
||||
tregister($01000013),
|
||||
tregister($01000014),
|
||||
tregister($01000015),
|
||||
tregister($01000016),
|
||||
tregister($01000017),
|
||||
tregister($01000018),
|
||||
tregister($01000019),
|
||||
tregister($0100001a),
|
||||
tregister($0100001b),
|
||||
tregister($0100001c),
|
||||
tregister($0100001d),
|
||||
tregister($0100001e),
|
||||
tregister($0100001f)
|
34
compiler/avr/ravrrni.inc
Normal file
34
compiler/avr/ravrrni.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32
|
34
compiler/avr/ravrsri.inc
Normal file
34
compiler/avr/ravrsri.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
3,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
4,
|
||||
31,
|
||||
32,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
34
compiler/avr/ravrsta.inc
Normal file
34
compiler/avr/ravrsta.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31
|
34
compiler/avr/ravrstd.inc
Normal file
34
compiler/avr/ravrstd.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
'INVALID',
|
||||
'r0',
|
||||
'r1',
|
||||
'r2',
|
||||
'r3',
|
||||
'r4',
|
||||
'r5',
|
||||
'r6',
|
||||
'r7',
|
||||
'r8',
|
||||
'r9',
|
||||
'r10',
|
||||
'r11',
|
||||
'r12',
|
||||
'r13',
|
||||
'r14',
|
||||
'r15',
|
||||
'r16',
|
||||
'r17',
|
||||
'r18',
|
||||
'r19',
|
||||
'r20',
|
||||
'r21',
|
||||
'r22',
|
||||
'r23',
|
||||
'r24',
|
||||
'r25',
|
||||
'r26',
|
||||
'r27',
|
||||
'r28',
|
||||
'r29',
|
||||
'r30',
|
||||
'r31'
|
34
compiler/avr/ravrsup.inc
Normal file
34
compiler/avr/ravrsup.inc
Normal file
@ -0,0 +1,34 @@
|
||||
{ don't edit, this file is generated from avrreg.dat }
|
||||
RS_NO = $00;
|
||||
RS_R0 = $00;
|
||||
RS_R1 = $01;
|
||||
RS_R2 = $02;
|
||||
RS_R3 = $03;
|
||||
RS_R4 = $04;
|
||||
RS_R5 = $05;
|
||||
RS_R6 = $06;
|
||||
RS_R7 = $07;
|
||||
RS_R8 = $08;
|
||||
RS_R9 = $09;
|
||||
RS_R10 = $0a;
|
||||
RS_R11 = $0b;
|
||||
RS_R12 = $0c;
|
||||
RS_R13 = $0d;
|
||||
RS_R14 = $0e;
|
||||
RS_R15 = $0f;
|
||||
RS_R16 = $10;
|
||||
RS_R17 = $11;
|
||||
RS_R18 = $12;
|
||||
RS_R19 = $13;
|
||||
RS_R20 = $14;
|
||||
RS_R21 = $15;
|
||||
RS_R22 = $16;
|
||||
RS_R23 = $17;
|
||||
RS_R24 = $18;
|
||||
RS_R25 = $19;
|
||||
RS_R26 = $1a;
|
||||
RS_R27 = $1b;
|
||||
RS_R28 = $1c;
|
||||
RS_R29 = $1d;
|
||||
RS_R30 = $1e;
|
||||
RS_R31 = $1f;
|
80
compiler/avr/rgcpu.pas
Normal file
80
compiler/avr/rgcpu.pas
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
Copyright (c) 1998-2008 by Florian Klaempfl
|
||||
|
||||
This unit implements the avr specific class for the register
|
||||
allocator
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
|
||||
unit rgcpu;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
aasmbase,aasmtai,aasmdata,aasmcpu,
|
||||
cgbase,cgutils,
|
||||
cpubase,
|
||||
rgobj;
|
||||
|
||||
type
|
||||
trgcpu = class(trgobj)
|
||||
procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
|
||||
procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
|
||||
end;
|
||||
|
||||
trgintcpu = class(trgcpu)
|
||||
procedure add_cpu_interferences(p : tai);override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
verbose, cutils,
|
||||
cgobj,
|
||||
procinfo;
|
||||
|
||||
|
||||
procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
|
||||
begin
|
||||
inherited do_spill_read(list,pos,spilltemp,tempreg);
|
||||
end;
|
||||
|
||||
|
||||
procedure trgcpu.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
|
||||
begin
|
||||
inherited do_spill_written(list,pos,spilltemp,tempreg);
|
||||
end;
|
||||
|
||||
|
||||
procedure trgintcpu.add_cpu_interferences(p : tai);
|
||||
var
|
||||
r : tregister;
|
||||
begin
|
||||
if p.typ=ait_instruction then
|
||||
begin
|
||||
case taicpu(p).opcode of
|
||||
A_LD:
|
||||
;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
@ -47,6 +47,7 @@
|
||||
{$endif cpuarm}
|
||||
|
||||
{$ifdef i386}
|
||||
{$define cpu32bit}
|
||||
{$define x86}
|
||||
{$define cpuflags}
|
||||
{$define cpuextended}
|
||||
@ -72,11 +73,13 @@
|
||||
{$endif alpha}
|
||||
|
||||
{$ifdef sparc}
|
||||
{$define cpu32bit}
|
||||
{$define cpuflags}
|
||||
{$define cputargethasfixedstack}
|
||||
{$endif sparc}
|
||||
|
||||
{$ifdef powerpc}
|
||||
{$define cpu32bit}
|
||||
{$define cpuflags}
|
||||
{$define cputargethasfixedstack}
|
||||
{$define cpumm}
|
||||
@ -90,6 +93,7 @@
|
||||
{$endif powerpc64}
|
||||
|
||||
{$ifdef arm}
|
||||
{$define cpu32bit}
|
||||
{$define cpuflags}
|
||||
{$define cpufpemu}
|
||||
{$define cpuneedsdiv32helper}
|
||||
@ -97,10 +101,17 @@
|
||||
{$endif arm}
|
||||
|
||||
{$ifdef m68k}
|
||||
{$define cpu32bit}
|
||||
{$define cpuflags}
|
||||
{$define cpufpemu}
|
||||
{$endif m68k}
|
||||
|
||||
{$ifdef avr}
|
||||
{$define cpu16bit}
|
||||
{$define cpuflags}
|
||||
{$define cpunofpu}
|
||||
{$endif avr}
|
||||
|
||||
{$IFDEF MACOS}
|
||||
{$DEFINE USE_FAKE_SYSUTILS}
|
||||
{$ENDIF MACOS}
|
||||
|
@ -894,7 +894,11 @@ implementation
|
||||
{ END is read, got a list of changed registers? }
|
||||
if try_to_consume(_LECKKLAMMER) then
|
||||
begin
|
||||
{$ifdef cpunofpu}
|
||||
asmstat.used_regs_fpu:=[0..first_int_imreg-1];
|
||||
{$else cpunofpu}
|
||||
asmstat.used_regs_fpu:=[0..first_fpu_imreg-1];
|
||||
{$endif cpunofpu}
|
||||
if token<>_RECKKLAMMER then
|
||||
begin
|
||||
if po_assembler in current_procinfo.procdef.procoptions then
|
||||
|
@ -409,12 +409,18 @@ implementation
|
||||
sinttype:=s64inttype;
|
||||
ptruinttype:=u64inttype;
|
||||
ptrsinttype:=s64inttype;
|
||||
{$else cpu64bit}
|
||||
{$endif cpu64bit}
|
||||
{$ifdef cpu32bit}
|
||||
uinttype:=u32inttype;
|
||||
sinttype:=s32inttype;
|
||||
ptruinttype:=u32inttype;
|
||||
ptrsinttype:=s32inttype;
|
||||
{$endif cpu64bit}
|
||||
{$endif cpu32bit}
|
||||
{$ifdef cpu16bit}
|
||||
uinttype:=u16inttype;
|
||||
sinttype:=s16inttype;
|
||||
ptrinttype:=u16inttype;
|
||||
{$endif cpu16bit}
|
||||
set_current_module(oldcurrentmodule);
|
||||
end;
|
||||
|
||||
|
@ -661,6 +661,9 @@ interface
|
||||
{$ifdef MIPS}
|
||||
pbestrealtype : ^tdef = @s64floattype;
|
||||
{$endif MIPS}
|
||||
{$ifdef AVR}
|
||||
pbestrealtype : ^tdef = @s64floattype;
|
||||
{$endif AVR}
|
||||
|
||||
function make_mangledname(const typeprefix:string;st:TSymtable;const suffix:string):string;
|
||||
|
||||
|
275
compiler/utils/mkavrreg.pp
Normal file
275
compiler/utils/mkavrreg.pp
Normal file
@ -0,0 +1,275 @@
|
||||
{
|
||||
Copyright (c) 1998-2002 by Peter Vreman and Florian Klaempfl
|
||||
|
||||
Convert spreg.dat to several .inc files for usage with
|
||||
the Free pascal compiler
|
||||
|
||||
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.
|
||||
|
||||
**********************************************************************}
|
||||
program mkspreg;
|
||||
|
||||
const Version = '1.00';
|
||||
max_regcount = 200;
|
||||
|
||||
var s : string;
|
||||
i : longint;
|
||||
line : longint;
|
||||
regcount:byte;
|
||||
regcount_bsstart:byte;
|
||||
names,
|
||||
regtypes,
|
||||
supregs,
|
||||
numbers,
|
||||
stdnames,
|
||||
stabs,dwarf : array[0..max_regcount-1] of string[63];
|
||||
regnumber_index,
|
||||
std_regname_index : array[0..max_regcount-1] of byte;
|
||||
|
||||
function tostr(l : longint) : string;
|
||||
|
||||
begin
|
||||
str(l,tostr);
|
||||
end;
|
||||
|
||||
function readstr : string;
|
||||
|
||||
var
|
||||
result : string;
|
||||
|
||||
begin
|
||||
result:='';
|
||||
while (s[i]<>',') and (i<=length(s)) do
|
||||
begin
|
||||
result:=result+s[i];
|
||||
inc(i);
|
||||
end;
|
||||
readstr:=result;
|
||||
end;
|
||||
|
||||
|
||||
procedure readcomma;
|
||||
begin
|
||||
if s[i]<>',' then
|
||||
begin
|
||||
writeln('Missing "," at line ',line);
|
||||
writeln('Line: "',s,'"');
|
||||
halt(1);
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
|
||||
|
||||
procedure skipspace;
|
||||
|
||||
begin
|
||||
while (s[i] in [' ',#9]) do
|
||||
inc(i);
|
||||
end;
|
||||
|
||||
procedure openinc(var f:text;const fn:string);
|
||||
begin
|
||||
writeln('creating ',fn);
|
||||
assign(f,fn);
|
||||
rewrite(f);
|
||||
writeln(f,'{ don''t edit, this file is generated from avrreg.dat }');
|
||||
end;
|
||||
|
||||
|
||||
procedure closeinc(var f:text);
|
||||
begin
|
||||
writeln(f);
|
||||
close(f);
|
||||
end;
|
||||
|
||||
procedure build_regnum_index;
|
||||
|
||||
var h,i,j,p,t:byte;
|
||||
|
||||
begin
|
||||
{Build the registernumber2regindex index.
|
||||
Step 1: Fill.}
|
||||
for i:=0 to regcount-1 do
|
||||
regnumber_index[i]:=i;
|
||||
{Step 2: Sort. We use a Shell-Metzner sort.}
|
||||
p:=regcount_bsstart;
|
||||
repeat
|
||||
for h:=0 to regcount-p-1 do
|
||||
begin
|
||||
i:=h;
|
||||
repeat
|
||||
j:=i+p;
|
||||
if numbers[regnumber_index[j]]>=numbers[regnumber_index[i]] then
|
||||
break;
|
||||
t:=regnumber_index[i];
|
||||
regnumber_index[i]:=regnumber_index[j];
|
||||
regnumber_index[j]:=t;
|
||||
if i<p then
|
||||
break;
|
||||
dec(i,p);
|
||||
until false;
|
||||
end;
|
||||
p:=p shr 1;
|
||||
until p=0;
|
||||
end;
|
||||
|
||||
procedure build_std_regname_index;
|
||||
|
||||
var h,i,j,p,t:byte;
|
||||
|
||||
begin
|
||||
{Build the registernumber2regindex index.
|
||||
Step 1: Fill.}
|
||||
for i:=0 to regcount-1 do
|
||||
std_regname_index[i]:=i;
|
||||
{Step 2: Sort. We use a Shell-Metzner sort.}
|
||||
p:=regcount_bsstart;
|
||||
repeat
|
||||
for h:=0 to regcount-p-1 do
|
||||
begin
|
||||
i:=h;
|
||||
repeat
|
||||
j:=i+p;
|
||||
if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then
|
||||
break;
|
||||
t:=std_regname_index[i];
|
||||
std_regname_index[i]:=std_regname_index[j];
|
||||
std_regname_index[j]:=t;
|
||||
if i<p then
|
||||
break;
|
||||
dec(i,p);
|
||||
until false;
|
||||
end;
|
||||
p:=p shr 1;
|
||||
until p=0;
|
||||
end;
|
||||
|
||||
|
||||
procedure read_spreg_file;
|
||||
|
||||
var infile:text;
|
||||
|
||||
begin
|
||||
{ open dat file }
|
||||
assign(infile,'avrreg.dat');
|
||||
reset(infile);
|
||||
while not(eof(infile)) do
|
||||
begin
|
||||
{ handle comment }
|
||||
readln(infile,s);
|
||||
inc(line);
|
||||
while (s[1]=' ') do
|
||||
delete(s,1,1);
|
||||
if (s='') or (s[1]=';') then
|
||||
continue;
|
||||
|
||||
i:=1;
|
||||
names[regcount]:=readstr;
|
||||
readcomma;
|
||||
regtypes[regcount]:=readstr;
|
||||
readcomma;
|
||||
supregs[regcount]:=readstr;
|
||||
readcomma;
|
||||
stdnames[regcount]:=readstr;
|
||||
readcomma;
|
||||
stabs[regcount]:=readstr;
|
||||
readcomma;
|
||||
dwarf[regcount]:=readstr;
|
||||
{ Create register number }
|
||||
if supregs[regcount][1]<>'$' then
|
||||
begin
|
||||
writeln('Missing $ before number, at line ',line);
|
||||
writeln('Line: "',s,'"');
|
||||
halt(1);
|
||||
end;
|
||||
numbers[regcount]:=regtypes[regcount]+'0000'+copy(supregs[regcount],2,255);
|
||||
if i<length(s) then
|
||||
begin
|
||||
writeln('Extra chars at end of line, at line ',line);
|
||||
writeln('Line: "',s,'"');
|
||||
halt(1);
|
||||
end;
|
||||
inc(regcount);
|
||||
if regcount>max_regcount then
|
||||
begin
|
||||
writeln('Error: Too much registers, please increase maxregcount in source');
|
||||
halt(2);
|
||||
end;
|
||||
end;
|
||||
close(infile);
|
||||
end;
|
||||
|
||||
procedure write_inc_files;
|
||||
|
||||
var
|
||||
norfile,stdfile,supfile,
|
||||
numfile,stabfile,dwarffile,confile,
|
||||
rnifile,srifile:text;
|
||||
first:boolean;
|
||||
|
||||
begin
|
||||
{ create inc files }
|
||||
openinc(confile,'ravrcon.inc');
|
||||
openinc(supfile,'ravrsup.inc');
|
||||
openinc(numfile,'ravrnum.inc');
|
||||
openinc(stdfile,'ravrstd.inc');
|
||||
openinc(stabfile,'ravrsta.inc');
|
||||
openinc(dwarffile,'ravrdwa.inc');
|
||||
openinc(norfile,'ravrnor.inc');
|
||||
openinc(rnifile,'ravrrni.inc');
|
||||
openinc(srifile,'ravrsri.inc');
|
||||
first:=true;
|
||||
for i:=0 to regcount-1 do
|
||||
begin
|
||||
if not first then
|
||||
begin
|
||||
writeln(numfile,',');
|
||||
writeln(stdfile,',');
|
||||
writeln(stabfile,',');
|
||||
writeln(dwarffile,',');
|
||||
writeln(rnifile,',');
|
||||
writeln(srifile,',');
|
||||
end
|
||||
else
|
||||
first:=false;
|
||||
writeln(supfile,'RS_',names[i],' = ',supregs[i],';');
|
||||
writeln(confile,'NR_'+names[i],' = ','tregister(',numbers[i],')',';');
|
||||
write(numfile,'tregister(',numbers[i],')');
|
||||
write(stdfile,'''',stdnames[i],'''');
|
||||
write(stabfile,stabs[i]);
|
||||
write(dwarffile,dwarf[i]);
|
||||
write(rnifile,regnumber_index[i]);
|
||||
write(srifile,std_regname_index[i]);
|
||||
end;
|
||||
write(norfile,regcount);
|
||||
close(confile);
|
||||
close(supfile);
|
||||
closeinc(numfile);
|
||||
closeinc(stdfile);
|
||||
closeinc(stabfile);
|
||||
closeinc(dwarffile);
|
||||
closeinc(norfile);
|
||||
closeinc(rnifile);
|
||||
closeinc(srifile);
|
||||
writeln('Done!');
|
||||
writeln(regcount,' registers procesed');
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
writeln('Register Table Converter Version ',Version);
|
||||
line:=0;
|
||||
regcount:=0;
|
||||
read_spreg_file;
|
||||
regcount_bsstart:=1;
|
||||
while 2*regcount_bsstart<regcount do
|
||||
regcount_bsstart:=regcount_bsstart*2;
|
||||
build_regnum_index;
|
||||
build_std_regname_index;
|
||||
write_inc_files;
|
||||
end.
|
Loading…
Reference in New Issue
Block a user