2
0
Эх сурвалжийг харах

* patch (indention adapted) by Christo Crause to check avr inline assembler, resolves also #32261

git-svn-id: trunk@38286 -
florian 7 жил өмнө
parent
commit
4cb9ad7e01

+ 2 - 0
.gitattributes

@@ -14351,6 +14351,7 @@ tests/webtbf/tw32043b.pp svneol=native#text/pascal
 tests/webtbf/tw32043c.pp svneol=native#text/pascal
 tests/webtbf/tw32075.pp svneol=native#text/pascal
 tests/webtbf/tw3218.pp svneol=native#text/plain
+tests/webtbf/tw32261.pp svneol=native#text/pascal
 tests/webtbf/tw3241.pp svneol=native#text/plain
 tests/webtbf/tw32412a.pp svneol=native#text/pascal
 tests/webtbf/tw32412b.pp svneol=native#text/pascal
@@ -15806,6 +15807,7 @@ tests/webtbs/tw29669.pp svneol=native#text/plain
 tests/webtbs/tw29669a.pp svneol=native#text/plain
 tests/webtbs/tw29745.pp svneol=native#text/pascal
 tests/webtbs/tw2975.pp svneol=native#text/plain
+tests/webtbs/tw29758.pp svneol=native#text/pascal
 tests/webtbs/tw2976.pp svneol=native#text/plain
 tests/webtbs/tw29792.pp svneol=native#text/pascal
 tests/webtbs/tw2983.pp svneol=native#text/plain

+ 329 - 4
compiler/avr/raavr.pas

@@ -28,7 +28,8 @@ unit raavr;
     uses
       cpubase,
       aasmtai,aasmdata,
-      rautils;
+      rautils,
+      globtype;
 
     type
        TAVROperand=class(TOperand)
@@ -38,15 +39,339 @@ unit raavr;
         function ConcatInstruction(p:TAsmList) : tai;override;
       end;
 
-  implementation
+      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: 0), (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: 0), (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: 0), (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: 0), (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: 0), (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: 0), (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: 0), (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: 0), (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;
+      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);
-      end;
 
+        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(cg_e_parasize_too_big);
+                        end;
+                  end;
+              end;
+          end;
+      end;
 
 end.

+ 10 - 0
tests/webtbf/tw32261.pp

@@ -0,0 +1,10 @@
+{%fail}
+{%CPU=avr}
+
+program webtbf32261;
+
+begin
+  asm
+    cp r24, 8  // 2nd operand should be a register
+  end;
+end.

+ 20 - 0
tests/webtbs/tw29758.pp

@@ -0,0 +1,20 @@
+{ %CPU=avr}
+{ %norun }
+
+program webtbs29758;
+
+type
+  TDoubleByte = packed record
+    l, h: byte;
+  end;
+
+var a: word;
+
+procedure check2(aparam: word); assembler;
+asm
+  mov r20, TDoubleByte(aparam).l
+end;
+
+begin
+  check2(a);
+end.