diff --git a/.gitattributes b/.gitattributes index 698348e0d6..3a6a5e4877 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/compiler/avr/aasmcpu.pas b/compiler/avr/aasmcpu.pas new file mode 100644 index 0000000000..7b8e8564e5 --- /dev/null +++ b/compiler/avr/aasmcpu.pas @@ -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. diff --git a/compiler/avr/aoptcpu.pas b/compiler/avr/aoptcpu.pas new file mode 100644 index 0000000000..18d74edd3c --- /dev/null +++ b/compiler/avr/aoptcpu.pas @@ -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. diff --git a/compiler/avr/aoptcpub.pas b/compiler/avr/aoptcpub.pas new file mode 100644 index 0000000000..c56bd8b31f --- /dev/null +++ b/compiler/avr/aoptcpub.pas @@ -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. diff --git a/compiler/avr/aoptcpud.pas b/compiler/avr/aoptcpud.pas new file mode 100644 index 0000000000..2df7e2e49e --- /dev/null +++ b/compiler/avr/aoptcpud.pas @@ -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. diff --git a/compiler/avr/avrreg.dat b/compiler/avr/avrreg.dat new file mode 100644 index 0000000000..83c71dec1d --- /dev/null +++ b/compiler/avr/avrreg.dat @@ -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 + diff --git a/compiler/avr/cgcpu.pas b/compiler/avr/cgcpu.pas new file mode 100644 index 0000000000..aa91f79980 --- /dev/null +++ b/compiler/avr/cgcpu.pas @@ -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. diff --git a/compiler/avr/cpubase.pas b/compiler/avr/cpubase.pas new file mode 100644 index 0000000000..ebcf1f71e3 --- /dev/null +++ b/compiler/avr/cpubase.pas @@ -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. diff --git a/compiler/avr/cpuinfo.pas b/compiler/avr/cpuinfo.pas new file mode 100644 index 0000000000..d94e980b68 --- /dev/null +++ b/compiler/avr/cpuinfo.pas @@ -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. diff --git a/compiler/avr/cpunode.pas b/compiler/avr/cpunode.pas new file mode 100644 index 0000000000..10ca66f692 --- /dev/null +++ b/compiler/avr/cpunode.pas @@ -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. diff --git a/compiler/avr/cpupara.pas b/compiler/avr/cpupara.pas new file mode 100644 index 0000000000..be965e484b --- /dev/null +++ b/compiler/avr/cpupara.pas @@ -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. diff --git a/compiler/avr/cpupi.pas b/compiler/avr/cpupi.pas new file mode 100644 index 0000000000..18a92a8f4a --- /dev/null +++ b/compiler/avr/cpupi.pas @@ -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. diff --git a/compiler/avr/cputarg.pas b/compiler/avr/cputarg.pas new file mode 100644 index 0000000000..c6bbcca79e --- /dev/null +++ b/compiler/avr/cputarg.pas @@ -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. diff --git a/compiler/avr/ravrcon.inc b/compiler/avr/ravrcon.inc new file mode 100644 index 0000000000..b5f01d44a4 --- /dev/null +++ b/compiler/avr/ravrcon.inc @@ -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); diff --git a/compiler/avr/ravrdwa.inc b/compiler/avr/ravrdwa.inc new file mode 100644 index 0000000000..4231ab6f18 --- /dev/null +++ b/compiler/avr/ravrdwa.inc @@ -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 diff --git a/compiler/avr/ravrnor.inc b/compiler/avr/ravrnor.inc new file mode 100644 index 0000000000..6640bf866a --- /dev/null +++ b/compiler/avr/ravrnor.inc @@ -0,0 +1,2 @@ +{ don't edit, this file is generated from avrreg.dat } +33 diff --git a/compiler/avr/ravrnum.inc b/compiler/avr/ravrnum.inc new file mode 100644 index 0000000000..92e62c897f --- /dev/null +++ b/compiler/avr/ravrnum.inc @@ -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) diff --git a/compiler/avr/ravrrni.inc b/compiler/avr/ravrrni.inc new file mode 100644 index 0000000000..9f5aa02027 --- /dev/null +++ b/compiler/avr/ravrrni.inc @@ -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 diff --git a/compiler/avr/ravrsri.inc b/compiler/avr/ravrsri.inc new file mode 100644 index 0000000000..771be07f06 --- /dev/null +++ b/compiler/avr/ravrsri.inc @@ -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 diff --git a/compiler/avr/ravrsta.inc b/compiler/avr/ravrsta.inc new file mode 100644 index 0000000000..4231ab6f18 --- /dev/null +++ b/compiler/avr/ravrsta.inc @@ -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 diff --git a/compiler/avr/ravrstd.inc b/compiler/avr/ravrstd.inc new file mode 100644 index 0000000000..a29e9cf2a9 --- /dev/null +++ b/compiler/avr/ravrstd.inc @@ -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' diff --git a/compiler/avr/ravrsup.inc b/compiler/avr/ravrsup.inc new file mode 100644 index 0000000000..da781e0718 --- /dev/null +++ b/compiler/avr/ravrsup.inc @@ -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; diff --git a/compiler/avr/rgcpu.pas b/compiler/avr/rgcpu.pas new file mode 100644 index 0000000000..73582d6f6e --- /dev/null +++ b/compiler/avr/rgcpu.pas @@ -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. diff --git a/compiler/fpcdefs.inc b/compiler/fpcdefs.inc index bb799c3878..11c07109be 100644 --- a/compiler/fpcdefs.inc +++ b/compiler/fpcdefs.inc @@ -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} diff --git a/compiler/pstatmnt.pas b/compiler/pstatmnt.pas index b37403cb9d..6434d1fdb1 100644 --- a/compiler/pstatmnt.pas +++ b/compiler/pstatmnt.pas @@ -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 diff --git a/compiler/psystem.pas b/compiler/psystem.pas index 7ea9881dac..8dddc16a5c 100644 --- a/compiler/psystem.pas +++ b/compiler/psystem.pas @@ -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; diff --git a/compiler/symdef.pas b/compiler/symdef.pas index 94a358ff03..896bf946a4 100644 --- a/compiler/symdef.pas +++ b/compiler/symdef.pas @@ -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; diff --git a/compiler/utils/mkavrreg.pp b/compiler/utils/mkavrreg.pp new file mode 100644 index 0000000000..3bec3cef4f --- /dev/null +++ b/compiler/utils/mkavrreg.pp @@ -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.