Browse Source

Add MSR/MRS for ARMv6M/7M.
Fix bug in FPA LFM/SFM.
Add usermode handling of LDM/STM.

git-svn-id: branches/laksen/armiw@29371 -

Jeppe Johansen 10 years ago
parent
commit
572076fc4d
4 changed files with 89 additions and 3 deletions
  1. 71 2
      compiler/arm/aasmcpu.pas
  2. 3 0
      compiler/arm/armins.dat
  3. 1 1
      compiler/arm/armnop.inc
  4. 14 0
      compiler/arm/armtab.inc

+ 71 - 2
compiler/arm/aasmcpu.pas

@@ -3327,6 +3327,22 @@ implementation
                       { set Rn }
                       bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16);
                     end;
+
+                  if oper[1]^.usermode then
+                    begin
+                      if (oper[0]^.typ=top_ref) then
+                        begin
+                          if (opcode=A_LDM) and
+                             (RS_PC in oper[1]^.regset^) then
+                            begin
+                              // Valid exception return
+                            end
+                          else
+                            Message(asmw_e_invalid_opcode_and_operands);
+                        end;
+
+                      bytes:=bytes or (1 shl 22);
+                    end;
                   { reglist }
                   bytes:=bytes or MakeRegList(oper[1]^.regset^);
                 end
@@ -5083,6 +5099,59 @@ implementation
                       (oper[0]^.typ=top_const) then
                 bytes:=bytes or (oper[0]^.val and $1F);
             end;
+          #$96: { Thumb-2: MSR/MRS }
+            begin
+              { set instruction code }
+              bytes:=bytes or (ord(insentry^.code[1]) shl 24);
+              bytes:=bytes or (ord(insentry^.code[2]) shl 16);
+              bytes:=bytes or (ord(insentry^.code[3]) shl 8);
+              bytes:=bytes or ord(insentry^.code[4]);
+
+              if opcode=A_MRS then
+                begin
+                  bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8);
+
+                  case oper[1]^.reg of
+                    NR_MSP: bytes:=bytes or $08;
+                    NR_PSP: bytes:=bytes or $09;
+
+                    NR_IPSR: bytes:=bytes or $05;
+                    NR_EPSR: bytes:=bytes or $06;
+                    NR_APSR: bytes:=bytes or $00;
+
+                    NR_PRIMASK: bytes:=bytes or $10;
+                    NR_BASEPRI: bytes:=bytes or $11;
+                    NR_BASEPRI_MAX: bytes:=bytes or $12;
+                    NR_FAULTMASK: bytes:=bytes or $13;
+                    NR_CONTROL: bytes:=bytes or $14;
+                  else
+                    Message(asmw_e_invalid_opcode_and_operands);
+                  end;
+                end
+              else
+                begin
+                  bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16);
+
+                  case oper[0]^.reg of
+                    NR_APSR,
+                    NR_APSR_nzcvqg: bytes:=bytes or $C00;
+                    NR_APSR_g: bytes:=bytes or $400;
+                    NR_APSR_nzcvq: bytes:=bytes or $800;
+
+                    NR_MSP: bytes:=bytes or $08;
+                    NR_PSP: bytes:=bytes or $09;
+
+                    NR_PRIMASK: bytes:=bytes or $10;
+                    NR_BASEPRI: bytes:=bytes or $11;
+                    NR_BASEPRI_MAX: bytes:=bytes or $12;
+
+                    NR_FAULTMASK: bytes:=bytes or $13;
+                    NR_CONTROL: bytes:=bytes or $14;
+                  else
+                    Message(asmw_e_invalid_opcode_and_operands);
+                  end;
+                end;
+            end;
           #$A0: { FPA: CPDT(LDF/STF) }
             begin
               { set instruction code }
@@ -5127,7 +5196,7 @@ implementation
                   bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16;
                   bytes:=bytes or ((oper[2]^.ref^.offset shr 2) and $FF);
                   if oper[2]^.ref^.offset>=0 then
-                    bytes:=bytes or (2 shl 23);
+                    bytes:=bytes or (1 shl 23);
 
                   if oper[2]^.ref^.addressmode<>AM_OFFSET then
                     bytes:=bytes or (1 shl 21);
@@ -5274,7 +5343,7 @@ implementation
         end;
 
         { Todo: Decide whether the code above should take care of writing data in an order that makes senes }
-        if (insentry^.code[0] in [#$80..#$95]) and (bytelen=4) then
+        if (insentry^.code[0] in [#$80..#$96]) and (bytelen=4) then
           bytes:=((bytes shr 16) and $FFFF) or ((bytes and $FFFF) shl 16);
 
         { we're finished, write code }

+ 3 - 0
compiler/arm/armins.dat

@@ -395,9 +395,12 @@ reg32,reg32,shifterop   \xA\x1\xA0                       ARM32,ARMv4
 reg32,immshifter        \xB\x1\xA0                       ARM32,ARMv4
 
 [MRScc]
+reg32,regf          \x90\xF3\xEF\x80\x0                 THUMB32,ARMv6
 reg32,regf          \x10\x01\x0F                        ARM32,ARMv4
 
 [MSRcc]
+regf,reg32          \x90\xF3\x80\x80\x0                 THUMB32,ARMv6
+
 regf,reg32          \x12\x01\x20\xF0                    ARM32,ARMv4
 regf,immshifter     \x13\x03\x20\xF0                    ARM32,ARMv4
 regs,immshifter     \x13\x03\x20\xF0                    ARM32,ARMv4

+ 1 - 1
compiler/arm/armnop.inc

@@ -1,2 +1,2 @@
 { don't edit, this file is generated from armins.dat }
-826;
+828;

+ 14 - 0
compiler/arm/armtab.inc

@@ -1323,6 +1323,13 @@
     code    : #11#1#160;
     flags   : if_arm32 or if_armv4
   ),
+  (
+    opcode  : A_MRS;
+    ops     : 2;
+    optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none);
+    code    : #144#243#239#128#0;
+    flags   : if_thumb32 or if_armv6
+  ),
   (
     opcode  : A_MRS;
     ops     : 2;
@@ -1330,6 +1337,13 @@
     code    : #16#1#15;
     flags   : if_arm32 or if_armv4
   ),
+  (
+    opcode  : A_MSR;
+    ops     : 2;
+    optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none);
+    code    : #144#243#128#128#0;
+    flags   : if_thumb32 or if_armv6
+  ),
   (
     opcode  : A_MSR;
     ops     : 2;