full system SPARC emulation (Blue Swirl)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1087 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/.cvsignore b/.cvsignore
index 9fad653..bca4882 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -12,3 +12,4 @@
 qemu.pod
 sparc-user
 qemu-img
+sparc-softmmu
diff --git a/Changelog b/Changelog
index bf8efc5..8bbe6d9 100644
--- a/Changelog
+++ b/Changelog
@@ -17,6 +17,7 @@
   - Fixed Fedora Core 2 problems (now you can run qemu without any
     LD_ASSUME_KERNEL tricks on FC2)
   - DHCP fix for Windows (accept DHCPREQUEST alone)
+  - SPARC system emulation (Blue Swirl)
 
 version 0.6.0:
 
diff --git a/Makefile.target b/Makefile.target
index 28585c7..ff07be8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -63,6 +63,26 @@
 endif # ARCH = amd64
 
 endif # TARGET_ARCH = ppc
+
+ifeq ($(TARGET_ARCH), sparc)
+
+ifeq ($(ARCH), ppc)
+PROGS+=$(QEMU_SYSTEM)
+endif
+
+ifeq ($(ARCH), i386)
+ifdef CONFIG_SOFTMMU
+PROGS+=$(QEMU_SYSTEM)
+endif
+endif # ARCH = i386
+
+ifeq ($(ARCH), amd64)
+ifdef CONFIG_SOFTMMU
+PROGS+=$(QEMU_SYSTEM)
+endif
+endif # ARCH = amd64
+
+endif # TARGET_ARCH = sparc
 endif # !CONFIG_USER_ONLY
 
 ifdef CONFIG_STATIC
@@ -201,6 +221,10 @@
 LIBOBJS+= op_helper.o helper.o
 endif
 
+ifeq ($(TARGET_ARCH), sparc)
+LIBOBJS+= op_helper.o helper.o
+endif
+
 # NOTE: the disassembler code is only needed for debugging
 LIBOBJS+=disas.o 
 ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -254,6 +278,9 @@
 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o
 endif
+ifeq ($(TARGET_ARCH), sparc)
+VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o
+endif
 ifdef CONFIG_GDBSTUB
 VL_OBJS+=gdbstub.o 
 endif
@@ -325,7 +352,7 @@
 endif
 
 ifeq ($(TARGET_ARCH), sparc)
-op.o: op.c op_template.h
+op.o: op.c op_template.h op_mem.h
 endif
 
 ifeq ($(TARGET_ARCH), ppc)
diff --git a/configure b/configure
index 54f1a9f..5d7eed6 100755
--- a/configure
+++ b/configure
@@ -27,7 +27,7 @@
 make="make"
 strip="strip"
 cpu=`uname -m`
-target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu"
+target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu sparc-softmmu"
 case "$cpu" in
   i386|i486|i586|i686|i86pc|BePC)
     cpu="i386"
@@ -99,7 +99,7 @@
   if [ ! "$darwin" = "yes" ] ; then
     make="gmake"
   fi
-  target_list="i386-softmmu ppc-softmmu"
+  target_list="i386-softmmu ppc-softmmu sparc-softmmu"
 fi
 
 # find source path
@@ -160,7 +160,7 @@
 strip="${cross_prefix}${strip}"
 
 if test "$mingw32" = "yes" ; then
-    target_list="i386-softmmu ppc-softmmu"
+    target_list="i386-softmmu ppc-softmmu sparc-softmmu"
     EXESUF=".exe"
     gdbstub="no"
 fi
diff --git a/cpu-exec.c b/cpu-exec.c
index 053c0cc..930bd7b 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -208,6 +208,11 @@
                                  env->exception_next_eip, 0);
 #elif defined(TARGET_PPC)
                     do_interrupt(env);
+#elif defined(TARGET_SPARC)
+                    do_interrupt(env->exception_index, 
+                                 0,
+                                 env->error_code, 
+                                 env->exception_next_pc, 0);
 #endif
                 }
                 env->exception_index = -1;
@@ -261,6 +266,14 @@
                             env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
 			}
                     }
+#elif defined(TARGET_SPARC)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+			do_interrupt(0, 0, 0, 0, 0);
+                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
+			//do_interrupt(0, 0, 0, 0, 0);
+			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+		    }
 #endif
                     if (interrupt_request & CPU_INTERRUPT_EXITTB) {
                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
diff --git a/exec-all.h b/exec-all.h
index b6853a1..2e886e0 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -56,6 +56,7 @@
 extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
 extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
 extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
+extern uint32_t gen_opc_npc[OPC_BUF_SIZE];
 extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
 extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
 
@@ -541,8 +542,7 @@
 
 extern int tb_invalidated_flag;
 
-#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
-    !defined(CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
 
 void tlb_fill(unsigned long addr, int is_write, int is_user, 
               void *retaddr);
@@ -585,6 +585,8 @@
     is_user = ((env->hflags & HF_CPL_MASK) == 3);
 #elif defined (TARGET_PPC)
     is_user = msr_pr;
+#elif defined (TARGET_SPARC)
+    is_user = (env->psrs == 0);
 #else
 #error "Unimplemented !"
 #endif
diff --git a/exec.c b/exec.c
index c33661b..f266bb9 100644
--- a/exec.c
+++ b/exec.c
@@ -1077,7 +1077,7 @@
    breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     int i;
     
     for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1099,7 +1099,7 @@
 /* remove a breakpoint */
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     int i;
     for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)
@@ -1122,7 +1122,7 @@
    CPU loop after each instruction */
 void cpu_single_step(CPUState *env, int enabled)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     if (env->singlestep_enabled != enabled) {
         env->singlestep_enabled = enabled;
         /* must flush all the translated code to avoid inconsistancies */
diff --git a/gdbstub.c b/gdbstub.c
index 1962310..e15216a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -157,42 +157,40 @@
 
 #if defined(TARGET_I386)
 
-static void to_le32(uint8_t *p, int v)
-{
-    p[0] = v;
-    p[1] = v >> 8;
-    p[2] = v >> 16;
-    p[3] = v >> 24;
-}
-
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 {
+    uint32_t *registers = (uint32_t *)mem_buf;
     int i, fpus;
 
     for(i = 0; i < 8; i++) {
-        to_le32(mem_buf + i * 4, env->regs[i]);
+        registers[i] = env->regs[i];
     }
-    to_le32(mem_buf + 8 * 4, env->eip);
-    to_le32(mem_buf + 9 * 4, env->eflags);
-    to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
-    to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
-    to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
-    to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
-    to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
-    to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
+    registers[8] = env->eip;
+    registers[9] = env->eflags;
+    registers[10] = env->segs[R_CS].selector;
+    registers[11] = env->segs[R_SS].selector;
+    registers[12] = env->segs[R_DS].selector;
+    registers[13] = env->segs[R_ES].selector;
+    registers[14] = env->segs[R_FS].selector;
+    registers[15] = env->segs[R_GS].selector;
     /* XXX: convert floats */
     for(i = 0; i < 8; i++) {
         memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
     }
-    to_le32(mem_buf + 36 * 4, env->fpuc);
+    registers[36] = env->fpuc;
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
-    to_le32(mem_buf + 37 * 4, fpus);
-    to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
-    to_le32(mem_buf + 39 * 4, 0); /* fiseg */
-    to_le32(mem_buf + 40 * 4, 0); /* fioff */
-    to_le32(mem_buf + 41 * 4, 0); /* foseg */
-    to_le32(mem_buf + 42 * 4, 0); /* fooff */
-    to_le32(mem_buf + 43 * 4, 0); /* fop */
+    registers[37] = fpus;
+    registers[38] = 0; /* XXX: convert tags */
+    registers[39] = 0; /* fiseg */
+    registers[40] = 0; /* fioff */
+    registers[41] = 0; /* foseg */
+    registers[42] = 0; /* fooff */
+    registers[43] = 0; /* fop */
+    
+    for(i = 0; i < 16; i++)
+        tswapls(&registers[i]);
+    for(i = 36; i < 44; i++)
+        tswapls(&registers[i]);
     return 44 * 4;
 }
 
@@ -204,8 +202,8 @@
     for(i = 0; i < 8; i++) {
         env->regs[i] = tswapl(registers[i]);
     }
-    env->eip = registers[8];
-    env->eflags = registers[9];
+    env->eip = tswapl(registers[8]);
+    env->eflags = tswapl(registers[9]);
 #if defined(CONFIG_USER_ONLY)
 #define LOAD_SEG(index, sreg)\
             if (tswapl(registers[index]) != env->segs[sreg].selector)\
@@ -220,15 +218,6 @@
 }
 
 #elif defined (TARGET_PPC)
-static void to_le32(uint32_t *buf, uint32_t v)
-{
-    uint8_t *p = (uint8_t *)buf;
-    p[3] = v;
-    p[2] = v >> 8;
-    p[1] = v >> 16;
-    p[0] = v >> 24;
-}
-
 static uint32_t from_le32 (uint32_t *buf)
 {
     uint8_t *p = (uint8_t *)buf;
@@ -243,24 +232,24 @@
 
     /* fill in gprs */
     for(i = 0; i < 32; i++) {
-        to_le32(&registers[i], env->gpr[i]);
+        registers[i] = tswapl(env->gpr[i]);
     }
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
-        to_le32(&registers[(i * 2) + 32], *((uint32_t *)&env->fpr[i]));
-	to_le32(&registers[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1));
+        registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
+	registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
-    to_le32(&registers[96], (uint32_t)env->nip/* - 4*/);
-    to_le32(&registers[97], _load_msr(env));
+    registers[96] = tswapl(env->nip);
+    registers[97] = tswapl(_load_msr(env));
     tmp = 0;
     for (i = 0; i < 8; i++)
         tmp |= env->crf[i] << (32 - ((i + 1) * 4));
-    to_le32(&registers[98], tmp);
-    to_le32(&registers[99], env->lr);
-    to_le32(&registers[100], env->ctr);
-    to_le32(&registers[101], _load_xer(env));
-    to_le32(&registers[102], 0);
+    registers[98] = tswapl(tmp);
+    registers[99] = tswapl(env->lr);
+    registers[100] = tswapl(env->ctr);
+    registers[101] = tswapl(_load_xer(env));
+    registers[102] = 0;
 
     return 103 * 4;
 }
@@ -272,22 +261,90 @@
 
     /* fill in gprs */
     for (i = 0; i < 32; i++) {
-        env->gpr[i] = from_le32(&registers[i]);
+        env->gpr[i] = tswapl(registers[i]);
     }
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
-        *((uint32_t *)&env->fpr[i]) = from_le32(&registers[(i * 2) + 32]);
-	*((uint32_t *)&env->fpr[i] + 1) = from_le32(&registers[(i * 2) + 33]);
+        *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
+	*((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
-    env->nip = from_le32(&registers[96]);
-    _store_msr(env, from_le32(&registers[97]));
-    registers[98] = from_le32(&registers[98]);
+    env->nip = tswapl(registers[96]);
+    _store_msr(env, tswapl(registers[97]));
+    registers[98] = tswapl(registers[98]);
     for (i = 0; i < 8; i++)
         env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
-    env->lr = from_le32(&registers[99]);
-    env->ctr = from_le32(&registers[100]);
-    _store_xer(env, from_le32(&registers[101]));
+    env->lr = tswapl(registers[99]);
+    env->ctr = tswapl(registers[100]);
+    _store_xer(env, tswapl(registers[101]));
+}
+#elif defined (TARGET_SPARC)
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+{
+    uint32_t *registers = (uint32_t *)mem_buf, tmp;
+    int i;
+
+    /* fill in g0..g7 */
+    for(i = 0; i < 7; i++) {
+        registers[i] = tswapl(env->gregs[i]);
+    }
+    /* fill in register window */
+    for(i = 0; i < 24; i++) {
+        registers[i + 8] = tswapl(env->regwptr[i]);
+    }
+    /* fill in fprs */
+    for (i = 0; i < 32; i++) {
+        registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
+    }
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    registers[64] = tswapl(env->y);
+    tmp = (0<<28) | (4<<24) | env->psr		\
+	| (env->psrs? PSR_S : 0)		\
+	| (env->psrs? PSR_PS : 0)		\
+	| (env->psret? PSR_ET : 0)		\
+	| env->cwp;
+    registers[65] = tswapl(tmp);
+    registers[66] = tswapl(env->wim);
+    registers[67] = tswapl(env->tbr);
+    registers[68] = tswapl(env->pc);
+    registers[69] = tswapl(env->npc);
+    registers[70] = tswapl(env->fsr);
+    registers[71] = 0; /* csr */
+    registers[72] = 0;
+
+    return 73 * 4;
+}
+
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+{
+    uint32_t *registers = (uint32_t *)mem_buf, tmp;
+    int i;
+
+    /* fill in g0..g7 */
+    for(i = 0; i < 7; i++) {
+        env->gregs[i] = tswapl(registers[i]);
+    }
+    /* fill in register window */
+    for(i = 0; i < 24; i++) {
+        env->regwptr[i] = tswapl(registers[i]);
+    }
+    /* fill in fprs */
+    for (i = 0; i < 32; i++) {
+        *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
+    }
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    env->y = tswapl(registers[64]);
+    tmp = tswapl(registers[65]);
+    env->psr = tmp & ~PSR_ICC;
+    env->psrs = (tmp & PSR_S)? 1 : 0;
+    env->psrps = (tmp & PSR_PS)? 1 : 0;
+    env->psret = (tmp & PSR_ET)? 1 : 0;
+    env->cwp = (tmp & PSR_CWP);
+    env->wim = tswapl(registers[66]);
+    env->tbr = tswapl(registers[67]);
+    env->pc = tswapl(registers[68]);
+    env->npc = tswapl(registers[69]);
+    env->fsr = tswapl(registers[70]);
 }
 #else
 
diff --git a/monitor.c b/monitor.c
index ad0f315..15b54d3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -883,18 +883,18 @@
 typedef struct MonitorDef {
     const char *name;
     int offset;
-    int (*get_value)(struct MonitorDef *md);
+    int (*get_value)(struct MonitorDef *md, int val);
 } MonitorDef;
 
 #if defined(TARGET_I386)
-static int monitor_get_pc (struct MonitorDef *md)
+static int monitor_get_pc (struct MonitorDef *md, int val)
 {
     return cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base;
 }
 #endif
 
 #if defined(TARGET_PPC)
-static int monitor_get_ccr (struct MonitorDef *md)
+static int monitor_get_ccr (struct MonitorDef *md, int val)
 {
     unsigned int u;
     int i;
@@ -906,7 +906,7 @@
     return u;
 }
 
-static int monitor_get_msr (struct MonitorDef *md)
+static int monitor_get_msr (struct MonitorDef *md, int val)
 {
     return (cpu_single_env->msr[MSR_POW] << MSR_POW) |
         (cpu_single_env->msr[MSR_ILE] << MSR_ILE) |
@@ -925,7 +925,7 @@
         (cpu_single_env->msr[MSR_LE] << MSR_LE);
 }
 
-static int monitor_get_xer (struct MonitorDef *md)
+static int monitor_get_xer (struct MonitorDef *md, int val)
 {
     return (cpu_single_env->xer[XER_SO] << XER_SO) |
         (cpu_single_env->xer[XER_OV] << XER_OV) |
@@ -933,25 +933,38 @@
         (cpu_single_env->xer[XER_BC] << XER_BC);
 }
 
-uint32_t cpu_ppc_load_decr (CPUState *env);
-static int monitor_get_decr (struct MonitorDef *md)
+static int monitor_get_decr (struct MonitorDef *md, int val)
 {
     return cpu_ppc_load_decr(cpu_single_env);
 }
 
-uint32_t cpu_ppc_load_tbu (CPUState *env);
-static int monitor_get_tbu (struct MonitorDef *md)
+static int monitor_get_tbu (struct MonitorDef *md, int val)
 {
     return cpu_ppc_load_tbu(cpu_single_env);
 }
 
-uint32_t cpu_ppc_load_tbl (CPUState *env);
-static int monitor_get_tbl (struct MonitorDef *md)
+static int monitor_get_tbl (struct MonitorDef *md, int val)
 {
     return cpu_ppc_load_tbl(cpu_single_env);
 }
 #endif
 
+#if defined(TARGET_SPARC)
+static int monitor_get_psr (struct MonitorDef *md, int val)
+{
+    return (0<<28) | (4<<24) | cpu_single_env->psr	\
+	| (cpu_single_env->psrs? PSR_S : 0)		\
+	| (cpu_single_env->psrs? PSR_PS : 0)		\
+	| (cpu_single_env->psret? PSR_ET : 0)		\
+	| cpu_single_env->cwp;
+}
+
+static int monitor_get_reg(struct MonitorDef *md, int val)
+{
+    return cpu_single_env->regwptr[val];
+}
+#endif
+
 static MonitorDef monitor_defs[] = {
 #ifdef TARGET_I386
 
@@ -1037,6 +1050,78 @@
     { "sr14", offsetof(CPUState, sr[14]) },
     { "sr15", offsetof(CPUState, sr[15]) },
     /* Too lazy to put BATs and SPRs ... */
+#elif defined(TARGET_SPARC)
+    { "g0", offsetof(CPUState, gregs[0]) },
+    { "g1", offsetof(CPUState, gregs[1]) },
+    { "g2", offsetof(CPUState, gregs[2]) },
+    { "g3", offsetof(CPUState, gregs[3]) },
+    { "g4", offsetof(CPUState, gregs[4]) },
+    { "g5", offsetof(CPUState, gregs[5]) },
+    { "g6", offsetof(CPUState, gregs[6]) },
+    { "g7", offsetof(CPUState, gregs[7]) },
+    { "o0", 0, monitor_get_reg },
+    { "o1", 1, monitor_get_reg },
+    { "o2", 2, monitor_get_reg },
+    { "o3", 3, monitor_get_reg },
+    { "o4", 4, monitor_get_reg },
+    { "o5", 5, monitor_get_reg },
+    { "o6", 6, monitor_get_reg },
+    { "o7", 7, monitor_get_reg },
+    { "l0", 8, monitor_get_reg },
+    { "l1", 9, monitor_get_reg },
+    { "l2", 10, monitor_get_reg },
+    { "l3", 11, monitor_get_reg },
+    { "l4", 12, monitor_get_reg },
+    { "l5", 13, monitor_get_reg },
+    { "l6", 14, monitor_get_reg },
+    { "l7", 15, monitor_get_reg },
+    { "i0", 16, monitor_get_reg },
+    { "i1", 17, monitor_get_reg },
+    { "i2", 18, monitor_get_reg },
+    { "i3", 19, monitor_get_reg },
+    { "i4", 20, monitor_get_reg },
+    { "i5", 21, monitor_get_reg },
+    { "i6", 22, monitor_get_reg },
+    { "i7", 23, monitor_get_reg },
+    { "pc", offsetof(CPUState, pc) },
+    { "npc", offsetof(CPUState, npc) },
+    { "y", offsetof(CPUState, y) },
+    { "psr", 0, &monitor_get_psr, },
+    { "wim", offsetof(CPUState, wim) },
+    { "tbr", offsetof(CPUState, tbr) },
+    { "fsr", offsetof(CPUState, fsr) },
+    { "f0", offsetof(CPUState, fpr[0]) },
+    { "f1", offsetof(CPUState, fpr[1]) },
+    { "f2", offsetof(CPUState, fpr[2]) },
+    { "f3", offsetof(CPUState, fpr[3]) },
+    { "f4", offsetof(CPUState, fpr[4]) },
+    { "f5", offsetof(CPUState, fpr[5]) },
+    { "f6", offsetof(CPUState, fpr[6]) },
+    { "f7", offsetof(CPUState, fpr[7]) },
+    { "f8", offsetof(CPUState, fpr[8]) },
+    { "f9", offsetof(CPUState, fpr[9]) },
+    { "f10", offsetof(CPUState, fpr[10]) },
+    { "f11", offsetof(CPUState, fpr[11]) },
+    { "f12", offsetof(CPUState, fpr[12]) },
+    { "f13", offsetof(CPUState, fpr[13]) },
+    { "f14", offsetof(CPUState, fpr[14]) },
+    { "f15", offsetof(CPUState, fpr[15]) },
+    { "f16", offsetof(CPUState, fpr[16]) },
+    { "f17", offsetof(CPUState, fpr[17]) },
+    { "f18", offsetof(CPUState, fpr[18]) },
+    { "f19", offsetof(CPUState, fpr[19]) },
+    { "f20", offsetof(CPUState, fpr[20]) },
+    { "f21", offsetof(CPUState, fpr[21]) },
+    { "f22", offsetof(CPUState, fpr[22]) },
+    { "f23", offsetof(CPUState, fpr[23]) },
+    { "f24", offsetof(CPUState, fpr[24]) },
+    { "f25", offsetof(CPUState, fpr[25]) },
+    { "f26", offsetof(CPUState, fpr[26]) },
+    { "f27", offsetof(CPUState, fpr[27]) },
+    { "f28", offsetof(CPUState, fpr[28]) },
+    { "f29", offsetof(CPUState, fpr[29]) },
+    { "f30", offsetof(CPUState, fpr[30]) },
+    { "f31", offsetof(CPUState, fpr[31]) },
 #endif
     { NULL },
 };
@@ -1054,7 +1139,7 @@
     for(md = monitor_defs; md->name != NULL; md++) {
         if (compare_cmd(name, md->name)) {
             if (md->get_value) {
-                *pval = md->get_value(md);
+                *pval = md->get_value(md, md->offset);
             } else {
                 *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset);
             }
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 8ae68af..3924c10 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -178,7 +178,8 @@
     rbp->bp_hlen = 6;
     memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
 
-    rbp->bp_yiaddr = daddr.sin_addr; /* IP address */
+    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
 
     q = rbp->bp_vend;
     memcpy(q, rfc1533_cookie, 4);
diff --git a/softmmu_header.h b/softmmu_header.h
index 0bbc368..074d090 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -55,6 +55,8 @@
 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
 #elif defined (TARGET_PPC)
 #define CPU_MEM_INDEX (msr_pr)
+#elif defined (TARGET_SPARC)
+#define CPU_MEM_INDEX ((env->psrs) == 0)
 #endif
 #define MMUSUFFIX _mmu
 
@@ -64,6 +66,8 @@
 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
 #elif defined (TARGET_PPC)
 #define CPU_MEM_INDEX (msr_pr)
+#elif defined (TARGET_SPARC)
+#define CPU_MEM_INDEX ((env->psrs) == 0)
 #endif
 #define MMUSUFFIX _cmmu
 
diff --git a/translate-all.c b/translate-all.c
index be3039c..1fbed41 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -46,6 +46,8 @@
 uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
 #if defined(TARGET_I386)
 uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
+#elif defined(TARGET_SPARC)
+uint32_t gen_opc_npc[OPC_BUF_SIZE];
 #endif
 
 int code_copy_enabled = 1;
@@ -208,6 +210,7 @@
 #elif defined(TARGET_SPARC)
     /* XXX: restore npc too */
     env->pc = gen_opc_pc[j];
+    env->npc = gen_opc_npc[j];
 #elif defined(TARGET_PPC)
     {
         int type;
diff --git a/vl.c b/vl.c
index 02edc7d..22b1412 100644
--- a/vl.c
+++ b/vl.c
@@ -710,7 +710,7 @@
     
     for(;;) {
         ts = *ptimer_head;
-        if (ts->expire_time > current_time)
+        if (!ts || ts->expire_time > current_time)
             break;
         /* remove timer from the list before calling the callback */
         *ptimer_head = ts->next;
@@ -2166,6 +2166,15 @@
 {
     return 0;
 }
+#elif defined(TARGET_SPARC)
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
 #else
 
 #warning No CPU save/restore functions
@@ -3336,6 +3345,10 @@
     ppc_init(ram_size, vga_ram_size, boot_device,
 	     ds, fd_filename, snapshot,
 	     kernel_filename, kernel_cmdline, initrd_filename);
+#elif defined(TARGET_SPARC)
+    sun4m_init(ram_size, vga_ram_size, boot_device,
+            ds, fd_filename, snapshot,
+            kernel_filename, kernel_cmdline, initrd_filename);
 #endif
 
     gui_timer = qemu_new_timer(rt_clock, gui_update, NULL);
diff --git a/vl.h b/vl.h
index 4cfe9c0..8151613 100644
--- a/vl.h
+++ b/vl.h
@@ -664,6 +664,28 @@
 extern CPUReadMemoryFunc *PPC_io_read[];
 extern int prep_enabled;
 
+/* sun4m.c */
+void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
+             DisplayState *ds, const char **fd_filename, int snapshot,
+             const char *kernel_filename, const char *kernel_cmdline,
+             const char *initrd_filename);
+
+/* iommu.c */
+void iommu_init();
+uint32_t iommu_translate(uint32_t addr);
+
+/* lance.c */
+void lance_init(NetDriverState *nd, int irq);
+
+/* tcx.c */
+void tcx_init(DisplayState *ds);
+
+/* sched.c */
+void sched_init();
+
+/* magic-load.c */
+void magic_init(const char *kfn, int kloadaddr);
+
 /* NVRAM helpers */
 #include "hw/m48t59.h"