Merged revisions 5891-10167,10169-10180 via svnmerge from

http://svn.freepascal.org/svn/fpc/branches/avr

........
  r5891 | florian | 2007-01-11 17:30:12 +0100 (Do, 11 Jan 2007) | 2 lines
  
  + some initial work
........
  r10170 | florian | 2008-02-03 11:02:04 +0100 (So, 03 Feb 2008) | 2 lines
  
  * continued to work on avr port
........
  r10180 | florian | 2008-02-03 15:29:30 +0100 (So, 03 Feb 2008) | 2 lines
  
  + a lot of skeleton code for avr added
........

git-svn-id: trunk@10186 -
This commit is contained in:
florian 2008-02-03 17:21:52 +00:00
parent a259154511
commit bc73f9021c
28 changed files with 3255 additions and 2 deletions

23
.gitattributes vendored
View File

@ -75,6 +75,28 @@ compiler/arm/rarmstd.inc svneol=native#text/plain
compiler/arm/rarmsup.inc svneol=native#text/plain
compiler/arm/rgcpu.pas svneol=native#text/plain
compiler/assemble.pas svneol=native#text/plain
compiler/avr/aasmcpu.pas svneol=native#text/plain
compiler/avr/aoptcpu.pas svneol=native#text/plain
compiler/avr/aoptcpub.pas svneol=native#text/plain
compiler/avr/aoptcpud.pas svneol=native#text/plain
compiler/avr/avrreg.dat svneol=native#text/plain
compiler/avr/cgcpu.pas svneol=native#text/plain
compiler/avr/cpubase.pas svneol=native#text/plain
compiler/avr/cpuinfo.pas svneol=native#text/plain
compiler/avr/cpunode.pas svneol=native#text/plain
compiler/avr/cpupara.pas svneol=native#text/plain
compiler/avr/cpupi.pas svneol=native#text/plain
compiler/avr/cputarg.pas svneol=native#text/plain
compiler/avr/ravrcon.inc svneol=native#text/plain
compiler/avr/ravrdwa.inc svneol=native#text/plain
compiler/avr/ravrnor.inc svneol=native#text/plain
compiler/avr/ravrnum.inc svneol=native#text/plain
compiler/avr/ravrrni.inc svneol=native#text/plain
compiler/avr/ravrsri.inc svneol=native#text/plain
compiler/avr/ravrsta.inc svneol=native#text/plain
compiler/avr/ravrstd.inc svneol=native#text/plain
compiler/avr/ravrsup.inc svneol=native#text/plain
compiler/avr/rgcpu.pas svneol=native#text/plain
compiler/browcol.pas svneol=native#text/plain
compiler/bsdcompile -text
compiler/catch.pas svneol=native#text/plain
@ -521,6 +543,7 @@ compiler/utils/gppc386.pp svneol=native#text/plain
compiler/utils/mk68kreg.pp svneol=native#text/plain
compiler/utils/mkarmins.pp svneol=native#text/plain
compiler/utils/mkarmreg.pp svneol=native#text/plain
compiler/utils/mkavrreg.pp svneol=native#text/plain
compiler/utils/mkmpsreg.pp svneol=native#text/plain
compiler/utils/mkppcreg.pp svneol=native#text/plain
compiler/utils/mkspreg.pp svneol=native#text/plain

257
compiler/avr/aasmcpu.pas Normal file
View File

@ -0,0 +1,257 @@
{
Copyright (c) 1999-2008 by Mazen Neifer and Florian Klaempfl
Contains the assembler object for the AVR
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit aasmcpu;
{$i fpcdefs.inc}
interface
uses
cclasses,
globtype,globals,verbose,
aasmbase,aasmtai,aasmdata,aasmsym,
cgbase,cgutils,cpubase,cpuinfo;
const
{ "mov reg,reg" source operand number }
O_MOV_SOURCE = 1;
{ "mov reg,reg" source operand number }
O_MOV_DEST = 0;
type
taicpu = class(tai_cpu_abstract_sym)
constructor op_none(op : tasmop);
constructor op_reg(op : tasmop;_op1 : tregister);
constructor op_const(op : tasmop;_op1 : LongInt);
constructor op_ref(op : tasmop;const _op1 : treference);
constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
constructor op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt);
constructor op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister);
constructor op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
{ this is for Jmp instructions }
constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
constructor op_sym(op : tasmop;_op1 : tasmsymbol);
constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
procedure loadbool(opidx:longint;_b:boolean);
{ register allocation }
function is_same_reg_move(regtype: Tregistertype):boolean; override;
{ register spilling code }
function spilling_get_operation_type(opnr: longint): topertype;override;
end;
tai_align = class(tai_align_abstract)
{ nothing to add }
end;
procedure InitAsm;
procedure DoneAsm;
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
implementation
{*****************************************************************************
taicpu Constructors
*****************************************************************************}
procedure taicpu.loadbool(opidx:longint;_b:boolean);
begin
if opidx>=ops then
ops:=opidx+1;
with oper[opidx]^ do
begin
if typ=top_ref then
dispose(ref);
b:=_b;
typ:=top_bool;
end;
end;
constructor taicpu.op_none(op : tasmop);
begin
inherited create(op);
end;
constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
begin
inherited create(op);
ops:=1;
loadreg(0,_op1);
end;
constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
begin
inherited create(op);
ops:=1;
loadref(0,_op1);
end;
constructor taicpu.op_const(op : tasmop;_op1 : LongInt);
begin
inherited create(op);
ops:=1;
loadconst(0,_op1);
end;
constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
begin
inherited create(op);
ops:=2;
loadreg(0,_op1);
loadreg(1,_op2);
end;
constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: LongInt);
begin
inherited create(op);
ops:=2;
loadreg(0,_op1);
loadconst(1,_op2);
end;
constructor taicpu.op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister);
begin
inherited create(op);
ops:=2;
loadconst(0,_op1);
loadreg(1,_op2);
end;
constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
begin
inherited create(op);
ops:=2;
loadreg(0,_op1);
loadref(1,_op2);
end;
constructor taicpu.op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
begin
inherited create(op);
ops:=2;
loadref(0,_op1);
loadreg(1,_op2);
end;
constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
begin
inherited create(op);
is_jmp:=op in jmp_instructions;
condition:=cond;
ops:=1;
loadsymbol(0,_op1,0);
end;
constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
begin
inherited create(op);
is_jmp:=op in jmp_instructions;
ops:=1;
loadsymbol(0,_op1,0);
end;
constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
begin
inherited create(op);
ops:=1;
loadsymbol(0,_op1,_op1ofs);
end;
function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
begin
result:=(
((opcode in [A_MOV,A_MOVW]) and (regtype = R_INTREGISTER))
) and
(ops=2) and
(oper[0]^.typ=top_reg) and
(oper[1]^.typ=top_reg) and
(oper[0]^.reg=oper[1]^.reg);
end;
function taicpu.spilling_get_operation_type(opnr: longint): topertype;
begin
result := operand_read;
case opcode of
A_CP,A_CPC,A_CPI :
;
else
begin
if opnr=ops-1 then
result := operand_write;
end;
end;
end;
function spilling_create_load(const ref:treference;r:tregister):Taicpu;
begin
case getregtype(r) of
R_INTREGISTER :
result:=taicpu.op_ref_reg(A_LD,ref,r);
else
internalerror(200401041);
end;
end;
function spilling_create_store(r:tregister; const ref:treference):Taicpu;
begin
case getregtype(r) of
R_INTREGISTER :
result:=taicpu.op_reg_ref(A_ST,r,ref);
else
internalerror(200401041);
end;
end;
procedure InitAsm;
begin
end;
procedure DoneAsm;
begin
end;
begin
cai_cpu:=taicpu;
cai_align:=tai_align;
end.

64
compiler/avr/aoptcpu.pas Normal file
View File

@ -0,0 +1,64 @@
{
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
Development Team
This unit implements the ARM optimizer object
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
Unit aoptcpu;
{$i fpcdefs.inc}
Interface
uses cpubase, aasmtai, aopt, aoptcpub;
Type
TCpuAsmOptimizer = class(TAsmOptimizer)
{ uses the same constructor as TAopObj }
function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
procedure PeepHoleOptPass2;override;
End;
Implementation
uses
aasmbase,aasmcpu;
function CanBeCond(p : tai) : boolean;
begin
result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
end;
function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
var
next1: tai;
begin
result := false;
end;
procedure TCpuAsmOptimizer.PeepHoleOptPass2;
begin
end;
begin
casmoptimizer:=TCpuAsmOptimizer;
End.

120
compiler/avr/aoptcpub.pas Normal file
View File

@ -0,0 +1,120 @@
{
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
Development Team
This unit contains several types and constants necessary for the
optimizer to work on the ARM architecture
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
{$i fpcdefs.inc}
{ enable the following define if memory references can have both a base and }
{ index register in 1 operand }
{$define RefsHaveIndexReg}
{ enable the following define if memory references can have a scaled index }
{ define RefsHaveScale}
{ enable the following define if memory references can have a segment }
{ override }
{ define RefsHaveSegment}
Interface
Uses
cpubase,aasmcpu,AOptBase;
Type
{ type of a normal instruction }
TInstr = Taicpu;
PInstr = ^TInstr;
{ ************************************************************************* }
{ **************************** TCondRegs ********************************** }
{ ************************************************************************* }
{ Info about the conditional registers }
TCondRegs = Object
Constructor Init;
Destructor Done;
End;
{ ************************************************************************* }
{ **************************** TAoptBaseCpu ******************************* }
{ ************************************************************************* }
TAoptBaseCpu = class(TAoptBase)
End;
{ ************************************************************************* }
{ ******************************* Constants ******************************* }
{ ************************************************************************* }
Const
{ the maximum number of things (registers, memory, ...) a single instruction }
{ changes }
MaxCh = 2;
{ the maximum number of operands an instruction has }
MaxOps = 2;
{Oper index of operand that contains the source (reference) with a load }
{instruction }
LoadSrc = 1;
{Oper index of operand that contains the destination (register) with a load }
{instruction }
LoadDst = 0;
{Oper index of operand that contains the source (register) with a store }
{instruction }
StoreSrc = 1;
{Oper index of operand that contains the destination (reference) with a load }
{instruction }
StoreDst = 0;
aopt_uncondjmp = A_JMP;
aopt_condjmp = A_BRxx;
Implementation
{ ************************************************************************* }
{ **************************** TCondRegs ********************************** }
{ ************************************************************************* }
Constructor TCondRegs.init;
Begin
End;
Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
Begin
End;
End.

40
compiler/avr/aoptcpud.pas Normal file
View File

@ -0,0 +1,40 @@
{
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
Development Team
This unit contains the processor specific implementation of the
assembler optimizer data flow analyzer.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
Unit aoptcpud;
{$i fpcdefs.inc}
Interface
uses
AOptDA;
Type
TAOptDFACpu = class(TAOptDFA)
End;
Implementation
End.

41
compiler/avr/avrreg.dat Normal file
View File

@ -0,0 +1,41 @@
;
; AVR registers
;
; layout
; <name>,<type>,<value>,<stdname>,<stab idx>,<dwarf idx>
;
NO,$00,$00,INVALID,-1,-1
R0,$01,$00,r0,0,0
R1,$01,$01,r1,1,1
R2,$01,$02,r2,2,2
R3,$01,$03,r3,3,3
R4,$01,$04,r4,4,4
R5,$01,$05,r5,5,5
R6,$01,$06,r6,6,6
R7,$01,$07,r7,7,7
R8,$01,$08,r8,8,8
R9,$01,$09,r9,9,9
R10,$01,$0a,r10,10,10
R11,$01,$0b,r11,11,11
R12,$01,$0c,r12,12,12
R13,$01,$0d,r13,13,13
R14,$01,$0e,r14,14,14
R15,$01,$0f,r15,15,15
R16,$01,$10,r16,16,16
R17,$01,$11,r17,17,17
R18,$01,$12,r18,18,18
R19,$01,$13,r19,19,19
R20,$01,$14,r20,20,20
R21,$01,$15,r21,21,21
R22,$01,$16,r22,22,22
R23,$01,$17,r23,23,23
R24,$01,$18,r24,24,24
R25,$01,$19,r25,25,25
R26,$01,$1a,r26,26,26
R27,$01,$1b,r27,27,27
R28,$01,$1c,r28,28,28
R29,$01,$1d,r29,29,29
R30,$01,$1e,r30,30,30
R31,$01,$1f,r31,31,31

798
compiler/avr/cgcpu.pas Normal file
View File

@ -0,0 +1,798 @@
{
Copyright (c) 2008 by Florian Klaempfl
Member of the Free Pascal development team
This unit implements the code generator for the AVR
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit cgcpu;
{$i fpcdefs.inc}
interface
uses
globtype,symtype,symdef,
cgbase,cgutils,cgobj,
aasmbase,aasmcpu,aasmtai,aasmdata,
parabase,
cpubase,cpuinfo,node,cg64f32,rgcpu;
type
tcgavr = class(tcg)
{ true, if the next arithmetic operation should modify the flags }
cgsetflags : boolean;
procedure init_register_allocators;override;
procedure done_register_allocators;override;
procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
procedure a_call_name(list : TAsmList;const s : string);override;
procedure a_call_reg(list : TAsmList;reg: tregister);override;
procedure a_call_ref(list : TAsmList;ref: treference);override;
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
size: tcgsize; a: aint; src, dst: tregister); override;
procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
size: tcgsize; src1, src2, dst: tregister); override;
procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
{ move instructions }
procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
{ comparison operations }
procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
l : tasmlabel);override;
procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
procedure a_jmp_name(list : TAsmList;const s : string); override;
procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
// procedure g_save_registers(list : TAsmList);override;
// procedure g_restore_registers(list : TAsmList);override;
procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
procedure fixref(list : TAsmList;var ref : treference);
function handle_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference):treference;
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
end;
tcg64favr = class(tcg64f32)
procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
end;
const
OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
implementation
uses
globals,verbose,systems,cutils,
fmodule,
symconst,symsym,
tgobj,
procinfo,cpupi,
paramgr;
procedure tcgavr.init_register_allocators;
begin
inherited init_register_allocators;
{ currently, we save R14 always, so we can use it }
rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
[RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
end;
procedure tcgavr.done_register_allocators;
begin
rg[R_INTREGISTER].free;
inherited done_register_allocators;
end;
procedure tcgavr.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
var
ref: treference;
begin
paraloc.check_simple_location;
case paraloc.location^.loc of
LOC_REGISTER,LOC_CREGISTER:
a_load_const_reg(list,size,a,paraloc.location^.register);
LOC_REFERENCE:
begin
reference_reset(ref);
ref.base:=paraloc.location^.reference.index;
ref.offset:=paraloc.location^.reference.offset;
a_load_const_ref(list,size,a,ref);
end;
else
internalerror(2002081101);
end;
end;
procedure tcgavr.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
var
tmpref, ref: treference;
location: pcgparalocation;
sizeleft: aint;
begin
location := paraloc.location;
tmpref := r;
sizeleft := paraloc.intsize;
while assigned(location) do
begin
case location^.loc of
LOC_REGISTER,LOC_CREGISTER:
a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
LOC_REFERENCE:
begin
reference_reset_base(ref,location^.reference.index,location^.reference.offset);
{ doubles in softemu mode have a strange order of registers and references }
if location^.size=OS_32 then
g_concatcopy(list,tmpref,ref,4)
else
begin
g_concatcopy(list,tmpref,ref,sizeleft);
if assigned(location^.next) then
internalerror(2005010710);
end;
end;
LOC_VOID:
begin
// nothing to do
end;
else
internalerror(2002081103);
end;
inc(tmpref.offset,tcgsize2size[location^.size]);
dec(sizeleft,tcgsize2size[location^.size]);
location := location^.next;
end;
end;
procedure tcgavr.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
var
ref: treference;
tmpreg: tregister;
begin
paraloc.check_simple_location;
case paraloc.location^.loc of
LOC_REGISTER,LOC_CREGISTER:
a_loadaddr_ref_reg(list,r,paraloc.location^.register);
LOC_REFERENCE:
begin
reference_reset(ref);
ref.base := paraloc.location^.reference.index;
ref.offset := paraloc.location^.reference.offset;
tmpreg := getintregister(list,OS_ADDR);
a_loadaddr_ref_reg(list,r,tmpreg);
a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
end;
else
internalerror(2002080701);
end;
end;
procedure tcgavr.a_call_name(list : TAsmList;const s : string);
begin
list.concat(taicpu.op_sym(A_RCALL,current_asmdata.RefAsmSymbol(s)));
{
the compiler does not properly set this flag anymore in pass 1, and
for now we only need it after pass 2 (I hope) (JM)
if not(pi_do_call in current_procinfo.flags) then
internalerror(2003060703);
}
include(current_procinfo.flags,pi_do_call);
end;
procedure tcgavr.a_call_reg(list : TAsmList;reg: tregister);
begin
a_reg_alloc(list,NR_ZLO);
a_reg_alloc(list,NR_ZHI);
list.concat(taicpu.op_reg_reg(A_MOV,NR_ZLO,reg));
list.concat(taicpu.op_reg_reg(A_MOV,NR_ZHI,GetHigh(reg)));
list.concat(taicpu.op_none(A_ICALL));
a_reg_dealloc(list,NR_ZLO);
a_reg_dealloc(list,NR_ZHI);
include(current_procinfo.flags,pi_do_call);
end;
procedure tcgavr.a_call_ref(list : TAsmList;ref: treference);
begin
a_reg_alloc(list,NR_ZLO);
a_reg_alloc(list,NR_ZHI);
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_ZLO);
list.concat(taicpu.op_none(A_ICALL));
a_reg_dealloc(list,NR_ZLO);
a_reg_dealloc(list,NR_ZHI);
include(current_procinfo.flags,pi_do_call);
end;
procedure tcgavr.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
begin
a_op_const_reg_reg(list,op,size,a,reg,reg);
end;
procedure tcgavr.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
begin
case op of
OP_NEG:
// !!!! list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
;
OP_NOT:
begin
// !!!! list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
case size of
OS_8 :
;
// !!!! a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
OS_16 :
// !!!! a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
;
end;
end
else
a_op_reg_reg_reg(list,op,size,src,dst,dst);
end;
end;
procedure tcgavr.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
size: tcgsize; a: aint; src, dst: tregister);
var
ovloc : tlocation;
begin
a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
end;
procedure tcgavr.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
size: tcgsize; src1, src2, dst: tregister);
var
ovloc : tlocation;
begin
a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
end;
procedure tcgavr.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
begin
end;
procedure tcgavr.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
var
so : tshifterop;
tmpreg,overflowreg : tregister;
asmop : tasmop;
begin
ovloc.loc:=LOC_VOID;
case op of
OP_NEG,OP_NOT,
OP_DIV,OP_IDIV:
internalerror(200308281);
OP_SHL:
begin
end;
OP_SHR:
begin
end;
OP_SAR:
begin
end;
OP_IMUL,
OP_MUL:
begin
end;
end;
end;
procedure tcgavr.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
begin
if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
internalerror(2002090902);
end;
function tcgavr.handle_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference):treference;
begin
end;
procedure tcgavr.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
begin
end;
procedure tcgavr.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
begin
end;
function tcgavr.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
begin
end;
function tcgavr.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
begin
end;
procedure tcgavr.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
begin
end;
{ comparison operations }
procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
l : tasmlabel);
begin
end;
procedure tcgavr.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
begin
end;
procedure tcgavr.a_jmp_name(list : TAsmList;const s : string);
begin
end;
procedure tcgavr.a_jmp_always(list : TAsmList;l: tasmlabel);
begin
end;
procedure tcgavr.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
begin
end;
procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
begin
end;
procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
{
var
ref : treference;
shift : byte;
firstfloatreg,lastfloatreg,
r : byte;
regs : tcpuregisterset;
}
begin
{
LocalSize:=align(LocalSize,4);
if not(nostackframe) then
begin
firstfloatreg:=RS_NO;
{ save floating point registers? }
for r:=RS_F0 to RS_F7 do
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
begin
if firstfloatreg=RS_NO then
firstfloatreg:=r;
lastfloatreg:=r;
end;
a_reg_alloc(list,NR_STACK_POINTER_REG);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
begin
a_reg_alloc(list,NR_FRAME_POINTER_REG);
a_reg_alloc(list,NR_R12);
list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
end;
{ save int registers }
reference_reset(ref);
ref.index:=NR_STACK_POINTER_REG;
ref.addressmode:=AM_PREINDEXED;
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
else
if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
include(regs,RS_R14);
if regs<>[] then
list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
{ allocate necessary stack size
not necessary according to Yury Sidorov
{ don't use a_op_const_reg_reg here because we don't allow register allocations
in the entry/exit code }
if (target_info.system in [system_arm_wince]) and
(localsize>=winstackpagesize) then
begin
if localsize div winstackpagesize<=5 then
begin
if is_shifter_const(localsize,shift) then
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
else
begin
a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
end;
for i:=1 to localsize div winstackpagesize do
begin
if localsize-i*winstackpagesize<4096 then
reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
else
begin
a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
reference_reset_base(href,NR_STACK_POINTER_REG,0);
href.index:=NR_R12;
end;
{ the data stored doesn't matter }
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
end;
a_reg_dealloc(list,NR_R12);
reference_reset_base(href,NR_STACK_POINTER_REG,0);
{ the data stored doesn't matter }
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
end
else
begin
current_asmdata.getjumplabel(again);
list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
a_label(list,again);
{ always shifterop }
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
reference_reset_base(href,NR_STACK_POINTER_REG,0);
{ the data stored doesn't matter }
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
a_jmp_cond(list,OC_NE,again);
if is_shifter_const(localsize mod winstackpagesize,shift) then
list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
else
begin
a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
end;
a_reg_dealloc(list,NR_R12);
reference_reset_base(href,NR_STACK_POINTER_REG,0);
{ the data stored doesn't matter }
list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
end
end
else
}
if LocalSize<>0 then
if not(is_shifter_const(localsize,shift)) then
begin
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
a_reg_alloc(list,NR_R12);
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
a_reg_dealloc(list,NR_R12);
end
else
begin
a_reg_dealloc(list,NR_R12);
list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
end;
if firstfloatreg<>RS_NO then
begin
reference_reset(ref);
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
begin
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
ref.base:=NR_R12;
end
else
begin
ref.base:=current_procinfo.framepointer;
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
end;
list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
lastfloatreg-firstfloatreg+1,ref));
end;
end;
}
end;
procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
{
var
ref : treference;
firstfloatreg,lastfloatreg,
r : byte;
shift : byte;
regs : tcpuregisterset;
LocalSize : longint;
}
begin
{
if not(nostackframe) then
begin
{ restore floating point register }
firstfloatreg:=RS_NO;
{ save floating point registers? }
for r:=RS_F0 to RS_F7 do
if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
begin
if firstfloatreg=RS_NO then
firstfloatreg:=r;
lastfloatreg:=r;
end;
if firstfloatreg<>RS_NO then
begin
reference_reset(ref);
if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
begin
a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
ref.base:=NR_R12;
end
else
begin
ref.base:=current_procinfo.framepointer;
ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
end;
list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
lastfloatreg-firstfloatreg+1,ref));
end;
if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
begin
LocalSize:=current_procinfo.calc_stackframe_size;
if LocalSize<>0 then
if not(is_shifter_const(LocalSize,shift)) then
begin
a_reg_alloc(list,NR_R12);
a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
a_reg_dealloc(list,NR_R12);
end
else
begin
list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
end;
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
begin
exclude(regs,RS_R14);
include(regs,RS_R15);
end;
if regs=[] then
list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
else
begin
reference_reset(ref);
ref.index:=NR_STACK_POINTER_REG;
ref.addressmode:=AM_PREINDEXED;
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
end;
end
else
begin
{ restore int registers and return }
reference_reset(ref);
ref.index:=NR_FRAME_POINTER_REG;
list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
end;
end
else
list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
}
end;
procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
begin
end;
procedure tcgavr.fixref(list : TAsmList;var ref : treference);
begin
end;
procedure tcgavr.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
var
paraloc1,paraloc2,paraloc3 : TCGPara;
begin
paraloc1.init;
paraloc2.init;
paraloc3.init;
paramanager.getintparaloc(pocall_default,1,paraloc1);
paramanager.getintparaloc(pocall_default,2,paraloc2);
paramanager.getintparaloc(pocall_default,3,paraloc3);
paramanager.allocparaloc(list,paraloc3);
a_param_const(list,OS_INT,len,paraloc3);
paramanager.allocparaloc(list,paraloc2);
a_paramaddr_ref(list,dest,paraloc2);
paramanager.allocparaloc(list,paraloc2);
a_paramaddr_ref(list,source,paraloc1);
paramanager.freeparaloc(list,paraloc3);
paramanager.freeparaloc(list,paraloc2);
paramanager.freeparaloc(list,paraloc1);
alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
a_call_name(list,'FPC_MOVE');
dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
paraloc3.done;
paraloc2.done;
paraloc1.done;
end;
procedure tcgavr.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
begin
end;
procedure tcgavr.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
begin
g_concatcopy_internal(list,source,dest,len,false);
end;
procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
begin
if (source.alignment in [1..3]) or
(dest.alignment in [1..3]) then
g_concatcopy_internal(list,source,dest,len,false)
else
g_concatcopy_internal(list,source,dest,len,true);
end;
procedure tcgavr.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
var
ovloc : tlocation;
begin
ovloc.loc:=LOC_VOID;
g_overflowCheck_loc(list,l,def,ovloc);
end;
procedure tcgavr.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
begin
end;
{
procedure tcgavr.g_save_registers(list : TAsmList);
begin
{ this work is done in g_proc_entry }
end;
procedure tcgavr.g_restore_registers(list : TAsmList);
begin
{ this work is done in g_proc_exit }
end;
}
procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
var
ai : taicpu;
begin
ai:=Taicpu.Op_sym(A_BRxx,l);
ai.SetCondition(OpCmp2AsmCond[cond]);
ai.is_jmp:=true;
list.concat(ai);
end;
procedure tcgavr.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
begin
end;
procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
begin
end;
procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
begin
a_op64_const_reg_reg(list,op,size,value,reg,reg);
end;
procedure tcg64favr.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
var
ovloc : tlocation;
begin
a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
end;
procedure tcg64favr.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
var
ovloc : tlocation;
begin
a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
end;
procedure tcg64favr.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
begin
end;
procedure tcg64favr.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
begin
end;
begin
cg:=tcgavr.create;
cg64:=tcg64favr.create;
end.

484
compiler/avr/cpubase.pas Normal file
View File

@ -0,0 +1,484 @@
{
Copyright (c) 2006 by Florian Klaempfl
Contains the base types for the AVR
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{# Base unit for processor information. This unit contains
enumerations of registers, opcodes, sizes, and other
such things which are processor specific.
}
unit cpubase;
{$i fpcdefs.inc}
interface
uses
cutils,cclasses,
globtype,globals,
cpuinfo,
aasmbase,
cgbase
;
{*****************************************************************************
Assembler Opcodes
*****************************************************************************}
type
TAsmOp=(A_None,
A_ADD,A_ADC,A_ADIW,A_SUB,A_SUBI,A_SBC,A_SBCI,A_SBIW,A_AND,A_ANDI,
A_OR,A_ORI,A_EOR,A_COM,A_NEG,A_SBR,A_CBR,A_INC,A_DEC,A_TST,A_CLR,
A_SER,A_MUL,A_MULS,A_FMUL,A_FMULS,A_FMULSU,A_RJMP,A_IJMP,
A_EIJMP,A_JMP,A_RCALL,A_ICALL,R_EICALL,A_CALL,A_RET,A_RETI,A_CPSE,
A_CP,A_CPC,A_CPI,A_SBxx,A_BRxx,A_MOV,A_MOVW,A_LDI,A_LDS,A_LD,A_LDD,
A_STS,A_ST,A_STD,A_LPM,A_ELPM,A_SPM,A_IN,A_OUT,A_PUSH,A_POP,
A_LSL,A_LSR,A_ROL,A_ROR,A_ASR,A_SWAP,A_BSET,A_BCLR,A_SBI,A_CBI,
A_BST,A_BLD,A_Sxx,A_Cxx,A_BRAK,A_NOP,A_SLEEP,A_WDR);
{ This should define the array of instructions as string }
op2strtable=array[tasmop] of string[11];
const
{ First value of opcode enumeration }
firstop = low(tasmop);
{ Last value of opcode enumeration }
lastop = high(tasmop);
jmp_instructions = [A_BRxx,A_SBxx,A_JMP,A_RCALL,A_ICALL,A_EIJMP,A_RJMP,A_CALL,A_RET,A_RETI,A_CPSE,A_IJMP];
{*****************************************************************************
Registers
*****************************************************************************}
type
{ Number of registers used for indexing in tables }
tregisterindex=0..{$i ravrnor.inc}-1;
const
{ Available Superregisters }
{$i ravrsup.inc}
{ No Subregisters }
R_SUBWHOLE = R_SUBNONE;
{ Available Registers }
{$i ravrcon.inc}
NR_XLO = NR_R26;
NR_XHI = NR_R27;
NR_YLO = NR_R28;
NR_YHI = NR_R29;
NR_ZLO = NR_R30;
NR_ZHI = NR_R31;
{ Integer Super registers first and last }
first_int_supreg = RS_R0;
first_int_imreg = $10;
{ Float Super register first and last }
first_fpu_supreg = RS_INVALID;
first_fpu_imreg = RS_INVALID;
{ MM Super register first and last }
first_mm_supreg = RS_INVALID;
first_mm_imreg = RS_INVALID;
{$warning TODO Calculate bsstart}
regnumber_count_bsstart = 64;
regnumber_table : array[tregisterindex] of tregister = (
{$i ravrnum.inc}
);
regstabs_table : array[tregisterindex] of shortint = (
{$i ravrsta.inc}
);
regdwarf_table : array[tregisterindex] of shortint = (
{$i ravrdwa.inc}
);
{ registers which may be destroyed by calls }
VOLATILE_INTREGISTERS = [RS_R18..RS_R27,RS_R30..RS_R31];
VOLATILE_FPUREGISTERS = [];
type
totherregisterset = set of tregisterindex;
{*****************************************************************************
Conditions
*****************************************************************************}
type
TAsmCond=(C_None,
C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
C_GE,C_LT,C_GT,C_LE,C_AL,C_NV
);
const
cond2str : array[TAsmCond] of string[2]=('',
'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
'ge','lt','gt','le','al','nv'
);
uppercond2str : array[TAsmCond] of string[2]=('',
'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
'GE','LT','GT','LE','AL','NV'
);
{*****************************************************************************
Flags
*****************************************************************************}
type
TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
F_GE,F_LT,F_GT,F_LE);
{*****************************************************************************
Operands
*****************************************************************************}
taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
tupdatereg = (UR_None,UR_Update);
pshifterop = ^tshifterop;
tshifterop = record
shiftmode : tshiftmode;
rs : tregister;
shiftimm : byte;
end;
{*****************************************************************************
Constants
*****************************************************************************}
const
max_operands = 4;
{# Constant defining possibly all registers which might require saving }
ALL_OTHERREGISTERS = [];
general_superregisters = [RS_R0..RS_R31];
{# Table of registers which can be allocated by the code generator
internally, when generating the code.
}
{ legend: }
{ xxxregs = set of all possibly used registers of that type in the code }
{ generator }
{ usableregsxxx = set of all 32bit components of registers that can be }
{ possible allocated to a regvar or using getregisterxxx (this }
{ excludes registers which can be only used for parameter }
{ passing on ABI's that define this) }
{ c_countusableregsxxx = amount of registers in the usableregsxxx set }
maxintregs = 15;
{ to determine how many registers to use for regvars }
maxintscratchregs = 3;
usableregsint = [RS_R4..RS_R10];
c_countusableregsint = 7;
maxfpuregs = 0;
fpuregs = [];
usableregsfpu = [];
c_countusableregsfpu = 0;
mmregs = [];
usableregsmm = [];
c_countusableregsmm = 0;
maxaddrregs = 0;
addrregs = [];
usableregsaddr = [];
c_countusableregsaddr = 0;
{*****************************************************************************
Operand Sizes
*****************************************************************************}
type
topsize = (S_NO,
S_B,S_W,S_L,S_BW,S_BL,S_WL,
S_IS,S_IL,S_IQ,
S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
);
{*****************************************************************************
Constants
*****************************************************************************}
const
firstsaveintreg = RS_R4;
lastsaveintreg = RS_R10;
firstsavefpureg = RS_INVALID;
lastsavefpureg = RS_INVALID;
firstsavemmreg = RS_INVALID;
lastsavemmreg = RS_INVALID;
maxvarregs = 7;
varregs : Array [1..maxvarregs] of tsuperregister =
(RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
maxfpuvarregs = 1;
fpuvarregs : Array [1..maxfpuvarregs] of tsuperregister =
(RS_INVALID);
{*****************************************************************************
Default generic sizes
*****************************************************************************}
{ Defines the default address size for a processor, }
OS_ADDR = OS_16;
{ the natural int size for a processor, }
OS_INT = OS_16;
OS_SINT = OS_S16;
{ the maximum float size for a processor, }
OS_FLOAT = OS_F64;
{ the size of a vector register for a processor }
OS_VECTOR = OS_M32;
{*****************************************************************************
Generic Register names
*****************************************************************************}
{ Stack pointer register }
NR_STACK_POINTER_REG = NR_R13;
RS_STACK_POINTER_REG = RS_R13;
{ Frame pointer register }
RS_FRAME_POINTER_REG = RS_R11;
NR_FRAME_POINTER_REG = NR_R11;
{ Register for addressing absolute data in a position independant way,
such as in PIC code. The exact meaning is ABI specific. For
further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
}
NR_PIC_OFFSET_REG = NR_R9;
{ Results are returned in this register (32-bit values) }
NR_FUNCTION_RETURN_REG = NR_R0;
RS_FUNCTION_RETURN_REG = RS_R0;
{ Low part of 64bit return value }
NR_FUNCTION_RETURN64_LOW_REG = NR_R0;
RS_FUNCTION_RETURN64_LOW_REG = RS_R0;
{ High part of 64bit return value }
NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
{ The value returned from a function is available in this register }
NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
{ The lowh part of 64bit value returned from a function }
NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
{ The high part of 64bit value returned from a function }
NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
NR_FPU_RESULT_REG = NR_NO;
NR_MM_RESULT_REG = NR_NO;
NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
{ Offset where the parent framepointer is pushed }
PARENT_FRAMEPOINTER_OFFSET = 0;
{*****************************************************************************
GCC /ABI linking information
*****************************************************************************}
const
{ Registers which must be saved when calling a routine declared as
cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
saved should be the ones as defined in the target ABI and / or GCC.
This value can be deduced from the CALLED_USED_REGISTERS array in the
GCC source.
}
saved_standard_registers : array[0..6] of tsuperregister =
(RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
{ Required parameter alignment when calling a routine declared as
stdcall and cdecl. The alignment value should be the one defined
by GCC or the target ABI.
The value of this constant is equal to the constant
PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
}
std_param_align = 4;
{*****************************************************************************
Helpers
*****************************************************************************}
{ Returns the tcgsize corresponding with the size of reg.}
function reg_cgsize(const reg: tregister) : tcgsize;
function cgsize2subreg(s:Tcgsize):Tsubregister;
procedure inverse_flags(var f: TResFlags);
function flags_to_cond(const f: TResFlags) : TAsmCond;
function findreg_by_number(r:Tregister):tregisterindex;
function std_regnum_search(const s:string):Tregister;
function std_regname(r:Tregister):string;
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
function is_pc(const r : tregister) : boolean;
function dwarf_reg(r:tregister):byte;
function GetHigh(const r : TRegister) : TRegister;
implementation
uses
rgBase,verbose;
const
std_regname_table : array[tregisterindex] of string[7] = (
{$i ravrstd.inc}
);
regnumber_index : array[tregisterindex] of tregisterindex = (
{$i ravrrni.inc}
);
std_regname_index : array[tregisterindex] of tregisterindex = (
{$i ravrsri.inc}
);
function cgsize2subreg(s:Tcgsize):Tsubregister;
begin
cgsize2subreg:=R_SUBWHOLE;
end;
function reg_cgsize(const reg: tregister): tcgsize;
const subreg2cgsize:array[Tsubregister] of Tcgsize =
(OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO);
begin
case getregtype(reg) of
R_INTREGISTER :
reg_cgsize:=OS_32;
R_FPUREGISTER :
reg_cgsize:=OS_F80;
else
internalerror(200303181);
end;
end;
procedure inverse_flags(var f: TResFlags);
const
inv_flags: array[TResFlags] of TResFlags =
(F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
F_LT,F_GE,F_LE,F_GT);
begin
f:=inv_flags[f];
end;
function flags_to_cond(const f: TResFlags) : TAsmCond;
const
flag_2_cond: array[F_EQ..F_LE] of TAsmCond =
(C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
C_GE,C_LT,C_GT,C_LE);
begin
if f>high(flag_2_cond) then
internalerror(200112301);
result:=flag_2_cond[f];
end;
function findreg_by_number(r:Tregister):tregisterindex;
begin
result:=rgBase.findreg_by_number_table(r,regnumber_index);
end;
function std_regnum_search(const s:string):Tregister;
begin
result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
end;
function std_regname(r:Tregister):string;
var
p : tregisterindex;
begin
p:=findreg_by_number_table(r,regnumber_index);
if p<>0 then
result:=std_regname_table[p]
else
result:=generic_regname(r);
end;
procedure shifterop_reset(var so : tshifterop);
begin
FillChar(so,sizeof(so),0);
end;
function is_pc(const r : tregister) : boolean;
begin
is_pc:=(r=NR_R15);
end;
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
const
inverse: array[TAsmCond] of TAsmCond=(C_None,
C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
C_LT,C_GE,C_LE,C_GT,C_None,C_None
);
begin
result := inverse[c];
end;
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
begin
result := c1 = c2;
end;
function rotl(d : dword;b : byte) : dword;
begin
result:=(d shr (32-b)) or (d shl b);
end;
function dwarf_reg(r:tregister):byte;
begin
result:=regdwarf_table[findreg_by_number(r)];
if result=-1 then
internalerror(200603251);
end;
function GetHigh(const r : TRegister) : TRegister;
begin
result:=TRegister(longint(r)+1)
end;
end.

87
compiler/avr/cpuinfo.pas Normal file
View File

@ -0,0 +1,87 @@
{
Copyright (c) 1998-2002 by the Free Pascal development team
Basic Processor information for the ARM
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
Unit CPUInfo;
Interface
uses
globtype;
Type
bestreal = double;
ts32real = single;
ts64real = double;
ts80real = type extended;
ts128real = type extended;
ts64comp = comp;
pbestreal=^bestreal;
{ possible supported processors for this target }
tcputype =
(cpu_none,
cpu_avr
);
tfputype =
(fpu_none,
fpu_soft,
fp_libgcc
);
Const
{# Size of native extended floating point type }
extended_size = 12;
{# Size of a multimedia register }
mmreg_size = 16;
{ target cpu string (used by compiler options) }
target_cpu_string = 'arm';
{ calling conventions supported by the code generator }
supported_calling_conventions : tproccalloptions = [
pocall_internproc,
pocall_safecall,
pocall_stdcall,
{ same as stdcall only different name mangling }
pocall_cdecl,
{ same as stdcall only different name mangling }
pocall_cppdecl,
{ same as stdcall but floating point numbers are handled like equal sized integers }
pocall_softfloat
];
cputypestr : array[tcputype] of string[5] = ('',
'AVR'
);
fputypestr : array[tfputype] of string[6] = ('',
'SOFT',
'LIBGCC'
);
{ Supported optimizations, only used for information }
supported_optimizerswitches = genericlevel1optimizerswitches+
genericlevel2optimizerswitches+
genericlevel3optimizerswitches-
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_regvar,cs_opt_loopunroll,cs_opt_tailrecursion,cs_opt_stackframe];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_regvar,cs_opt_stackframe,cs_opt_tailrecursion];
level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
Implementation
end.

40
compiler/avr/cpunode.pas Normal file
View File

@ -0,0 +1,40 @@
{
Copyright (c) 2000-2008 by Florian Klaempfl
This unit includes the AVR code generator into the compiler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit cpunode;
{$i fpcdefs.inc}
interface
implementation
uses
{ generic nodes }
ncgbas,ncgld,ncgflw,ncgcnv,ncgmem,ncgcon,ncgcal,ncgset,ncginl,ncgopt,ncgmat
{ to be able to only parts of the generic code,
the processor specific nodes must be included
after the generic one (FK)
}
;
end.

490
compiler/avr/cpupara.pas Normal file
View File

@ -0,0 +1,490 @@
{
Copyright (c) 2008 by Florian Klaempfl
AVR specific calling conventions, it follows the GCC AVR calling conventions
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{ ARM specific calling conventions are handled by this unit
}
unit cpupara;
{$i fpcdefs.inc}
interface
uses
globtype,globals,
aasmtai,aasmdata,
cpuinfo,cpubase,cgbase,
symconst,symbase,symtype,symdef,parabase,paramgr;
type
tavrparamanager = class(tparamanager)
function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;override;
procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
private
procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
end;
implementation
uses
verbose,systems,
rgobj,
defutil,symsym,
cgutils;
function tavrparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
begin
result:=VOLATILE_INTREGISTERS;
end;
function tavrparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
begin
result:=VOLATILE_FPUREGISTERS;
end;
procedure tavrparamanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
var
paraloc : pcgparalocation;
begin
if nr<1 then
internalerror(2002070801);
cgpara.reset;
cgpara.size:=OS_INT;
cgpara.intsize:=tcgsize2size[OS_INT];
cgpara.alignment:=std_param_align;
paraloc:=cgpara.add_location;
with paraloc^ do
begin
size:=OS_INT;
{ the four first parameters are passed into registers }
if nr<=4 then
begin
loc:=LOC_REGISTER;
register:=newreg(R_INTREGISTER,RS_R0+nr-1,R_SUBWHOLE);
end
else
begin
{ the other parameters are passed on the stack }
loc:=LOC_REFERENCE;
reference.index:=NR_STACK_POINTER_REG;
reference.offset:=(nr-5)*4;
end;
end;
end;
function getparaloc(calloption : tproccalloption; p : tdef) : tcgloc;
begin
{ Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
if push_addr_param for the def is true
}
case p.typ of
orddef:
getparaloc:=LOC_REGISTER;
floatdef:
if (calloption in [pocall_cdecl,pocall_cppdecl,pocall_softfloat]) or (cs_fp_emulation in current_settings.moduleswitches) then
getparaloc:=LOC_REGISTER
else
getparaloc:=LOC_FPUREGISTER;
enumdef:
getparaloc:=LOC_REGISTER;
pointerdef:
getparaloc:=LOC_REGISTER;
formaldef:
getparaloc:=LOC_REGISTER;
classrefdef:
getparaloc:=LOC_REGISTER;
recorddef:
getparaloc:=LOC_REGISTER;
objectdef:
getparaloc:=LOC_REGISTER;
stringdef:
if is_shortstring(p) or is_longstring(p) then
getparaloc:=LOC_REFERENCE
else
getparaloc:=LOC_REGISTER;
procvardef:
getparaloc:=LOC_REGISTER;
filedef:
getparaloc:=LOC_REGISTER;
arraydef:
getparaloc:=LOC_REFERENCE;
setdef:
if is_smallset(p) then
getparaloc:=LOC_REGISTER
else
getparaloc:=LOC_REFERENCE;
variantdef:
getparaloc:=LOC_REGISTER;
{ avoid problems with errornous definitions }
errordef:
getparaloc:=LOC_REGISTER;
else
internalerror(2002071001);
end;
end;
function tavrparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
begin
result:=false;
if varspez in [vs_var,vs_out] then
begin
result:=true;
exit;
end;
case def.typ of
objectdef:
result:=is_object(def) and ((varspez=vs_const) or (def.size=0));
recorddef:
result:=(varspez=vs_const) or (def.size=0);
variantdef,
formaldef:
result:=true;
arraydef:
result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
is_open_array(def) or
is_array_of_const(def) or
is_array_constructor(def);
setdef :
result:=(tsetdef(def).settype<>smallset);
stringdef :
result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
end;
end;
function tavrparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
begin
case def.typ of
recorddef:
{ this is how gcc 4.0.4 on linux seems to do it, it doesn't look like being
ARM ABI standard compliant
}
result:=not((trecorddef(def).symtable.SymList.count=1) and
not(ret_in_param(tabstractvarsym(trecorddef(def).symtable.SymList[0]).vardef,calloption)));
{
objectdef
arraydef:
result:=not(def.size in [1,2,4]);
}
else
result:=inherited ret_in_param(def,calloption);
end;
end;
procedure tavrparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
begin
curintreg:=RS_R0;
curfloatreg:=RS_INVALID;
curmmreg:=RS_INVALID;
cur_stack_offset:=0;
end;
function tavrparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
var
nextintreg,nextfloatreg,nextmmreg : tsuperregister;
paradef : tdef;
paraloc : pcgparalocation;
stack_offset : aword;
hp : tparavarsym;
loc : tcgloc;
paracgsize : tcgsize;
paralen : longint;
i : integer;
procedure assignintreg;
begin
if nextintreg<=RS_R3 then
begin
paraloc^.loc:=LOC_REGISTER;
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
inc(nextintreg);
end
else
begin
paraloc^.loc:=LOC_REFERENCE;
paraloc^.reference.index:=NR_STACK_POINTER_REG;
paraloc^.reference.offset:=stack_offset;
inc(stack_offset,4);
end;
end;
begin
result:=0;
nextintreg:=curintreg;
nextfloatreg:=curfloatreg;
nextmmreg:=curmmreg;
stack_offset:=cur_stack_offset;
for i:=0 to paras.count-1 do
begin
hp:=tparavarsym(paras[i]);
paradef:=hp.vardef;
hp.paraloc[side].reset;
{ currently only support C-style array of const,
there should be no location assigned to the vararg array itself }
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
is_array_of_const(paradef) then
begin
paraloc:=hp.paraloc[side].add_location;
{ hack: the paraloc must be valid, but is not actually used }
paraloc^.loc:=LOC_REGISTER;
paraloc^.register:=NR_R0;
paraloc^.size:=OS_ADDR;
break;
end;
if (hp.varspez in [vs_var,vs_out]) or
push_addr_param(hp.varspez,paradef,p.proccalloption) or
is_open_array(paradef) or
is_array_of_const(paradef) then
begin
paradef:=voidpointertype;
loc:=LOC_REGISTER;
paracgsize := OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
end
else
begin
if not is_special_array(paradef) then
paralen := paradef.size
else
paralen := tcgsize2size[def_cgsize(paradef)];
loc := getparaloc(p.proccalloption,paradef);
if (paradef.typ in [objectdef,arraydef,recorddef]) and
not is_special_array(paradef) and
(hp.varspez in [vs_value,vs_const]) then
paracgsize := int_cgsize(paralen)
else
begin
paracgsize:=def_cgsize(paradef);
{ for things like formaldef }
if (paracgsize=OS_NO) then
begin
paracgsize:=OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
end;
end
end;
hp.paraloc[side].size:=paracgsize;
hp.paraloc[side].Alignment:=std_param_align;
hp.paraloc[side].intsize:=paralen;
{$ifdef EXTDEBUG}
if paralen=0 then
internalerror(200410311);
{$endif EXTDEBUG}
while paralen>0 do
begin
paraloc:=hp.paraloc[side].add_location;
if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
case paracgsize of
OS_F32:
paraloc^.size:=OS_32;
OS_F64:
paraloc^.size:=OS_32;
else
internalerror(2005082901);
end
else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
paraloc^.size := OS_32
else
paraloc^.size:=paracgsize;
case loc of
LOC_REGISTER:
begin
{ this is not abi compliant
why? (FK) }
if nextintreg<=RS_R3 then
begin
paraloc^.loc:=LOC_REGISTER;
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
inc(nextintreg);
end
else
begin
{ LOC_REFERENCE covers always the overleft }
paraloc^.loc:=LOC_REFERENCE;
paraloc^.size:=int_cgsize(paralen);
if (side=callerside) then
paraloc^.reference.index:=NR_STACK_POINTER_REG;
paraloc^.reference.offset:=stack_offset;
inc(stack_offset,align(paralen,4));
paralen:=0;
end;
end;
LOC_REFERENCE:
begin
paraloc^.size:=OS_ADDR;
if push_addr_param(hp.varspez,paradef,p.proccalloption) or
is_open_array(paradef) or
is_array_of_const(paradef) then
assignintreg
else
begin
paraloc^.loc:=LOC_REFERENCE;
paraloc^.reference.index:=NR_STACK_POINTER_REG;
paraloc^.reference.offset:=stack_offset;
inc(stack_offset,hp.vardef.size);
end;
end;
else
internalerror(2002071002);
end;
if side=calleeside then
begin
if paraloc^.loc=LOC_REFERENCE then
begin
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
inc(paraloc^.reference.offset,4);
end;
end;
dec(paralen,tcgsize2size[paraloc^.size]);
end;
end;
curintreg:=nextintreg;
curfloatreg:=nextfloatreg;
curmmreg:=nextmmreg;
cur_stack_offset:=stack_offset;
result:=cur_stack_offset;
end;
function tavrparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
var
cur_stack_offset: aword;
curintreg, curfloatreg, curmmreg: tsuperregister;
retcgsize : tcgsize;
begin
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
{ Constructors return self instead of a boolean }
if (p.proctypeoption=potype_constructor) then
retcgsize:=OS_ADDR
else
retcgsize:=def_cgsize(p.returndef);
location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
p.funcretloc[side].size:=retcgsize;
{ void has no location }
if is_void(p.returndef) then
begin
location_reset(p.funcretloc[side],LOC_VOID,OS_NO);
exit;
end;
{ Return is passed as var parameter }
if ret_in_param(p.returndef,p.proccalloption) then
begin
p.funcretloc[side].loc:=LOC_REFERENCE;
p.funcretloc[side].size:=retcgsize;
exit;
end;
{ Return in FPU register? }
if p.returndef.typ=floatdef then
begin
if (p.proccalloption in [pocall_softfloat]) or (cs_fp_emulation in current_settings.moduleswitches) then
begin
case retcgsize of
OS_64,
OS_F64:
begin
{ low }
p.funcretloc[side].loc:=LOC_REGISTER;
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG;
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG;
p.funcretloc[side].size:=OS_64;
end;
OS_32,
OS_F32:
begin
p.funcretloc[side].loc:=LOC_REGISTER;
p.funcretloc[side].register:=NR_FUNCTION_RETURN_REG;
p.funcretloc[side].size:=OS_32;
end;
else
internalerror(2005082603);
end;
end
else
begin
p.funcretloc[side].loc:=LOC_FPUREGISTER;
p.funcretloc[side].register:=NR_FPU_RESULT_REG;
end;
end
{ Return in register }
else
begin
if retcgsize in [OS_64,OS_S64] then
begin
{ low }
p.funcretloc[side].loc:=LOC_REGISTER;
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG;
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG;
end
else
begin
p.funcretloc[side].loc:=LOC_REGISTER;
p.funcretloc[side].register:=NR_FUNCTION_RETURN_REG;
end;
end;
end;
function tavrparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
var
cur_stack_offset: aword;
curintreg, curfloatreg, curmmreg: tsuperregister;
begin
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
{ just continue loading the parameters in the registers }
result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset)
else
internalerror(200410231);
end;
begin
paramanager:=tavrparamanager.create;
end.

84
compiler/avr/cpupi.pas Normal file
View File

@ -0,0 +1,84 @@
{
Copyright (c) 2008 by Florian Klaempfl
This unit contains the CPU specific part of tprocinfo
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{ This unit contains the CPU specific part of tprocinfo. }
unit cpupi;
{$i fpcdefs.inc}
interface
uses
globtype,cutils,
procinfo,cpuinfo,psub;
type
tavrprocinfo = class(tcgprocinfo)
floatregstart : aint;
// procedure handle_body_start;override;
// procedure after_pass1;override;
procedure set_first_temp_offset;override;
function calc_stackframe_size:longint;override;
end;
implementation
uses
globals,systems,
cpubase,
aasmtai,aasmdata,
tgobj,
symconst,symsym,paramgr,
cgbase,
cgobj;
procedure tavrprocinfo.set_first_temp_offset;
begin
{ We allocate enough space to save all registers because we can't determine
the necessary space because the used registers aren't known before
secondpass is run. Even worse, patching
the local offsets after generating the code could cause trouble because
"shifter" constants could change to non-"shifter" constants. This
is especially a problem when taking the address of a local. For now,
this extra memory should hurt less than generating all local contants with offsets
>256 as non shifter constants }
if tg.direction = -1 then
tg.setfirsttemp(-12-28)
else
tg.setfirsttemp(maxpushedparasize);
end;
function tavrprocinfo.calc_stackframe_size:longint;
var
firstfloatreg,lastfloatreg,
r : byte;
floatsavesize : aword;
begin
maxpushedparasize:=align(maxpushedparasize,max(current_settings.alignment.localalignmin,4));
end;
begin
cprocinfo:=tavrprocinfo;
end.

72
compiler/avr/cputarg.pas Normal file
View File

@ -0,0 +1,72 @@
{
Copyright (c) 2001-2008 by Peter Vreman
Includes the AVR dependent target units
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit cputarg;
{$i fpcdefs.inc}
interface
implementation
uses
systems { prevent a syntax error when nothing is included }
{**************************************
Targets
**************************************}
{$ifndef NOTARGETEMBEDDED}
,t_embed
{$endif}
{**************************************
Assemblers
**************************************}
{$ifndef NOAGARMGAS}
,agarmgas
{$endif}
,ogcoff
{**************************************
Assembler Readers
**************************************}
{$ifndef NoRaarmgas}
,raarmgas
{$endif NoRaarmgas}
{**************************************
Debuginfo
**************************************}
{$ifndef NoDbgStabs}
,dbgstabs
{$endif NoDbgStabs}
{$ifndef NoDbgDwarf}
,dbgdwarf
{$endif NoDbgDwarf}
;
end.

34
compiler/avr/ravrcon.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
NR_NO = tregister($00000000);
NR_R0 = tregister($01000000);
NR_R1 = tregister($01000001);
NR_R2 = tregister($01000002);
NR_R3 = tregister($01000003);
NR_R4 = tregister($01000004);
NR_R5 = tregister($01000005);
NR_R6 = tregister($01000006);
NR_R7 = tregister($01000007);
NR_R8 = tregister($01000008);
NR_R9 = tregister($01000009);
NR_R10 = tregister($0100000a);
NR_R11 = tregister($0100000b);
NR_R12 = tregister($0100000c);
NR_R13 = tregister($0100000d);
NR_R14 = tregister($0100000e);
NR_R15 = tregister($0100000f);
NR_R16 = tregister($01000010);
NR_R17 = tregister($01000011);
NR_R18 = tregister($01000012);
NR_R19 = tregister($01000013);
NR_R20 = tregister($01000014);
NR_R21 = tregister($01000015);
NR_R22 = tregister($01000016);
NR_R23 = tregister($01000017);
NR_R24 = tregister($01000018);
NR_R25 = tregister($01000019);
NR_R26 = tregister($0100001a);
NR_R27 = tregister($0100001b);
NR_R28 = tregister($0100001c);
NR_R29 = tregister($0100001d);
NR_R30 = tregister($0100001e);
NR_R31 = tregister($0100001f);

34
compiler/avr/ravrdwa.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
-1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31

2
compiler/avr/ravrnor.inc Normal file
View File

@ -0,0 +1,2 @@
{ don't edit, this file is generated from avrreg.dat }
33

34
compiler/avr/ravrnum.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
tregister($00000000),
tregister($01000000),
tregister($01000001),
tregister($01000002),
tregister($01000003),
tregister($01000004),
tregister($01000005),
tregister($01000006),
tregister($01000007),
tregister($01000008),
tregister($01000009),
tregister($0100000a),
tregister($0100000b),
tregister($0100000c),
tregister($0100000d),
tregister($0100000e),
tregister($0100000f),
tregister($01000010),
tregister($01000011),
tregister($01000012),
tregister($01000013),
tregister($01000014),
tregister($01000015),
tregister($01000016),
tregister($01000017),
tregister($01000018),
tregister($01000019),
tregister($0100001a),
tregister($0100001b),
tregister($0100001c),
tregister($0100001d),
tregister($0100001e),
tregister($0100001f)

34
compiler/avr/ravrrni.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32

34
compiler/avr/ravrsri.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
0,
1,
2,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
3,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
4,
31,
32,
5,
6,
7,
8,
9,
10

34
compiler/avr/ravrsta.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
-1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31

34
compiler/avr/ravrstd.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
'INVALID',
'r0',
'r1',
'r2',
'r3',
'r4',
'r5',
'r6',
'r7',
'r8',
'r9',
'r10',
'r11',
'r12',
'r13',
'r14',
'r15',
'r16',
'r17',
'r18',
'r19',
'r20',
'r21',
'r22',
'r23',
'r24',
'r25',
'r26',
'r27',
'r28',
'r29',
'r30',
'r31'

34
compiler/avr/ravrsup.inc Normal file
View File

@ -0,0 +1,34 @@
{ don't edit, this file is generated from avrreg.dat }
RS_NO = $00;
RS_R0 = $00;
RS_R1 = $01;
RS_R2 = $02;
RS_R3 = $03;
RS_R4 = $04;
RS_R5 = $05;
RS_R6 = $06;
RS_R7 = $07;
RS_R8 = $08;
RS_R9 = $09;
RS_R10 = $0a;
RS_R11 = $0b;
RS_R12 = $0c;
RS_R13 = $0d;
RS_R14 = $0e;
RS_R15 = $0f;
RS_R16 = $10;
RS_R17 = $11;
RS_R18 = $12;
RS_R19 = $13;
RS_R20 = $14;
RS_R21 = $15;
RS_R22 = $16;
RS_R23 = $17;
RS_R24 = $18;
RS_R25 = $19;
RS_R26 = $1a;
RS_R27 = $1b;
RS_R28 = $1c;
RS_R29 = $1d;
RS_R30 = $1e;
RS_R31 = $1f;

80
compiler/avr/rgcpu.pas Normal file
View File

@ -0,0 +1,80 @@
{
Copyright (c) 1998-2008 by Florian Klaempfl
This unit implements the avr specific class for the register
allocator
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit rgcpu;
{$i fpcdefs.inc}
interface
uses
aasmbase,aasmtai,aasmdata,aasmcpu,
cgbase,cgutils,
cpubase,
rgobj;
type
trgcpu = class(trgobj)
procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override;
end;
trgintcpu = class(trgcpu)
procedure add_cpu_interferences(p : tai);override;
end;
implementation
uses
verbose, cutils,
cgobj,
procinfo;
procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
begin
inherited do_spill_read(list,pos,spilltemp,tempreg);
end;
procedure trgcpu.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);
begin
inherited do_spill_written(list,pos,spilltemp,tempreg);
end;
procedure trgintcpu.add_cpu_interferences(p : tai);
var
r : tregister;
begin
if p.typ=ait_instruction then
begin
case taicpu(p).opcode of
A_LD:
;
end;
end;
end;
end.

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -661,6 +661,9 @@ interface
{$ifdef MIPS}
pbestrealtype : ^tdef = @s64floattype;
{$endif MIPS}
{$ifdef AVR}
pbestrealtype : ^tdef = @s64floattype;
{$endif AVR}
function make_mangledname(const typeprefix:string;st:TSymtable;const suffix:string):string;

275
compiler/utils/mkavrreg.pp Normal file
View File

@ -0,0 +1,275 @@
{
Copyright (c) 1998-2002 by Peter Vreman and Florian Klaempfl
Convert spreg.dat to several .inc files for usage with
the Free pascal compiler
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
program mkspreg;
const Version = '1.00';
max_regcount = 200;
var s : string;
i : longint;
line : longint;
regcount:byte;
regcount_bsstart:byte;
names,
regtypes,
supregs,
numbers,
stdnames,
stabs,dwarf : array[0..max_regcount-1] of string[63];
regnumber_index,
std_regname_index : array[0..max_regcount-1] of byte;
function tostr(l : longint) : string;
begin
str(l,tostr);
end;
function readstr : string;
var
result : string;
begin
result:='';
while (s[i]<>',') and (i<=length(s)) do
begin
result:=result+s[i];
inc(i);
end;
readstr:=result;
end;
procedure readcomma;
begin
if s[i]<>',' then
begin
writeln('Missing "," at line ',line);
writeln('Line: "',s,'"');
halt(1);
end;
inc(i);
end;
procedure skipspace;
begin
while (s[i] in [' ',#9]) do
inc(i);
end;
procedure openinc(var f:text;const fn:string);
begin
writeln('creating ',fn);
assign(f,fn);
rewrite(f);
writeln(f,'{ don''t edit, this file is generated from avrreg.dat }');
end;
procedure closeinc(var f:text);
begin
writeln(f);
close(f);
end;
procedure build_regnum_index;
var h,i,j,p,t:byte;
begin
{Build the registernumber2regindex index.
Step 1: Fill.}
for i:=0 to regcount-1 do
regnumber_index[i]:=i;
{Step 2: Sort. We use a Shell-Metzner sort.}
p:=regcount_bsstart;
repeat
for h:=0 to regcount-p-1 do
begin
i:=h;
repeat
j:=i+p;
if numbers[regnumber_index[j]]>=numbers[regnumber_index[i]] then
break;
t:=regnumber_index[i];
regnumber_index[i]:=regnumber_index[j];
regnumber_index[j]:=t;
if i<p then
break;
dec(i,p);
until false;
end;
p:=p shr 1;
until p=0;
end;
procedure build_std_regname_index;
var h,i,j,p,t:byte;
begin
{Build the registernumber2regindex index.
Step 1: Fill.}
for i:=0 to regcount-1 do
std_regname_index[i]:=i;
{Step 2: Sort. We use a Shell-Metzner sort.}
p:=regcount_bsstart;
repeat
for h:=0 to regcount-p-1 do
begin
i:=h;
repeat
j:=i+p;
if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then
break;
t:=std_regname_index[i];
std_regname_index[i]:=std_regname_index[j];
std_regname_index[j]:=t;
if i<p then
break;
dec(i,p);
until false;
end;
p:=p shr 1;
until p=0;
end;
procedure read_spreg_file;
var infile:text;
begin
{ open dat file }
assign(infile,'avrreg.dat');
reset(infile);
while not(eof(infile)) do
begin
{ handle comment }
readln(infile,s);
inc(line);
while (s[1]=' ') do
delete(s,1,1);
if (s='') or (s[1]=';') then
continue;
i:=1;
names[regcount]:=readstr;
readcomma;
regtypes[regcount]:=readstr;
readcomma;
supregs[regcount]:=readstr;
readcomma;
stdnames[regcount]:=readstr;
readcomma;
stabs[regcount]:=readstr;
readcomma;
dwarf[regcount]:=readstr;
{ Create register number }
if supregs[regcount][1]<>'$' then
begin
writeln('Missing $ before number, at line ',line);
writeln('Line: "',s,'"');
halt(1);
end;
numbers[regcount]:=regtypes[regcount]+'0000'+copy(supregs[regcount],2,255);
if i<length(s) then
begin
writeln('Extra chars at end of line, at line ',line);
writeln('Line: "',s,'"');
halt(1);
end;
inc(regcount);
if regcount>max_regcount then
begin
writeln('Error: Too much registers, please increase maxregcount in source');
halt(2);
end;
end;
close(infile);
end;
procedure write_inc_files;
var
norfile,stdfile,supfile,
numfile,stabfile,dwarffile,confile,
rnifile,srifile:text;
first:boolean;
begin
{ create inc files }
openinc(confile,'ravrcon.inc');
openinc(supfile,'ravrsup.inc');
openinc(numfile,'ravrnum.inc');
openinc(stdfile,'ravrstd.inc');
openinc(stabfile,'ravrsta.inc');
openinc(dwarffile,'ravrdwa.inc');
openinc(norfile,'ravrnor.inc');
openinc(rnifile,'ravrrni.inc');
openinc(srifile,'ravrsri.inc');
first:=true;
for i:=0 to regcount-1 do
begin
if not first then
begin
writeln(numfile,',');
writeln(stdfile,',');
writeln(stabfile,',');
writeln(dwarffile,',');
writeln(rnifile,',');
writeln(srifile,',');
end
else
first:=false;
writeln(supfile,'RS_',names[i],' = ',supregs[i],';');
writeln(confile,'NR_'+names[i],' = ','tregister(',numbers[i],')',';');
write(numfile,'tregister(',numbers[i],')');
write(stdfile,'''',stdnames[i],'''');
write(stabfile,stabs[i]);
write(dwarffile,dwarf[i]);
write(rnifile,regnumber_index[i]);
write(srifile,std_regname_index[i]);
end;
write(norfile,regcount);
close(confile);
close(supfile);
closeinc(numfile);
closeinc(stdfile);
closeinc(stabfile);
closeinc(dwarffile);
closeinc(norfile);
closeinc(rnifile);
closeinc(srifile);
writeln('Done!');
writeln(regcount,' registers procesed');
end;
begin
writeln('Register Table Converter Version ',Version);
line:=0;
regcount:=0;
read_spreg_file;
regcount_bsstart:=1;
while 2*regcount_bsstart<regcount do
regcount_bsstart:=regcount_bsstart*2;
build_regnum_index;
build_std_regname_index;
write_inc_files;
end.