? out.txt
Index: cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.10
diff -u -p -r1.10 cpu.h
--- cpu.h	17 Apr 2005 19:16:13 -0000	1.10
+++ cpu.h	29 Apr 2005 17:13:13 -0000
@@ -42,8 +42,8 @@
  */
 
 typedef struct CPUARMState {
-    uint32_t regs[16];
-    uint32_t cpsr;
+  uint32_t regs[16];
+  uint32_t cpsr;
     
     /* cpsr flag cache for faster execution */
     uint32_t CF; /* 0 or 1 */
Index: op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/op.c,v
retrieving revision 1.13
diff -u -p -r1.13 op.c
--- op.c	27 Apr 2005 20:25:20 -0000	1.13
+++ op.c	29 Apr 2005 17:13:14 -0000
@@ -91,6 +91,15 @@ void OPPROTO op_bx_T0(void)
   env->thumb = (T0 & 1) != 0;
 }
 
+/* Special case of moving an immediate constant into R15.  Used by
+   branch, SWI and undefined instruction handlers.  We simplify the
+   instruction sequence by not having to clear the bottom 2 bits as
+   we assume the instruction is already word-aligned.  */
+void OPPROTO op_movl_r15_im_excp (void)
+{
+  env->regs[15] = PARAM1;
+}
+
 void OPPROTO op_movl_T0_0(void)
 {
     T0 = 0;
@@ -116,6 +125,11 @@ void OPPROTO op_movl_T2_im(void)
     T2 = PARAM1;
 }
 
+void OPPROTO op_addl_T0_im(void)
+{
+    T0 += PARAM1;
+}
+
 void OPPROTO op_addl_T1_im(void)
 {
     T1 += PARAM1;
@@ -473,6 +487,28 @@ void OPPROTO op_stl_T0_T1(void)
     stl((void *)T1, T0);
 }
 
+/* Create an indexed instruction.  T0=T1[T2].  */
+void OPPROTO op_ldl_T0_T1_imm(void)
+{
+  T0 = ldl ((void *) T1 + PARAM1);
+}
+
+void OPPROTO op_ldub_T0_T1_imm(void)
+{
+  T0 = ldub ((void *) T1 + PARAM1);
+}
+
+/* Create an indexed instruction.  T1[T2]=T0.  */
+void OPPROTO op_stl_T0_T1_imm(void)
+{
+  stl ((void *) T1 + PARAM1, T0);
+}
+
+void OPPROTO op_stb_T0_T1_imm(void)
+{
+  stb ((void *) T1 + PARAM1, T0);
+}
+
 void OPPROTO op_swpb_T0_T1(void)
 {
     int tmp;
Index: op_template.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/op_template.h,v
retrieving revision 1.2
diff -u -p -r1.2 op_template.h
--- op_template.h	31 Jan 2005 20:43:28 -0000	1.2
+++ op_template.h	29 Apr 2005 17:13:14 -0000
@@ -48,6 +48,11 @@ void OPPROTO glue(glue(op_movl_, REGNAME
     SET_REG (T1);
 }
 
+void OPPROTO glue(glue(op_movl_, REGNAME), _im)(void)
+{
+    SET_REG (PARAM1);
+}
+
 #undef REG
 #undef REGNAME
 #undef SET_REG
Index: translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.24
diff -u -p -r1.24 translate.c
--- translate.c	27 Apr 2005 20:25:20 -0000	1.24
+++ translate.c	29 Apr 2005 17:13:18 -0000
@@ -252,6 +252,25 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] 
     gen_op_movl_T2_im,
 };
 
+static GenOpFunc1 *gen_op_movl_reg_im[16] = {
+    gen_op_movl_r0_im,
+    gen_op_movl_r1_im,
+    gen_op_movl_r2_im,
+    gen_op_movl_r3_im,
+    gen_op_movl_r4_im,
+    gen_op_movl_r5_im,
+    gen_op_movl_r6_im,
+    gen_op_movl_r7_im,
+    gen_op_movl_r8_im,
+    gen_op_movl_r9_im,
+    gen_op_movl_r10_im,
+    gen_op_movl_r11_im,
+    gen_op_movl_r12_im,
+    gen_op_movl_r13_im,
+    gen_op_movl_r14_im,
+    gen_op_movl_r15_im
+};
+
 static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
     gen_op_shll_T0_im_thumb,
     gen_op_shrl_T0_im_thumb,
@@ -1362,6 +1381,202 @@ static void disas_arm_insn(CPUState * en
                 }
             }
             break;
+#if 1
+        case 0x4:
+        case 0x6:
+	  {
+	    /* Single data transfer instructions with post-indexed
+	       addressing.  */
+
+	    /* Non-zero if address translation should occur i.e. a USR
+	       mode transfer.  */
+	    int translation_bit = insn & (1 << 21);
+
+	    /* Non-zero if this is a load operation.  */
+	    int load = insn & (1 << 20);
+
+	    /* Non-zero if this is a byte operation, rather than a word.  */
+	    int byte = insn & (1 << 22);
+
+	    /* Base register for addressing.  */
+            rn = (insn >> 16) & 0xf;
+
+	    /* Source or destination register.  */
+            rd = (insn >> 12) & 0xf;
+
+	    if (rn == 15) {
+		int val = (int) s->pc + 4;
+		gen_op_movl_TN_im[1](val);
+	    } else {
+		/* T1 = Rn */
+
+		/* FIXME.  At this point we should check if the
+		   translation bit is set and load from the USR banked
+		   register.  */
+		gen_movl_T1_reg (s, rn);
+	    }
+	    
+	    if (load) {
+		/* printf ("LDR R%d, [R%d], #%d\n", rd, rn, val); */
+		if (byte)
+		  gen_op_ldub_T0_T1 ();
+		else
+		  gen_op_ldl_T0_T1 ();
+
+		if (rd == 15)
+		  gen_bx (s);
+		else
+		  gen_movl_reg_T0 (s, rd);
+	    } else {
+		/* printf ("STR R%d, [R%d], #%d\n", rd, rn, val); */
+		gen_movl_T0_reg (s, rd);
+		if (byte)
+		  gen_op_stb_T0_T1 ();
+		else
+		  gen_op_stl_T0_T1 ();
+	    }
+
+	    /* Update Rn.  */
+	    gen_add_data_offset (s, insn);
+	    gen_movl_reg_T1 (s, rn);
+	  }
+	  break;
+
+        case 0x5:
+        case 0x7:
+	  {
+	    /* Single data transfer instructions with pre-indexed
+	       addressing.  */
+
+	    /* Non-zero if pre-indexed addressing is used.  */
+	    int pre_indexed = insn & (1 << 24);
+
+	    /* Non-zero if write-back bit is set.  */
+	    int write_back = insn & (1 << 21);
+
+	    /* Non zero if we are using the register form, rather
+	       than immediate addressing.  */
+	    int reg_form = insn & (1 << 25);
+
+	    /* Non-zero if this is a load operation.  */
+	    int load = insn & (1 << 20);
+
+	    /* Non-zero if this is a byte operation, rather than a word.  */
+	    int byte = insn & (1 << 22);
+
+	    /* Non-zero if offset is added to the base register.  */
+	    int positive = insn & (1 << 23);
+
+	    /* Base register for addressing.  */
+            rn = (insn >> 16) & 0xf;
+
+	    /* Source or destination register.  */
+            rd = (insn >> 12) & 0xf;
+
+	    if (reg_form) {
+		/* Add Rm to Rn.  */
+		gen_movl_T1_reg (s, rn);
+		gen_add_data_offset (s, insn);
+		
+		if (load) {
+		    /* printf ("LDR R%d, [R%d, Rx]\n", rd, rn); */
+		    /* Load Rd from Rn.  */
+		    if (byte)
+		      gen_op_ldub_T0_T1 ();
+		    else
+		      gen_op_ldl_T0_T1 ();
+
+		    if (rd == 15)
+		      gen_bx (s);
+		    else
+		      gen_movl_reg_T0(s, rd);
+		} else {
+		    /* printf ("STR R%d, [R%d, Rx]\n", rd, rn); */
+		    /* Store Rd to Rn.  */
+		    gen_movl_T0_reg (s, rd);
+		    if (byte)
+		      gen_op_stb_T0_T1 ();
+		    else
+		      gen_op_stl_T0_T1 ();
+		}
+
+		if (write_back)
+		  /* Write back requested, so update Rn with new value.  */
+		  gen_movl_reg_T1 (s, rn);
+	    } else {
+		/* Immediate form.  */
+		int val = insn & 0xfff;
+		if (! positive)
+		  val = - val;
+		if (rn == 15) {
+		    /* Got either
+		       LDR rd, [pc, #offset]
+		       STR rd, [pc, #offset]
+		    
+		       We can optimise since we already know the value of
+		       the program counter.  */
+		    val += (int) s->pc + 4;
+		    gen_op_movl_TN_im[1](val);
+
+		    if (load) {
+			/* printf ("LDR R%d, [pc, #%d]\n", rd, val); */
+			/* Store Rd to Rn.  */
+			if (byte)
+			  gen_op_ldub_T0_T1 ();
+			else
+			  gen_op_ldl_T0_T1 ();
+
+			if (rd == 15)
+			  gen_bx (s);
+			else
+			  gen_movl_reg_T0(s, rd);
+		    } else {
+			/* printf ("STR R%d, [pc, #%d]\n", rd, val); */
+			/* Load Rd from Rn.  */
+		        gen_movl_T0_reg (s, rd);
+			if (byte)
+			  gen_op_stb_T0_T1 ();
+			else
+			  gen_op_stl_T0_T1 ();
+		    }
+		} else {
+		    /* Got either
+		       LDR rd, [rn, #offset]
+		       STR rd, [rn, #offset]
+		    */
+
+		    /* T1 = Rn */
+		    gen_movl_T1_reg (s, rn);
+
+		    if (load) {
+			/* printf ("LDR R%d, [R%d, #%d]\n", rd, rn, val); */
+			if (byte)
+			    gen_op_ldub_T0_T1_imm (val);
+			else
+			    gen_op_ldl_T0_T1_imm (val);
+
+			if (rd == 15)
+			    gen_bx (s);
+			else
+			    gen_movl_reg_T0 (s, rd);
+		    } else {
+		        /* printf ("STR R%d, [R%d, #%d]\n", rd, rn, val); */
+		        gen_movl_T0_reg (s, rd);
+
+			if (byte)
+			    gen_op_stb_T0_T1_imm (val);
+			else
+			    gen_op_stl_T0_T1_imm (val);
+		    }
+		}
+		if (write_back) {
+		    gen_op_addl_T1_im (val);
+		    gen_movl_reg_T1 (s, rn);
+		}
+	    }
+	  }
+	  break;
+#else
         case 0x4:
         case 0x5:
         case 0x6:
@@ -1369,9 +1584,22 @@ static void disas_arm_insn(CPUState * en
             /* load/store byte/word */
             rn = (insn >> 16) & 0xf;
             rd = (insn >> 12) & 0xf;
-            gen_movl_T1_reg(s, rn);
-            if (insn & (1 << 24))
-                gen_add_data_offset(s, insn);
+	    if (rn == 15 && !(insn & (1 << 25)))
+	      {
+		/* PC relative load with immediate constant.  We can
+		   combine a mov and add instruction into one mov.  */
+		int val = insn & 0xfff;
+		if (! (insn & (1 << 23)))
+		  val = -val;
+		val += (int) s->pc + 4;
+		gen_op_movl_TN_im[1](val);
+	      }
+	    else
+	      {
+		gen_movl_T1_reg(s, rn);
+		if (insn & (1 << 24))
+		  gen_add_data_offset(s, insn);
+	      }
             if (insn & (1 << 20)) {
                 /* load */
                 if (insn & (1 << 22))
@@ -1397,6 +1625,163 @@ static void disas_arm_insn(CPUState * en
                 gen_movl_reg_T1(s, rn); {
             }
             break;
+#endif
+#if 1
+        case 0x08:
+        case 0x09:
+            {
+	      /* Load/Store multiple instruction.  */
+
+	      /* Non-zero if base register will be updated after operation.  */
+	      int writeback = insn & (1 << 21);
+
+	      /* Non-zero if this is a load rather than a store operation.  */
+	      int load = insn & (1 << 20);
+
+	      /* Non-zero if this operation increments the base register
+		 after each operation, zero if it is to be decremented.  */
+	      int incr = insn & (1 << 23);
+
+	      /* Non-zero if the adjustment of the base register should
+		 before each load.  Zero if it should occur after.  */
+	      int before = insn & (1 << 24);
+
+	      /* Bottom 16 bits of instruction hold the mask of registers.  */
+	      int mask = insn & 0xffff;
+
+	      int regno;
+	      int offset = 0;
+
+	      /* Calculate number of registers in mask.  This is only
+	         used for adjusting the base register final offset.  */
+	      int total_regs = 0;
+              for (i = 0; i < 16; i++) {
+		  if (mask & (1 << i))
+		    total_regs ++;
+              }
+
+	      if (insn & (1 << 22))
+	      	goto illegal_op; /* only usable in supervisor mode */
+
+	      /* When incrementing or decrementing the base register before
+		 a load/store operation, it is similar to loading an
+		 extra register.  */
+
+	      /* Base register for addressing.  T1 = rn */
+	      rn = (insn >> 16) & 0xf;
+	      gen_movl_T1_reg (s, rn);
+
+	      /* Registers are always stored with the lowest register
+		 in the lowest position in memory.  So we adjust the
+	         base register accordingly.  After this, accesses from
+	         the base register will always be positive.  */
+
+	      if (load) {
+		  if (incr) {
+		      if (before)
+			/* A LDMIB operation.  Keep base register the same,
+			   but just increase the memory offset that we use
+			   by one.  */
+			offset += 4;
+		  } else {
+		      if (before) {
+			  /* LDMDB R5, {R0, R1, R2}
+			     where R5 == 0x1484, it will load:
+			       R0 from 0x1478
+			       R1 from 0x147c
+			       R2 from 0x1480
+
+			     With writeback set, R5 will be set to 0x1478
+			     on completion.  */			  
+			  gen_op_addl_T1_im (- total_regs * 4);
+		      } else
+			/* A LDMDA operation.  */
+			gen_op_addl_T1_im (- (total_regs - 1) * 4);
+		  }
+	      } else {
+		  if (incr) {
+		      if (before)
+			/* A STMIB operation.  */
+			offset += 4;
+		  } else {
+		      if (before) {
+			  /* STMDB R5, {R0, R1, R2}
+			     where R5 == 0x1484, it will store
+			       R0 at 0x1478
+			       R1 to 0x147c
+			       R2 to 0x1480
+
+			     With writeback set, R5 will be set to 0x1478
+			     on completion.  */
+			  gen_op_addl_T1_im (- total_regs * 4);
+		      } else {
+			  /* STMDA R5, {R0, R1, R2}
+			     where R5 == 0x1484, it will store
+			       R0 at 0x1478
+			       R1 to 0x1480
+			       R2 to 0x1484
+
+			     With writeback set, R5 will be set to 0x1474
+			     after.  */
+			  gen_op_addl_T1_im (- (total_regs - 1) * 4);
+			  /* offset++ */
+		      }
+		  }
+	      }
+
+	      for (regno = 0; regno < 16; regno ++) {
+		  if (mask & 1) {
+		      if (load) {
+			  /* Load operation.  */
+			  gen_op_ldl_T0_T1_imm (offset);
+			  if (regno == 15) {
+			      /* Special case for R15.  */
+			      gen_bx (s);
+			  } else
+			      gen_movl_reg_T0 (s, regno);
+		      } else {
+			  /* Store operation.  */
+			  if (regno == 15) {
+			      /* R15 is a special case.  We store PC + 12.  */
+			      int val = (long) s->pc + 8;
+			      gen_op_movl_TN_im[0](val);
+			  } else {
+			      /* FIXME.  At this point we should check if the
+				 translation bit is set and store the
+				 USR banked register.  */
+			      gen_movl_T0_reg (s, regno);
+
+			      /* When writing a register that appears as a
+				 base register, we write the value it would
+				 have as if the register had been incremented
+				 for each store.  */
+			      if (regno == rn)
+				  gen_op_addl_T0_im (offset);
+			  }
+			  gen_op_stl_T0_T1_imm (offset);
+		      }
+		      
+		      offset += 4;
+		  }
+		  mask >>= 1;
+	      }
+
+	      if (writeback) {
+		  /* Adjust the base register accordingly.  NB: as opposed
+		     to a decrementing stack, we don't need to perform
+		     this adjustment with no writeback.  */
+		  if (incr) {
+		      if (before)
+			  gen_op_addl_T1_im ((total_regs + 1) * 4);
+		      else
+			  gen_op_addl_T1_im (total_regs * 4);
+		  }
+		  
+		  gen_movl_reg_T1 (s, rn);
+	      }
+            }
+            break;
+#else
         case 0x08:
         case 0x09:
             {
@@ -1482,6 +1867,7 @@ static void disas_arm_insn(CPUState * en
                 }
             }
             break;
+#endif
         case 0xa:
         case 0xb:
             {
@@ -1490,8 +1876,12 @@ static void disas_arm_insn(CPUState * en
                 /* branch (and link) */
                 val = (int32_t)s->pc;
                 if (insn & (1 << 24)) {
+#if 1
+		    gen_op_movl_r14_im (val);
+#else
                     gen_op_movl_T0_im(val);
                     gen_op_movl_reg_TN[0][14]();
+#endif
                 }
                 offset = (((int32_t)insn << 8) >> 8);
                 val += (offset << 2) + 4;
@@ -1516,15 +1906,23 @@ static void disas_arm_insn(CPUState * en
             break;
         case 0xf:
             /* swi */
+#if 1
+	    gen_op_movl_r15_im_excp((long) s->pc);
+#else
             gen_op_movl_T0_im((long)s->pc);
             gen_op_movl_reg_TN[0][15]();
+#endif
             gen_op_swi();
             s->is_jmp = DISAS_JUMP;
             break;
         default:
         illegal_op:
+#if 1
+	    gen_op_movl_r15_im_excp((long) s->pc - 4);
+#else
             gen_op_movl_T0_im((long)s->pc - 4);
             gen_op_movl_reg_TN[0][15]();
+#endif
             gen_op_undef_insn();
             s->is_jmp = DISAS_JUMP;
             break;
@@ -2147,7 +2545,8 @@ static inline int gen_intermediate_code_
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "----------------\n");
-        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+        /* fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); */
+        fprintf(logfile, "IN:\n");
         target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
         fprintf(logfile, "\n");
         if (loglevel & (CPU_LOG_TB_OP)) {
