| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 | {    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={$i z80op.inc}      { This should define the array of instructions as string }      op2strtable=array[tasmop] of string[4];    const      { First value of opcode enumeration }      firstop = low(tasmop);      { Last value of opcode enumeration  }      lastop  = high(tasmop);      std_op2str:op2strtable={$i z80stdopnames.inc}      { call/reg instructions are not considered as jmp instructions for the usage cases of        this set }      jmp_instructions = [A_JP,A_JR,A_JRJP,A_DJNZ];      call_jmp_instructions = [A_CALL]+jmp_instructions;      { instructions that can have a condition }      cond_instructions = [A_CALL,A_JP,A_JR,A_JRJP,A_RET];{*****************************************************************************                                  Registers*****************************************************************************}    type      { Number of registers used for indexing in tables }      tregisterindex=0..{$i rz80nor.inc}-1;    const      { Available Superregisters }      {$i rz80sup.inc}      { No Subregisters }      R_SUBWHOLE = R_SUBL;      { Available Registers }      {$i rz80con.inc}      { Integer Super registers first and last }      first_int_supreg = RS_A;      first_int_imreg = $20;      { Float Super register first and last }      first_fpu_supreg    = RS_INVALID;      first_fpu_imreg     = 0;      { MM Super register first and last }      first_mm_supreg    = RS_INVALID;      first_mm_imreg     = 0;      regnumber_count_bsstart = 32;      regnumber_table : array[tregisterindex] of tregister = (        {$i rz80num.inc}      );      regstabs_table : array[tregisterindex] of shortint = (        {$i rz80sta.inc}      );      regdwarf_table : array[tregisterindex] of shortint = (        {$i rz80dwa.inc}      );      { registers which may be destroyed by calls }      VOLATILE_INTREGISTERS = [RS_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L];      VOLATILE_FPUREGISTERS = [];    type      totherregisterset = set of tregisterindex;{*****************************************************************************                                Conditions*****************************************************************************}    type      TAsmCond=(C_None,        C_NZ,C_Z,C_NC,C_C,C_PO,C_PE,C_P,C_M      );    const      cond2str : array[TAsmCond] of string[2]=('',        'nz','z','nc','c','po','pe','p','m'      );      uppercond2str : array[TAsmCond] of string[2]=('',        'NZ','Z','NC','C','PO','PE','P','M'      );{*****************************************************************************                                   Flags*****************************************************************************}    type      TResFlags = (F_NotPossible,F_NE,F_E,F_NC,F_C,F_PO,F_PE,F_P,F_M);{*****************************************************************************                                 Constants*****************************************************************************}    const      max_operands = 2;      maxintregs = 15;      maxfpuregs = 0;      maxaddrregs = 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_INVALID;      lastsaveintreg  = RS_INVALID;      firstsavefpureg = RS_INVALID;      lastsavefpureg  = RS_INVALID;      firstsavemmreg  = RS_INVALID;      lastsavemmreg   = RS_INVALID;{*****************************************************************************                          Default generic sizes*****************************************************************************}      { Defines the default address size for a processor, }      OS_ADDR = OS_16;      { the natural int size for a processor,        has to match osuinttype/ossinttype as initialized in psystem,        initially, this was OS_16/OS_S16 on avr, but experience has        proven that it is better to make it 8 Bit thus having the same        size as a register.      }      OS_INT = OS_8;      OS_SINT = OS_S8;      { 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_SP;      RS_STACK_POINTER_REG = RS_SP;      { Frame pointer register }      RS_FRAME_POINTER_REG = RS_IX;      NR_FRAME_POINTER_REG = NR_IX;      { 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_INVALID;      { Results are returned in this register (32-bit values) }      NR_FUNCTION_RETURN_REG = NR_L;      RS_FUNCTION_RETURN_REG = RS_L;      { Low part of 64bit return value }      NR_FUNCTION_RETURN64_LOW_REG = NR_L;      RS_FUNCTION_RETURN64_LOW_REG = RS_L;      { High part of 64bit return value }      NR_FUNCTION_RETURN64_HIGH_REG = NR_C;      RS_FUNCTION_RETURN64_HIGH_REG = RS_C;      { 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;      NR_DEFAULTFLAGS = NR_F;      RS_DEFAULTFLAGS = RS_F;{*****************************************************************************                       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.      }      { on avr, gen_entry/gen_exit code saves/restores registers, so        we don't need this array }      saved_standard_registers : array[0..0] of tsuperregister =        (RS_INVALID);      { 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;      saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID);      saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID);{*****************************************************************************                                  Helpers*****************************************************************************}    { Returns the tcgsize corresponding with the size of reg.}    function reg_cgsize(const reg: tregister) : tcgsize;    function cgsize2subreg(regtype: tregistertype; 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 is_regpair(r:Tregister):boolean;    procedure split_regpair(regpair:Tregister;out reglo,reghi:Tregister);    { Checks if sreg is a subset of reg (e.g. NR_H is a subset of NR_HL }    function register_in(sreg,reg:Tregister):boolean;    function super_registers_equal(reg1,reg2 : TRegister) : Boolean;    function registers_interfere(reg1,reg2: TRegister) : Boolean;    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}    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }    function condition_in(const Subset, c: TAsmCond): Boolean;    function dwarf_reg(r:tregister):byte;    function dwarf_reg_no_error(r:tregister):shortint;    function eh_return_data_regno(nr: longint): longint;    function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}  implementation    uses      rgBase,verbose;    const      std_regname_table : TRegNameTable = (        {$i rz80std.inc}      );      regnumber_index : array[tregisterindex] of tregisterindex = (        {$i rz80rni.inc}      );      std_regname_index : array[tregisterindex] of tregisterindex = (        {$i rz80sri.inc}      );    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;      begin        cgsize2subreg:=R_SUBWHOLE;      end;    function reg_cgsize(const reg: tregister): tcgsize;      begin        case getregtype(reg) of          R_INTREGISTER,          R_SPECIALREGISTER:            case getsubreg(reg) of              R_SUBNONE,              R_SUBL,              R_SUBH:                reg_cgsize:=OS_8;              R_SUBW:                reg_cgsize:=OS_16;              else                internalerror(2020041901);            end;          R_ADDRESSREGISTER:            reg_cgsize:=OS_16;          else            internalerror(2011021905);          end;        end;    procedure inverse_flags(var f: TResFlags);      const        inv_flags: array[TResFlags] of TResFlags =          (F_NotPossible,F_E,F_NE,F_C,F_NC,F_PE,F_PO,F_M,F_P);      begin        f:=inv_flags[f];      end;    function flags_to_cond(const f: TResFlags) : TAsmCond;      const        flag_2_cond: array[F_NE..F_M] of TAsmCond =          (C_NZ,C_Z,C_NC,C_C,C_PO,C_PE,C_P,C_M);      begin        if f=F_NotPossible then          internalerror(2011022101);        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;    function is_regpair(r: Tregister): boolean;      begin        result:=(r=NR_AF) or (r=NR_BC) or (r=NR_DE) or (r=NR_HL);      end;    procedure split_regpair(regpair: Tregister; out reglo, reghi: Tregister);      begin        case regpair of          NR_AF:            begin              reglo:=NR_F;              reghi:=NR_A;            end;          NR_BC:            begin              reglo:=NR_C;              reghi:=NR_B;            end;          NR_DE:            begin              reglo:=NR_E;              reghi:=NR_D;            end;          NR_HL:            begin              reglo:=NR_L;              reghi:=NR_H;            end;          else            internalerror(2020042804);        end;      end;    function register_in(sreg,reg: Tregister):boolean;      var        tmpreg1, tmpreg2: Tregister;      begin        if sreg=reg then          result:=true        else if is_regpair(reg) then          begin            split_regpair(reg,tmpreg1,tmpreg2);            result:=(sreg=tmpreg1) or (sreg=tmpreg2);          end        else          result:=false;      end;    function super_registers_equal(reg1, reg2: TRegister): Boolean;      begin        case reg1 of          NR_A,NR_F,NR_AF,NR_CARRYFLAG,NR_ADDSUBTRACTFLAG,NR_PARITYOVERFLOWFLAG,NR_HALFCARRYFLAG,NR_ZEROFLAG,NR_SIGNFLAG:            result:=(reg2=NR_A) or (reg2=NR_F) or (reg2=NR_AF) or                    (reg2=NR_CARRYFLAG) or (reg2=NR_ADDSUBTRACTFLAG) or                    (reg2=NR_PARITYOVERFLOWFLAG) or (reg2=NR_HALFCARRYFLAG) or                    (reg2=NR_ZEROFLAG) or (reg2=NR_SIGNFLAG);          NR_B,NR_C,NR_BC:            result:=(reg2=NR_B) or (reg2=NR_C) or (reg2=NR_BC);          NR_D,NR_E,NR_DE:            result:=(reg2=NR_D) or (reg2=NR_E) or (reg2=NR_DE);          NR_H,NR_L,NR_HL:            result:=(reg2=NR_H) or (reg2=NR_L) or (reg2=NR_HL);          NR_A_,NR_F_,NR_AF_,NR_CARRYFLAG_,NR_ADDSUBTRACTFLAG_,NR_PARITYOVERFLOWFLAG_,NR_HALFCARRYFLAG_,NR_ZEROFLAG_,NR_SIGNFLAG_:            result:=(reg2=NR_A_) or (reg2=NR_F_) or (reg2=NR_AF_) or                    (reg2=NR_CARRYFLAG_) or (reg2=NR_ADDSUBTRACTFLAG_) or                    (reg2=NR_PARITYOVERFLOWFLAG_) or (reg2=NR_HALFCARRYFLAG_) or                    (reg2=NR_ZEROFLAG_) or (reg2=NR_SIGNFLAG_);          NR_B_,NR_C_,NR_BC_:            result:=(reg2=NR_B_) or (reg2=NR_C_) or (reg2=NR_BC_);          NR_D_,NR_E_,NR_DE_:            result:=(reg2=NR_D_) or (reg2=NR_E_) or (reg2=NR_DE_);          NR_H_,NR_L_,NR_HL_:            result:=(reg2=NR_H_) or (reg2=NR_L_) or (reg2=NR_HL_);          else            result:=reg1=reg2;        end;      end;    function registers_interfere(reg1, reg2: TRegister): Boolean;      begin        case reg1 of          NR_A:            result:=(reg2=NR_A) or (reg2=NR_AF);          NR_F:            result:=(reg2=NR_F) or (reg2=NR_AF) or                    (reg2=NR_CARRYFLAG) or (reg2=NR_ADDSUBTRACTFLAG) or                    (reg2=NR_PARITYOVERFLOWFLAG) or (reg2=NR_HALFCARRYFLAG) or                    (reg2=NR_ZEROFLAG) or (reg2=NR_SIGNFLAG);          NR_AF:            result:=(reg2=NR_A) or (reg2=NR_F) or (reg2=NR_AF) or                    (reg2=NR_CARRYFLAG) or (reg2=NR_ADDSUBTRACTFLAG) or                    (reg2=NR_PARITYOVERFLOWFLAG) or (reg2=NR_HALFCARRYFLAG) or                    (reg2=NR_ZEROFLAG) or (reg2=NR_SIGNFLAG);          NR_CARRYFLAG,NR_ADDSUBTRACTFLAG,NR_PARITYOVERFLOWFLAG,NR_HALFCARRYFLAG,NR_ZEROFLAG,NR_SIGNFLAG:            result:=(reg2=NR_F) or (reg2=NR_AF) or (reg2=reg1);          NR_B:            result:=(reg2=NR_B) or (reg2=NR_BC);          NR_C:            result:=(reg2=NR_C) or (reg2=NR_BC);          NR_BC:            result:=(reg2=NR_B) or (reg2=NR_C) or (reg2=NR_BC);          NR_D:            result:=(reg2=NR_D) or (reg2=NR_DE);          NR_E:            result:=(reg2=NR_E) or (reg2=NR_DE);          NR_DE:            result:=(reg2=NR_D) or (reg2=NR_E) or (reg2=NR_DE);          NR_H:            result:=(reg2=NR_H) or (reg2=NR_HL);          NR_L:            result:=(reg2=NR_L) or (reg2=NR_HL);          NR_HL:            result:=(reg2=NR_H) or (reg2=NR_L) or (reg2=NR_HL);          NR_A_:            result:=(reg2=NR_A_) or (reg2=NR_AF_);          NR_F_:            result:=(reg2=NR_F_) or (reg2=NR_AF_) or                    (reg2=NR_CARRYFLAG_) or (reg2=NR_ADDSUBTRACTFLAG_) or                    (reg2=NR_PARITYOVERFLOWFLAG_) or (reg2=NR_HALFCARRYFLAG_) or                    (reg2=NR_ZEROFLAG_) or (reg2=NR_SIGNFLAG_);          NR_AF_:            result:=(reg2=NR_A_) or (reg2=NR_F_) or (reg2=NR_AF_) or                    (reg2=NR_CARRYFLAG_) or (reg2=NR_ADDSUBTRACTFLAG_) or                    (reg2=NR_PARITYOVERFLOWFLAG_) or (reg2=NR_HALFCARRYFLAG_) or                    (reg2=NR_ZEROFLAG_) or (reg2=NR_SIGNFLAG_);          NR_CARRYFLAG_,NR_ADDSUBTRACTFLAG_,NR_PARITYOVERFLOWFLAG_,NR_HALFCARRYFLAG_,NR_ZEROFLAG_,NR_SIGNFLAG_:            result:=(reg2=NR_F_) or (reg2=NR_AF_) or (reg2=reg1);          NR_B_:            result:=(reg2=NR_B_) or (reg2=NR_BC_);          NR_C_:            result:=(reg2=NR_C_) or (reg2=NR_BC_);          NR_BC_:            result:=(reg2=NR_B_) or (reg2=NR_C_) or (reg2=NR_BC_);          NR_D_:            result:=(reg2=NR_D_) or (reg2=NR_DE_);          NR_E_:            result:=(reg2=NR_E_) or (reg2=NR_DE_);          NR_DE_:            result:=(reg2=NR_D_) or (reg2=NR_E_) or (reg2=NR_DE_);          NR_H_:            result:=(reg2=NR_H_) or (reg2=NR_HL_);          NR_L_:            result:=(reg2=NR_L_) or (reg2=NR_HL_);          NR_HL_:            result:=(reg2=NR_H_) or (reg2=NR_L_) or (reg2=NR_HL_);          else            result:=reg1=reg2;        end;      end;    function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}      const        inverse: array[TAsmCond] of TAsmCond=(C_None,          C_Z,C_NZ,C_C,C_NC,C_PE,C_PO,C_M,C_P);      begin        result := inverse[c];      end;    function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}      begin        result := c1 = c2;      end;    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }    function condition_in(const Subset, c: TAsmCond): Boolean;      begin        { Z80 has no condition subsets }        Result := {(c.cond = C_None) or} conditions_equal(Subset, c);      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;      var        reg : shortint;      begin        reg:=regdwarf_table[findreg_by_number(r)];        if reg=-1 then          internalerror(200603251);        result:=reg;      end;    function dwarf_reg_no_error(r:tregister):shortint;      begin        result:=regdwarf_table[findreg_by_number(r)];      end;    function eh_return_data_regno(nr: longint): longint;      begin        result:=-1;      end;    function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}      begin        is_calljmp:= o in call_jmp_instructions;      end;end.
 |