mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 04:39:28 +01:00 
			
		
		
		
	* allow -128 to 255 as a constant for instructions taking a byte sized constants (this is also what GNU As accepts), resolves #32039 git-svn-id: trunk@38316 -
		
			
				
	
	
		
			378 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			378 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
 | 
						|
 | 
						|
    Handles the common arm assembler reader routines
 | 
						|
 | 
						|
    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 raavr;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
    uses
 | 
						|
      cpubase,
 | 
						|
      aasmtai,aasmdata,
 | 
						|
      rautils,
 | 
						|
      globtype;
 | 
						|
 | 
						|
    type
 | 
						|
       TAVROperand=class(TOperand)
 | 
						|
      end;
 | 
						|
 | 
						|
      TAVRInstruction=class(TInstruction)
 | 
						|
        function ConcatInstruction(p:TAsmList) : tai;override;
 | 
						|
      end;
 | 
						|
 | 
						|
      TRegType = (rt_all, rt_even, rt_16_31, rt_even_24_30, rt_16_23, rt_XYZ, rt_YZ, rt_X, rt_Y, rt_Z);
 | 
						|
 | 
						|
      TAVROpConstraint = record
 | 
						|
        case typ : toptype of
 | 
						|
          top_none   : ();
 | 
						|
          top_reg    : (rt: TRegType; am: set of taddressmode; minconst, maxconst: tcgint);
 | 
						|
          top_ref,
 | 
						|
          top_const  : (max, min: tcgint);
 | 
						|
      end;
 | 
						|
 | 
						|
      // Constraints of operands per opcode
 | 
						|
      // Encode variable number of operands by bit position, e.g.
 | 
						|
      // 2 operands = 1 shl 2 = 4
 | 
						|
      // 1 or 2 operands = 1 shl 1 + 1 shl 2 = 6
 | 
						|
      TAVRInstrConstraint = record
 | 
						|
        numOperands: byte;
 | 
						|
        Operands: array[0..max_operands-1] of TAVROpConstraint;
 | 
						|
      end;
 | 
						|
 | 
						|
  const
 | 
						|
    AVRInstrConstraint: array[TAsmOp] of TAVRInstrConstraint =
 | 
						|
      // A_NONE
 | 
						|
      ((numOperands: 0; Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
      // A_ADD
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ADC
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ADIW
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_even_24_30), (typ: top_const; max: 63; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SUB
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SUBI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBC
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBCI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBRC
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBRS
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBIW
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_even_24_30), (typ: top_const; max: 63; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_AND
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ANDI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_OR
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ORI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_EOR
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_COM
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_NEG
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBR
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CBR
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_INC
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_DEC
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_TST
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_MUL
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_MULS
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_reg; rt: rt_16_31), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_MULSU
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_23), (typ: top_reg; rt: rt_16_23), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_FMUL
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_23), (typ: top_reg; rt: rt_16_23), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_FMULS
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_23), (typ: top_reg; rt: rt_16_23), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_FMULSU
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_23), (typ: top_reg; rt: rt_16_23), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_RJMP
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 2047; min: -2048), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_IJMP
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_EIJMP
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_JMP, max size depends on size op PC
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: (1 shl 22 - 1); min: 0), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_RCALL
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 2047; min: -2048), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ICALL
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_EICALL
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CALL, max size depends on size op PC
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: (1 shl 22 - 1); min: 0), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_RET
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_IRET
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CPSE
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CP
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CPC
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CPI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBIC
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 31; min: 0), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBIS
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 31; min: 0), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BRxx
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 63; min: -64), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_MOV
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_MOVW
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_even), (typ: top_reg; rt: rt_even), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LDI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_const; max: 255; min: -128), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LDS TODO: There are 2 versions with different machine codes and constant ranges. Could possibly distinguish based on size of PC?
 | 
						|
       // Perhaps handle separately with a check on sub-architecture? Range check only important if smaller instruction code selected on larger arch
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 65535; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LD
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_XYZ; am: [AM_UNCHANGED, AM_POSTINCREMENT, AM_PREDRECEMENT]), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LDD
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_YZ; am: [AM_UNCHANGED]; minconst: 0; maxconst: 63), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_STS TODO: See LDS above
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 65535; min: 0), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ST
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_XYZ; am: [AM_UNCHANGED, AM_POSTINCREMENT, AM_PREDRECEMENT]), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_STD
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_YZ; am: [AM_UNCHANGED]; minconst: 0; maxconst: 63), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LPM
 | 
						|
       (numOperands: (1 shl 0 + 1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_Z; am: [AM_UNCHANGED, AM_POSTINCREMENT]), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ELPM
 | 
						|
       (numOperands: (1 shl 0 + 1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_reg; rt: rt_Z; am: [AM_UNCHANGED, AM_POSTINCREMENT]), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SPM
 | 
						|
       (numOperands: (1 shl 0 + 1 shl 1); Operands: ((typ: top_reg; rt: rt_Z; am: [AM_UNCHANGED, AM_POSTINCREMENT]), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_IN
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 63; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_OUT
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 63; min: 0), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_PUSH
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_POP
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LSL
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_LSR
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ROL
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ROR
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_ASR
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SWAP
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BSET
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BCLR
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SBI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 32; min: 0), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CBI
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_const; max: 32; min: 0), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEC
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEH
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEI
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEN
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SER
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_16_31), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SES
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SET
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEV
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SEZ
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLC
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLH
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLI
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLN
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLR
 | 
						|
       (numOperands: (1 shl 1); Operands: ((typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLS
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLT
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLV
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_CLZ
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BST
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BLD
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_all), (typ: top_const; max: 7; min: 0), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_BREAK
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_NOP
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_SLEEP
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_WDR
 | 
						|
       (numOperands: (1 shl 0); Operands: ((typ: top_none), (typ: top_none), (typ: top_none), (typ: top_none))),
 | 
						|
       // A_XCH
 | 
						|
       (numOperands: (1 shl 2); Operands: ((typ: top_reg; rt: rt_Z), (typ: top_reg; rt: rt_all), (typ: top_none), (typ: top_none)))
 | 
						|
       );
 | 
						|
 | 
						|
  implementation
 | 
						|
    uses
 | 
						|
      aasmcpu, verbose, cgbase, itcpugas;
 | 
						|
 | 
						|
    function TAVRInstruction.ConcatInstruction(p:TAsmList) : tai;
 | 
						|
      var
 | 
						|
        i: integer;
 | 
						|
        err, opregasref: boolean;
 | 
						|
        s1, s2: string;
 | 
						|
        reg: tregister;
 | 
						|
      begin
 | 
						|
        result:=inherited ConcatInstruction(p);
 | 
						|
 | 
						|
        if Result.typ = ait_instruction then
 | 
						|
          begin
 | 
						|
            // check if number of operands fall inside the allowed set
 | 
						|
            if ((1 shl taicpu(Result).ops) and AVRInstrConstraint[opcode].numOperands = 0)  then
 | 
						|
              Message(asmr_e_invalid_opcode_and_operand)
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                for i := 0 to taicpu(Result).ops-1 do
 | 
						|
                  begin
 | 
						|
                    err := true;
 | 
						|
                    opregasref := false;
 | 
						|
                    // Type check
 | 
						|
                    if (taicpu(Result).oper[i]^.typ = AVRInstrConstraint[opcode].Operands[i].typ) then
 | 
						|
                      err := false
 | 
						|
 | 
						|
                    // if label was specified check if const is expected
 | 
						|
                    else if (AVRInstrConstraint[opcode].Operands[i].typ = top_const) and (taicpu(Result).oper[i]^.typ = top_ref) then
 | 
						|
                      err := false
 | 
						|
 | 
						|
                    // Also expressions such as X+, -Z and X+8 are classified as TOP_REF
 | 
						|
                    else if (AVRInstrConstraint[opcode].Operands[i].typ = top_reg) and (taicpu(Result).oper[i]^.typ = top_ref) and
 | 
						|
                             (int64(taicpu(Result).oper[i]^.ref^.base) and $01030000 > 0) then
 | 
						|
                      begin
 | 
						|
                        err := false;
 | 
						|
                        opregasref := true;
 | 
						|
                        reg := taicpu(Result).oper[i]^.ref^.base;
 | 
						|
                      end
 | 
						|
                    // LDD r1, a or STD a, r1 where a is local variable => type is set to top_local
 | 
						|
                    // also mov r10, TypeCastToByte(procParam) returns top_local for typecasted param
 | 
						|
                    // but no further information is available at this point to check
 | 
						|
                    else if (AVRInstrConstraint[opcode].Operands[i].typ = top_reg) and (taicpu(Result).oper[i]^.typ = top_local) and
 | 
						|
                            (opcode in [A_LDD, A_STD, A_MOV]) then
 | 
						|
                      begin
 | 
						|
                        err := false;
 | 
						|
                      end;
 | 
						|
 | 
						|
                    if err then
 | 
						|
                      begin
 | 
						|
                        WriteStr(s1, taicpu(Result).oper[i]^.typ);
 | 
						|
                        WriteStr(s2, AVRInstrConstraint[opcode].Operands[i].typ);
 | 
						|
                        Message2(type_e_incompatible_types, s1, s2);
 | 
						|
                      end
 | 
						|
                    else if (taicpu(Result).oper[i]^.typ = top_reg) or opregasref then
 | 
						|
                      begin
 | 
						|
                        err := false;
 | 
						|
                        if not opregasref then
 | 
						|
                          reg := taicpu(Result).oper[i]^.reg;
 | 
						|
 | 
						|
                        case AVRInstrConstraint[opcode].Operands[i].rt of
 | 
						|
                          rt_all: err := int64(reg) > $1030000;  // excluding pointer registers X, Y, Z
 | 
						|
                          rt_even:    err := int64(reg) mod 2 = 1;
 | 
						|
                          rt_even_24_30:  err := not(word(reg) in [24, 26, 28, 30]);
 | 
						|
                          rt_16_31: err := not(word(reg) in [16..31]);
 | 
						|
                          rt_16_23: err := not(word(reg) in [16..23]);
 | 
						|
                          rt_Z: err := (int64(reg) <> $0103001e);
 | 
						|
                          rt_YZ: err := not((int64(reg) = $0103001c) or
 | 
						|
                                         (int64(reg) =$0103001e));
 | 
						|
                          rt_XYZ: err := not((int64(reg) = $0103001a) or
 | 
						|
                                         (int64(reg) = $0103001c) or
 | 
						|
                                         (int64(reg) = $0103001e));
 | 
						|
                        end;
 | 
						|
 | 
						|
                        // Catch erroneous z if it should be z+k or something similar
 | 
						|
                        // By checking if .am is not empty (implying a reference is expected)
 | 
						|
 | 
						|
                        // ldd R20, z should not pass  => opregasref = true
 | 
						|
                        // but ldd R20, z+1 should pass => opregasref = false
 | 
						|
                        if not (err) and (AVRInstrConstraint[opcode].Operands[i].am = [AM_UNCHANGED]) then
 | 
						|
                          err := not opregasref;
 | 
						|
 | 
						|
                        if not (err) and not(AM_UNCHANGED in AVRInstrConstraint[opcode].Operands[i].am) and
 | 
						|
                          ((AM_POSTINCREMENT in AVRInstrConstraint[opcode].Operands[i].am) or
 | 
						|
                           (AM_PREDRECEMENT in AVRInstrConstraint[opcode].Operands[i].am)) then
 | 
						|
                          err := not opregasref;
 | 
						|
 | 
						|
                        if not(err) and opregasref then
 | 
						|
                          begin
 | 
						|
                            if (taicpu(Result).oper[i]^.ref^.addressmode = AM_UNCHANGED) and
 | 
						|
                                  (AM_UNCHANGED in AVRInstrConstraint[opcode].Operands[i].am) then
 | 
						|
                               err := ((taicpu(Result).oper[i]^.ref^.offset > AVRInstrConstraint[opcode].Operands[i].maxconst) or
 | 
						|
                                      (taicpu(Result).oper[i]^.ref^.offset < AVRInstrConstraint[opcode].Operands[i].minconst))
 | 
						|
 | 
						|
                            else if (taicpu(Result).oper[i]^.ref^.addressmode in AVRInstrConstraint[opcode].Operands[i].am) then
 | 
						|
                              err := false
 | 
						|
 | 
						|
                            else
 | 
						|
                              err := true;
 | 
						|
                          end;
 | 
						|
 | 
						|
                          if err then
 | 
						|
                            Message1(asmr_e_invalid_ref_register, gas_regname(reg));
 | 
						|
                        end
 | 
						|
                      else if taicpu(Result).oper[i]^.typ = top_const then
 | 
						|
                        begin
 | 
						|
                          // Need to check if original value was signed or simply sign overflowed in 16 bit?
 | 
						|
                          if ((taicpu(Result).oper[i]^.val > AVRInstrConstraint[opcode].Operands[i].max) or
 | 
						|
                              (taicpu(Result).oper[i]^.val < AVRInstrConstraint[opcode].Operands[i].min)) then
 | 
						|
                            Message(asmr_e_constant_out_of_bounds);
 | 
						|
                        end;
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
end.
 |