r3778 - in trunk/src/host/qemu-neo1973: . fpu hw linux-user pc-bios target-mips target-sparc

andrew at sita.openmoko.org andrew at sita.openmoko.org
Mon Jan 7 08:18:02 CET 2008


Author: andrew
Date: 2008-01-07 08:17:44 +0100 (Mon, 07 Jan 2008)
New Revision: 3778

Added:
   trunk/src/host/qemu-neo1973/hw/sbi.c
   trunk/src/host/qemu-neo1973/hw/sun4c_intctl.c
Modified:
   trunk/src/host/qemu-neo1973/Changelog
   trunk/src/host/qemu-neo1973/Makefile
   trunk/src/host/qemu-neo1973/Makefile.target
   trunk/src/host/qemu-neo1973/VERSION
   trunk/src/host/qemu-neo1973/block-raw-posix.c
   trunk/src/host/qemu-neo1973/configure
   trunk/src/host/qemu-neo1973/cpu-all.h
   trunk/src/host/qemu-neo1973/disas.c
   trunk/src/host/qemu-neo1973/dyngen-exec.h
   trunk/src/host/qemu-neo1973/exec.c
   trunk/src/host/qemu-neo1973/fpu/softfloat-specialize.h
   trunk/src/host/qemu-neo1973/hw/boards.h
   trunk/src/host/qemu-neo1973/hw/eccmemctl.c
   trunk/src/host/qemu-neo1973/hw/esp.c
   trunk/src/host/qemu-neo1973/hw/fdc.c
   trunk/src/host/qemu-neo1973/hw/iommu.c
   trunk/src/host/qemu-neo1973/hw/m48t59.c
   trunk/src/host/qemu-neo1973/hw/mainstone.c
   trunk/src/host/qemu-neo1973/hw/mips_malta.c
   trunk/src/host/qemu-neo1973/hw/pcnet.c
   trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c
   trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
   trunk/src/host/qemu-neo1973/hw/slavio_misc.c
   trunk/src/host/qemu-neo1973/hw/slavio_serial.c
   trunk/src/host/qemu-neo1973/hw/slavio_timer.c
   trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
   trunk/src/host/qemu-neo1973/hw/sun4m.c
   trunk/src/host/qemu-neo1973/hw/sun4m.h
   trunk/src/host/qemu-neo1973/hw/tcx.c
   trunk/src/host/qemu-neo1973/linux-user/main.c
   trunk/src/host/qemu-neo1973/pc-bios/README
   trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
   trunk/src/host/qemu-neo1973/qemu-doc.texi
   trunk/src/host/qemu-neo1973/qemu-img.c
   trunk/src/host/qemu-neo1973/target-mips/cpu.h
   trunk/src/host/qemu-neo1973/target-mips/exec.h
   trunk/src/host/qemu-neo1973/target-mips/helper.c
   trunk/src/host/qemu-neo1973/target-mips/mips-defs.h
   trunk/src/host/qemu-neo1973/target-mips/op.c
   trunk/src/host/qemu-neo1973/target-mips/op_helper.c
   trunk/src/host/qemu-neo1973/target-mips/translate.c
   trunk/src/host/qemu-neo1973/target-mips/translate_init.c
   trunk/src/host/qemu-neo1973/target-sparc/helper.c
   trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
   trunk/src/host/qemu-neo1973/vl.c
Log:
Update tree to qemu-0.9.1.


Modified: trunk/src/host/qemu-neo1973/Changelog
===================================================================
--- trunk/src/host/qemu-neo1973/Changelog	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/Changelog	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1,3 +1,5 @@
+version 0.9.1:
+
   - TFTP booting from host directory (Anthony Liguori, Erwan Velu)
   - Tap device emulation for Solaris (Sittichai Palanisong)
   - Monitor multiplexing to several I/O channels (Jason Wessel)
@@ -18,6 +20,9 @@
   - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
   - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
   - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
+  - Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
+  - Intel mainstone II board emulation (Armin Kuster)
+  - VMware SVGA II graphics card support (Andrzej Zaborowski)
 
 version 0.9.0:
 

Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/Makefile	2008-01-07 07:17:44 UTC (rev 3778)
@@ -273,22 +273,24 @@
 	$(bindir)/qemu-system-m68k \
 	$(bindir)/qemu-system-sh4 \
 	$(bindir)/qemu-system-sh4eb \
+	$(bindir)/qemu-system-cris \
 	$(bindir)/qemu-i386 \
+	$(bindir)/qemu-x86_64 \
         $(bindir)/qemu-arm \
         $(bindir)/qemu-armeb \
         $(bindir)/qemu-sparc \
+        $(bindir)/qemu-sparc32plus \
+        $(bindir)/qemu-sparc64 \
         $(bindir)/qemu-ppc \
         $(bindir)/qemu-ppc64 \
+        $(bindir)/qemu-ppc64abi32 \
         $(bindir)/qemu-mips \
         $(bindir)/qemu-mipsel \
-        $(bindir)/qemu-mipsn32 \
-        $(bindir)/qemu-mipsn32el \
-        $(bindir)/qemu-mips64 \
-        $(bindir)/qemu-mips64el \
         $(bindir)/qemu-alpha \
         $(bindir)/qemu-m68k \
         $(bindir)/qemu-sh4 \
         $(bindir)/qemu-sh4eb \
+        $(bindir)/qemu-cris \
         $(bindir)/qemu-img \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \

Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/Makefile.target	2008-01-07 07:17:44 UTC (rev 3778)
@@ -43,7 +43,9 @@
 HELPER_CFLAGS=$(CFLAGS)
 DYNGEN=../dyngen$(EXESUF)
 # user emulator name
+ifndef TARGET_ARCH2
 TARGET_ARCH2=$(TARGET_ARCH)
+endif
 ifeq ($(TARGET_ARCH),arm)
   ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
     TARGET_ARCH2=armeb
@@ -69,11 +71,6 @@
     TARGET_ARCH2=mips64el
   endif
 endif
-ifeq ($(TARGET_ARCH),sparc64)
-  ifeq ($(TARGET_ABI_DIR),sparc)
-    TARGET_ARCH2=sparc32plus
-  endif
-endif
 QEMU_USER=qemu-$(TARGET_ARCH2)
 # system emulator name
 ifdef CONFIG_SOFTMMU
@@ -478,6 +475,7 @@
 VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
 VL_OBJS+= piix_pci.o parallel.o cirrus_vga.o $(SOUND_HW)
 VL_OBJS+= mipsnet.o
+VL_OBJS+= pflash_cfi01.o
 CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), cris)
@@ -494,7 +492,7 @@
 else
 VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
 VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
-VL_OBJS+= cs4231.o ptimer.o eccmemctl.o
+VL_OBJS+= cs4231.o ptimer.o eccmemctl.o sbi.o sun4c_intctl.o
 endif
 endif
 ifeq ($(TARGET_BASE_ARCH), arm)

Modified: trunk/src/host/qemu-neo1973/VERSION
===================================================================
--- trunk/src/host/qemu-neo1973/VERSION	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/VERSION	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1 +1 @@
-0.9.0-openmoko-svn
+0.9.1-openmoko-svn

Modified: trunk/src/host/qemu-neo1973/block-raw-posix.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-raw-posix.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/block-raw-posix.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -276,8 +276,8 @@
            seems to fix the problem. */
         struct aioinit ai;
         memset(&ai, 0, sizeof(ai));
-        ai.aio_threads = 16;
-        ai.aio_num = 16;
+        ai.aio_threads = 1;
+        ai.aio_num = 1;
         ai.aio_idle_time = 365 * 100000;
         aio_init(&ai);
     }

Modified: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/configure	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1133,6 +1133,7 @@
 elif test "$target_cpu" = "sparc32plus" ; then
   echo "TARGET_ARCH=sparc64" >> $config_mak
   echo "TARGET_ABI_DIR=sparc" >> $config_mak
+  echo "TARGET_ARCH2=sparc32plus" >> $config_mak
   echo "#define TARGET_ARCH \"sparc64\"" >> $config_h
   echo "#define TARGET_SPARC 1" >> $config_h
   echo "#define TARGET_SPARC64 1" >> $config_h
@@ -1156,6 +1157,7 @@
 elif test "$target_cpu" = "ppc64abi32" ; then
   echo "TARGET_ARCH=ppc64" >> $config_mak
   echo "TARGET_ABI_DIR=ppc" >> $config_mak
+  echo "TARGET_ARCH2=ppc64abi32" >> $config_mak
   echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
   echo "#define TARGET_PPC 1" >> $config_h
   echo "#define TARGET_PPC64 1" >> $config_h

Modified: trunk/src/host/qemu-neo1973/cpu-all.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-all.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/cpu-all.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -821,6 +821,7 @@
    the physical address */
 #define IO_MEM_ROMD        (1)
 #define IO_MEM_SUBPAGE     (2)
+#define IO_MEM_SUBWIDTH    (4)
 
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);

Modified: trunk/src/host/qemu-neo1973/disas.c
===================================================================
--- trunk/src/host/qemu-neo1973/disas.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/disas.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -392,6 +392,8 @@
     print_insn = print_insn_i386;
 #elif defined(TARGET_ARM)
     print_insn = print_insn_arm;
+#elif defined(TARGET_ALPHA)
+    print_insn = print_insn_alpha;
 #elif defined(TARGET_SPARC)
     print_insn = print_insn_sparc;
 #ifdef TARGET_SPARC64

Modified: trunk/src/host/qemu-neo1973/dyngen-exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen-exec.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/dyngen-exec.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -38,7 +38,7 @@
 // Linux/Sparc64 defines uint64_t
 #if !(defined (__sparc_v9__) && defined(__linux__))
 /* XXX may be done for all 64 bits targets ? */
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__)
+#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) 
 typedef unsigned long uint64_t;
 #else
 typedef unsigned long long uint64_t;
@@ -55,7 +55,7 @@
 typedef signed int int32_t;
 // Linux/Sparc64 defines int64_t
 #if !(defined (__sparc_v9__) && defined(__linux__))
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__)
+#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__)
 typedef signed long int64_t;
 #else
 typedef signed long long int64_t;

Modified: trunk/src/host/qemu-neo1973/exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/exec.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/exec.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -163,9 +163,9 @@
 #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
 typedef struct subpage_t {
     target_phys_addr_t base;
-    CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE];
-    CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE];
-    void *opaque[TARGET_PAGE_SIZE];
+    CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
+    CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
+    void *opaque[TARGET_PAGE_SIZE][2][4];
 } subpage_t;
 
 static void page_init(void)
@@ -2025,7 +2025,7 @@
 
             CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
                           need_subpage);
-            if (need_subpage) {
+            if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                 if (!(orig_memory & IO_MEM_SUBPAGE)) {
                     subpage = subpage_init((addr & TARGET_PAGE_MASK),
                                            &p->phys_offset, orig_memory);
@@ -2053,7 +2053,7 @@
                 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
                               end_addr2, need_subpage);
 
-                if (need_subpage) {
+                if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                     subpage = subpage_init((addr & TARGET_PAGE_MASK),
                                            &p->phys_offset, IO_MEM_UNASSIGNED);
                     subpage_register(subpage, start_addr2, end_addr2,
@@ -2308,7 +2308,6 @@
 static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
                                  unsigned int len)
 {
-    CPUReadMemoryFunc **mem_read;
     uint32_t ret;
     unsigned int idx;
 
@@ -2317,8 +2316,7 @@
     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
            mmio, len, addr, idx);
 #endif
-    mem_read = mmio->mem_read[idx];
-    ret = (*mem_read[len])(mmio->opaque[idx], addr);
+    ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
 
     return ret;
 }
@@ -2326,7 +2324,6 @@
 static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
                               uint32_t value, unsigned int len)
 {
-    CPUWriteMemoryFunc **mem_write;
     unsigned int idx;
 
     idx = SUBPAGE_IDX(addr - mmio->base);
@@ -2334,8 +2331,7 @@
     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
            mmio, len, addr, idx, value);
 #endif
-    mem_write = mmio->mem_write[idx];
-    (*mem_write[len])(mmio->opaque[idx], addr, value);
+    (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
 }
 
 static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
@@ -2408,6 +2404,7 @@
                              int memory)
 {
     int idx, eidx;
+    unsigned int i;
 
     if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
         return -1;
@@ -2419,9 +2416,16 @@
 #endif
     memory >>= IO_MEM_SHIFT;
     for (; idx <= eidx; idx++) {
-        mmio->mem_read[idx] = io_mem_read[memory];
-        mmio->mem_write[idx] = io_mem_write[memory];
-        mmio->opaque[idx] = io_mem_opaque[memory];
+        for (i = 0; i < 4; i++) {
+            if (io_mem_read[memory][i]) {
+                mmio->mem_read[idx][i] = &io_mem_read[memory][i];
+                mmio->opaque[idx][0][i] = io_mem_opaque[memory];
+            }
+            if (io_mem_write[memory][i]) {
+                mmio->mem_write[idx][i] = &io_mem_write[memory][i];
+                mmio->opaque[idx][1][i] = io_mem_opaque[memory];
+            }
+        }
     }
 
     return 0;
@@ -2466,16 +2470,18 @@
 
 /* mem_read and mem_write are arrays of functions containing the
    function to access byte (index 0), word (index 1) and dword (index
-   2). All functions must be supplied. If io_index is non zero, the
-   corresponding io zone is modified. If it is zero, a new io zone is
-   allocated. The return value can be used with
-   cpu_register_physical_memory(). (-1) is returned if error. */
+   2). Functions can be omitted with a NULL function pointer. The
+   registered functions may be modified dynamically later.
+   If io_index is non zero, the corresponding io zone is
+   modified. If it is zero, a new io zone is allocated. The return
+   value can be used with cpu_register_physical_memory(). (-1) is
+   returned if error. */
 int cpu_register_io_memory(int io_index,
                            CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,
                            void *opaque)
 {
-    int i;
+    int i, subwidth = 0;
 
     if (io_index <= 0) {
         if (io_mem_nb >= IO_MEM_NB_ENTRIES)
@@ -2487,11 +2493,13 @@
     }
 
     for(i = 0;i < 3; i++) {
+        if (!mem_read[i] || !mem_write[i])
+            subwidth = IO_MEM_SUBWIDTH;
         io_mem_read[io_index][i] = mem_read[i];
         io_mem_write[io_index][i] = mem_write[i];
     }
     io_mem_opaque[io_index] = opaque;
-    return io_index << IO_MEM_SHIFT;
+    return (io_index << IO_MEM_SHIFT) | subwidth;
 }
 
 CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)

Modified: trunk/src/host/qemu-neo1973/fpu/softfloat-specialize.h
===================================================================
--- trunk/src/host/qemu-neo1973/fpu/softfloat-specialize.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/fpu/softfloat-specialize.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -65,7 +65,13 @@
 /*----------------------------------------------------------------------------
 | The pattern for a default generated single-precision NaN.
 *----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
+#if defined(TARGET_SPARC)
+#define float32_default_nan make_float32(0x7FFFFFFF)
+#elif defined(TARGET_POWERPC)
+#define float32_default_nan make_float32(0x7FC00000)
+#elif defined(TARGET_HPPA)
+#define float32_default_nan make_float32(0x7FA00000)
+#elif SNAN_BIT_IS_ONE
 #define float32_default_nan make_float32(0x7FBFFFFF)
 #else
 #define float32_default_nan make_float32(0xFFC00000)
@@ -125,8 +131,12 @@
 
 static float32 commonNaNToFloat32( commonNaNT a )
 {
-    return make_float32(
-        ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ) );
+    bits32 mantissa = a.high>>41;
+    if ( mantissa )
+        return make_float32(
+            ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
+    else
+        return float32_default_nan;
 }
 
 /*----------------------------------------------------------------------------
@@ -180,7 +190,13 @@
 /*----------------------------------------------------------------------------
 | The pattern for a default generated double-precision NaN.
 *----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
+#if defined(TARGET_SPARC)
+#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
+#elif defined(TARGET_POWERPC)
+#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
+#elif defined(TARGET_HPPA)
+#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
+#elif SNAN_BIT_IS_ONE
 #define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
 #else
 #define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
@@ -244,10 +260,15 @@
 
 static float64 commonNaNToFloat64( commonNaNT a )
 {
-    return make_float64(
-          ( ( (bits64) a.sign )<<63 )
-        | LIT64( 0x7FF8000000000000 )
-        | ( a.high>>12 ));
+    bits64 mantissa = a.high>>12;
+
+    if ( mantissa )
+        return make_float64(
+              ( ( (bits64) a.sign )<<63 )
+            | LIT64( 0x7FF0000000000000 )
+            | ( a.high>>12 ));
+    else
+        return float64_default_nan;
 }
 
 /*----------------------------------------------------------------------------
@@ -366,7 +387,7 @@
     if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
     z.sign = a.high>>15;
     z.low = 0;
-    z.high = a.low<<1;
+    z.high = a.low;
     return z;
 }
 
@@ -379,7 +400,10 @@
 {
     floatx80 z;
 
-    z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+    if (a.high)
+        z.low = a.high;
+    else
+        z.low = floatx80_default_nan_low;
     z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
     return z;
 }
@@ -500,7 +524,7 @@
     float128 z;
 
     shift128Right( a.high, a.low, 16, &z.high, &z.low );
-    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
     return z;
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/boards.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/boards.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/boards.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -53,6 +53,8 @@
 
 /* sun4m.c */
 extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine, ss20_machine;
+extern QEMUMachine ss2_machine;
+extern QEMUMachine ss1000_machine, ss2000_machine;
 
 /* sun4u.c */
 extern QEMUMachine sun4u_machine;

Modified: trunk/src/host/qemu-neo1973/hw/eccmemctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/eccmemctl.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/eccmemctl.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -93,30 +93,6 @@
     uint32_t regs[ECC_NREGS];
 } ECCState;
 
-static void ecc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %02x\n",
-           addr, val & 0xff);
-}
-
-static uint32_t ecc_mem_readb(void *opaque, target_phys_addr_t addr)
-{
-    printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 00\n", addr);
-    return 0;
-}
-
-static void ecc_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %04x\n",
-           addr, val & 0xffff);
-}
-
-static uint32_t ecc_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 0000\n", addr);
-    return 0;
-}
-
 static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     ECCState *s = opaque;
@@ -201,14 +177,14 @@
 }
 
 static CPUReadMemoryFunc *ecc_mem_read[3] = {
-    ecc_mem_readb,
-    ecc_mem_readw,
+    NULL,
+    NULL,
     ecc_mem_readl,
 };
 
 static CPUWriteMemoryFunc *ecc_mem_write[3] = {
-    ecc_mem_writeb,
-    ecc_mem_writew,
+    NULL,
+    NULL,
     ecc_mem_writel,
 };
 

Modified: trunk/src/host/qemu-neo1973/hw/esp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/esp.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/esp.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -543,14 +543,14 @@
 
 static CPUReadMemoryFunc *esp_mem_read[3] = {
     esp_mem_readb,
-    esp_mem_readb,
-    esp_mem_readb,
+    NULL,
+    NULL,
 };
 
 static CPUWriteMemoryFunc *esp_mem_write[3] = {
     esp_mem_writeb,
-    esp_mem_writeb,
-    esp_mem_writeb,
+    NULL,
+    NULL,
 };
 
 static void esp_save(QEMUFile *f, void *opaque)

Modified: trunk/src/host/qemu-neo1973/hw/fdc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/fdc.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/fdc.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -493,6 +493,18 @@
     fdctrl_write_mem,
 };
 
+static CPUReadMemoryFunc *fdctrl_mem_read_strict[3] = {
+    fdctrl_read_mem,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc *fdctrl_mem_write_strict[3] = {
+    fdctrl_write_mem,
+    NULL,
+    NULL,
+};
+
 static void fd_save (QEMUFile *f, fdrive_t *fd)
 {
     uint8_t tmp;
@@ -586,12 +598,11 @@
     fdctrl_reset(s, 0);
 }
 
-fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
-                       target_phys_addr_t io_base,
-                       BlockDriverState **fds)
+static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann,
+                                     target_phys_addr_t io_base,
+                                     BlockDriverState **fds)
 {
     fdctrl_t *fdctrl;
-    int io_mem;
     int i;
 
     FLOPPY_DPRINTF("init controller\n");
@@ -611,7 +622,6 @@
     fdctrl->dma_chann = dma_chann;
     fdctrl->io_base = io_base;
     fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
-    fdctrl->sun4m = 0;
     if (fdctrl->dma_chann != -1) {
         fdctrl->dma_en = 1;
         DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
@@ -623,6 +633,25 @@
     }
     fdctrl_reset(fdctrl, 0);
     fdctrl->state = FD_CTRL_ACTIVE;
+    register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
+    qemu_register_reset(fdctrl_external_reset, fdctrl);
+    for (i = 0; i < 2; i++) {
+        fd_revalidate(&fdctrl->drives[i]);
+    }
+
+    return fdctrl;
+}
+
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
+                       target_phys_addr_t io_base,
+                       BlockDriverState **fds)
+{
+    fdctrl_t *fdctrl;
+    int io_mem;
+
+    fdctrl = fdctrl_init_common(irq, dma_chann, io_base, fds);
+
+    fdctrl->sun4m = 0;
     if (mem_mapped) {
         io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write,
                                         fdctrl);
@@ -637,11 +666,6 @@
         register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
                               fdctrl);
     }
-    register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
-    qemu_register_reset(fdctrl_external_reset, fdctrl);
-    for (i = 0; i < 2; i++) {
-        fd_revalidate(&fdctrl->drives[i]);
-    }
 
     return fdctrl;
 }
@@ -650,9 +674,14 @@
                              BlockDriverState **fds)
 {
     fdctrl_t *fdctrl;
+    int io_mem;
 
-    fdctrl = fdctrl_init(irq, 0, 1, io_base, fds);
+    fdctrl = fdctrl_init_common(irq, 0, io_base, fds);
     fdctrl->sun4m = 1;
+    io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict,
+                                    fdctrl_mem_write_strict,
+                                    fdctrl);
+    cpu_register_physical_memory(io_base, 0x08, io_mem);
 
     return fdctrl;
 }

Modified: trunk/src/host/qemu-neo1973/hw/iommu.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/iommu.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/iommu.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -112,24 +112,31 @@
     uint32_t regs[IOMMU_NREGS];
     target_phys_addr_t iostart;
     uint32_t version;
+    qemu_irq irq;
 } IOMMUState;
 
-static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
+static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     IOMMUState *s = opaque;
     target_phys_addr_t saddr;
+    uint32_t ret;
 
     saddr = (addr - s->addr) >> 2;
     switch (saddr) {
     default:
-        DPRINTF("read reg[%d] = %x\n", (int)saddr, s->regs[saddr]);
-        return s->regs[saddr];
+        ret = s->regs[saddr];
         break;
+    case IOMMU_AFAR:
+    case IOMMU_AFSR:
+        ret = s->regs[saddr];
+        qemu_irq_lower(s->irq);
+        break;
     }
-    return 0;
+    DPRINTF("read reg[%d] = %x\n", (int)saddr, ret);
+    return ret;
 }
 
-static void iommu_mem_writew(void *opaque, target_phys_addr_t addr,
+static void iommu_mem_writel(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
     IOMMUState *s = opaque;
@@ -180,8 +187,13 @@
         DPRINTF("page flush %x\n", val);
         s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
         break;
+    case IOMMU_AFAR:
+        s->regs[saddr] = val;
+        qemu_irq_lower(s->irq);
+        break;
     case IOMMU_AFSR:
         s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
+        qemu_irq_lower(s->irq);
         break;
     case IOMMU_SBCFG0:
     case IOMMU_SBCFG1:
@@ -201,15 +213,15 @@
 }
 
 static CPUReadMemoryFunc *iommu_mem_read[3] = {
-    iommu_mem_readw,
-    iommu_mem_readw,
-    iommu_mem_readw,
+    NULL,
+    NULL,
+    iommu_mem_readl,
 };
 
 static CPUWriteMemoryFunc *iommu_mem_write[3] = {
-    iommu_mem_writew,
-    iommu_mem_writew,
-    iommu_mem_writew,
+    NULL,
+    NULL,
+    iommu_mem_writel,
 };
 
 static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr)
@@ -255,6 +267,7 @@
     if (!is_write)
         s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
     s->regs[IOMMU_AFAR] = addr;
+    qemu_irq_raise(s->irq);
 }
 
 void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
@@ -324,9 +337,10 @@
     s->regs[IOMMU_CTRL] = s->version;
     s->regs[IOMMU_ARBEN] = IOMMU_MID;
     s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
+    qemu_irq_lower(s->irq);
 }
 
-void *iommu_init(target_phys_addr_t addr, uint32_t version)
+void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq)
 {
     IOMMUState *s;
     int iommu_io_memory;
@@ -337,6 +351,7 @@
 
     s->addr = addr;
     s->version = version;
+    s->irq = irq;
 
     iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read,
                                              iommu_mem_write, s);

Modified: trunk/src/host/qemu-neo1973/hw/m48t59.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/m48t59.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/m48t59.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -36,13 +36,13 @@
 #endif
 
 /*
- * The M48T08 and M48T59 chips are very similar. The newer '59 has
+ * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
  * alarm and a watchdog timer and related control registers. In the
  * PPC platform there is also a nvram lock function.
  */
 struct m48t59_t {
     /* Model parameters */
-    int type; // 8 = m48t08, 59 = m48t59
+    int type; // 2 = m48t02, 8 = m48t08, 59 = m48t59
     /* Hardware parameters */
     qemu_irq IRQ;
     int mem_index;
@@ -210,9 +210,14 @@
 
     if (addr > 0x1FF8 && addr < 0x2000)
 	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
-    if (NVRAM->type == 8 &&
-        (addr >= 0x1ff0 && addr <= 0x1ff7))
+
+    /* check for NVRAM access */
+    if ((NVRAM->type == 2 && addr < 0x7f8) ||
+        (NVRAM->type == 8 && addr < 0x1ff8) ||
+        (NVRAM->type == 59 && addr < 0x1ff0))
         goto do_write;
+
+    /* TOD access */
     switch (addr) {
     case 0x1FF0:
         /* flags register : read-only */
@@ -270,10 +275,12 @@
         set_up_watchdog(NVRAM, val);
         break;
     case 0x1FF8:
+    case 0x07F8:
         /* control */
-	NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
+       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
         break;
     case 0x1FF9:
+    case 0x07F9:
         /* seconds (BCD) */
 	tmp = fromBCD(val & 0x7F);
 	if (tmp >= 0 && tmp <= 59) {
@@ -281,7 +288,7 @@
 	    tm.tm_sec = tmp;
 	    set_time(NVRAM, &tm);
 	}
-	if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
+       if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
 	    if (val & 0x80) {
 		NVRAM->stop_time = time(NULL);
 	    } else {
@@ -289,9 +296,10 @@
 		NVRAM->stop_time = 0;
 	    }
 	}
-	NVRAM->buffer[0x1FF9] = val & 0x80;
+       NVRAM->buffer[addr] = val & 0x80;
         break;
     case 0x1FFA:
+    case 0x07FA:
         /* minutes (BCD) */
 	tmp = fromBCD(val & 0x7F);
 	if (tmp >= 0 && tmp <= 59) {
@@ -301,6 +309,7 @@
 	}
         break;
     case 0x1FFB:
+    case 0x07FB:
         /* hours (BCD) */
 	tmp = fromBCD(val & 0x3F);
 	if (tmp >= 0 && tmp <= 23) {
@@ -310,14 +319,16 @@
 	}
         break;
     case 0x1FFC:
+    case 0x07FC:
         /* day of the week / century */
 	tmp = fromBCD(val & 0x07);
 	get_time(NVRAM, &tm);
 	tm.tm_wday = tmp;
 	set_time(NVRAM, &tm);
-        NVRAM->buffer[0x1FFC] = val & 0x40;
+        NVRAM->buffer[addr] = val & 0x40;
         break;
     case 0x1FFD:
+    case 0x07FD:
         /* date */
 	tmp = fromBCD(val & 0x1F);
 	if (tmp != 0) {
@@ -327,6 +338,7 @@
 	}
         break;
     case 0x1FFE:
+    case 0x07FE:
         /* month */
 	tmp = fromBCD(val & 0x1F);
 	if (tmp >= 1 && tmp <= 12) {
@@ -336,6 +348,7 @@
 	}
         break;
     case 0x1FFF:
+    case 0x07FF:
         /* year */
 	tmp = fromBCD(val);
 	if (tmp >= 0 && tmp <= 99) {
@@ -367,9 +380,13 @@
     struct tm tm;
     uint32_t retval = 0xFF;
 
-    if (NVRAM->type == 8 &&
-        (addr >= 0x1ff0 && addr <= 0x1ff7))
+    /* check for NVRAM access */
+    if ((NVRAM->type == 2 && addr < 0x078f) ||
+        (NVRAM->type == 8 && addr < 0x1ff8) ||
+        (NVRAM->type == 59 && addr < 0x1ff0))
         goto do_read;
+
+    /* TOD access */
     switch (addr) {
     case 0x1FF0:
         /* flags register */
@@ -398,39 +415,47 @@
 	set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
 	goto do_read;
     case 0x1FF8:
+    case 0x07F8:
         /* control */
 	goto do_read;
     case 0x1FF9:
+    case 0x07F9:
         /* seconds (BCD) */
         get_time(NVRAM, &tm);
-        retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
+        retval = (NVRAM->buffer[addr] & 0x80) | toBCD(tm.tm_sec);
         break;
     case 0x1FFA:
+    case 0x07FA:
         /* minutes (BCD) */
         get_time(NVRAM, &tm);
         retval = toBCD(tm.tm_min);
         break;
     case 0x1FFB:
+    case 0x07FB:
         /* hours (BCD) */
         get_time(NVRAM, &tm);
         retval = toBCD(tm.tm_hour);
         break;
     case 0x1FFC:
+    case 0x07FC:
         /* day of the week / century */
         get_time(NVRAM, &tm);
-        retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
+        retval = NVRAM->buffer[addr] | tm.tm_wday;
         break;
     case 0x1FFD:
+    case 0x07FD:
         /* date */
         get_time(NVRAM, &tm);
         retval = toBCD(tm.tm_mday);
         break;
     case 0x1FFE:
+    case 0x07FE:
         /* month */
         get_time(NVRAM, &tm);
         retval = toBCD(tm.tm_mon + 1);
         break;
     case 0x1FFF:
+    case 0x07FF:
         /* year */
         get_time(NVRAM, &tm);
         if (NVRAM->type == 8)
@@ -451,7 +476,7 @@
         break;
     }
     if (addr > 0x1FF9 && addr < 0x2000)
-	NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
+       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 
     return retval;
 }
@@ -476,7 +501,7 @@
     m48t59_t *NVRAM = opaque;
 
     addr -= NVRAM->io_base;
-    NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
+    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
     switch (addr) {
     case 0:
         NVRAM->addr &= ~0x00FF;
@@ -509,7 +534,7 @@
         retval = -1;
         break;
     }
-    NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
+    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 
     return retval;
 }
@@ -650,7 +675,7 @@
     }
     if (mem_base != 0) {
         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
-        cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
+        cpu_register_physical_memory(mem_base, size, s->mem_index);
     }
     if (type == 59) {
         s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);

Modified: trunk/src/host/qemu-neo1973/hw/mainstone.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mainstone.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/mainstone.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -64,19 +64,24 @@
                 const char *kernel_cmdline, const char *initrd_filename,
                 const char *cpu_model, enum mainstone_model_e model, int arm_id)
 {
-    uint32_t mainstone_ram = 0x04000000;
-    uint32_t mainstone_rom = 0x00800000;
+    uint32_t mainstone_ram   = 0x04000000;
+    uint32_t mainstone_rom   = 0x00800000;
+    uint32_t mainstone_flash = 0x02000000;
+    uint32_t sector_len = 256 * 1024;
+    target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
     struct pxa2xx_state_s *cpu;
     qemu_irq *mst_irq;
-    int index;
+    int i, index;
 
     if (!cpu_model)
         cpu_model = "pxa270-c5";
 
     /* Setup CPU & memory */
-    if (ram_size < mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE) {
+    if (ram_size < mainstone_ram + mainstone_rom + 2 * mainstone_flash +
+                    PXA2XX_INTERNAL_SIZE) {
         fprintf(stderr, "This platform requires %i bytes of memory\n",
-                        mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE);
+                        mainstone_ram + mainstone_rom + 2 * mainstone_flash +
+                        PXA2XX_INTERNAL_SIZE);
         exit(1);
     }
 
@@ -88,33 +93,22 @@
     cpu->env->regs[15] = PXA2XX_SDRAM_BASE;
 
     /* There are two 32MiB flash devices on the board */
-    index = drive_get_index(IF_PFLASH, 0, 0);
-    if (index == -1) {
-        fprintf(stderr, "Two flash images must be given with the "
-                "'pflash' parameter\n");
-        exit(1);
-    }
-    if (!pflash_cfi01_register(MST_FLASH_0,
-                         mainstone_ram + PXA2XX_INTERNAL_SIZE,
-                         drives_table[index].bdrv,
-                         256 * 1024, 128, 4, 0, 0, 0, 0)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-        exit(1);
-    }
+    for (i = 0; i < 2; i ++) {
+        index = drive_get_index(IF_PFLASH, 0, i);
+        if (index == -1) {
+            fprintf(stderr, "Two flash images must be given with the "
+                    "'pflash' parameter\n");
+            exit(1);
+        }
 
-    index = drive_get_index(IF_PFLASH, 0, 1);
-    if (index == -1) {
-        fprintf(stderr, "Two flash images must be given with the "
-                "'pflash' parameter\n");
-        exit(1);
+        if (!pflash_cfi01_register(mainstone_flash_base[i],
+                                qemu_ram_alloc(mainstone_flash),
+                                drives_table[index].bdrv, sector_len,
+                                mainstone_flash / sector_len, 4, 0, 0, 0, 0)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+            exit(1);
+        }
     }
-    if (!pflash_cfi01_register(MST_FLASH_1,
-                         mainstone_ram + PXA2XX_INTERNAL_SIZE,
-                         drives_table[index].bdrv,
-                         256 * 1024, 128, 4, 0, 0, 0, 0)) {
-        fprintf(stderr, "qemu: Error registering flash memory.\n");
-        exit(1);
-    }
 
     mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0);
 

Modified: trunk/src/host/qemu-neo1973/hw/mips_malta.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_malta.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/mips_malta.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -28,6 +28,8 @@
 #include "net.h"
 #include "boards.h"
 #include "smbus.h"
+#include "block.h"
+#include "flash.h"
 #include "mips.h"
 #include "pci.h"
 #include "qemu-char.h"
@@ -35,6 +37,8 @@
 #include "audio/audio.h"
 #include "boards.h"
 
+//#define DEBUG_BOARD_INIT
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define BIOS_FILENAME "mips_bios.bin"
 #else
@@ -766,13 +770,13 @@
 {
     char buf[1024];
     unsigned long bios_offset;
+    target_long bios_size;
     int64_t kernel_entry;
     PCIBus *pci_bus;
     CPUState *env;
     RTCState *rtc_state;
     fdctrl_t *floppy_controller;
     MaltaFPGAState *malta_fpga;
-    int ret;
     qemu_irq *i8259;
     int piix4_devfn;
     uint8_t *eeprom_buf;
@@ -781,6 +785,8 @@
     int index;
     BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     BlockDriverState *fd[MAX_FD];
+    int fl_idx = 0;
+    int fl_sectors = 0;
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -801,7 +807,7 @@
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
-    /* Map the bios at two physical locations, as on the real board */
+    /* Map the bios at two physical locations, as on the real board. */
     bios_offset = ram_size + vga_ram_size;
     cpu_register_physical_memory(0x1e000000LL,
                                  BIOS_SIZE, bios_offset | IO_MEM_ROM);
@@ -811,17 +817,44 @@
     /* FPGA */
     malta_fpga = malta_fpga_init(0x1f000000LL, env);
 
-    /* Load a BIOS image unless a kernel image has been specified. */
-    if (!kernel_filename) {
-        if (bios_name == NULL)
-            bios_name = BIOS_FILENAME;
-        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
-        ret = load_image(buf, phys_ram_base + bios_offset);
-        if (ret < 0 || ret > BIOS_SIZE) {
-            fprintf(stderr,
-                    "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
-                    buf);
-            exit(1);
+    /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
+    if (kernel_filename) {
+        /* Write a small bootloader to the flash location. */
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        kernel_entry = load_kernel(env);
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+        write_bootloader(env, bios_offset, kernel_entry);
+    } else {
+        index = drive_get_index(IF_PFLASH, 0, fl_idx);
+        if (index != -1) {
+            /* Load firmware from flash. */
+            bios_size = 0x400000;
+            fl_sectors = bios_size >> 16;
+#ifdef DEBUG_BOARD_INIT
+            printf("Register parallel flash %d size " TARGET_FMT_lx " at "
+                   "offset %08lx addr %08llx '%s' %x\n",
+                   fl_idx, bios_size, bios_offset, 0x1e000000LL,
+                   bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
+#endif
+            pflash_cfi01_register(0x1e000000LL, bios_offset,
+                                  drives_table[index].bdrv, 65536, fl_sectors,
+                                  4, 0x0000, 0x0000, 0x0000, 0x0000);
+            fl_idx++;
+        } else {
+            /* Load a BIOS image. */
+            if (bios_name == NULL)
+                bios_name = BIOS_FILENAME;
+            snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
+            bios_size = load_image(buf, phys_ram_base + bios_offset);
+            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+                fprintf(stderr,
+                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                        buf);
+                exit(1);
+            }
         }
         /* In little endian mode the 32bit words in the bios are swapped,
            a neat trick which allows bi-endian firmware. */
@@ -829,26 +862,14 @@
         {
             uint32_t *addr;
             for (addr = (uint32_t *)(phys_ram_base + bios_offset);
-                 addr < (uint32_t *)(phys_ram_base + bios_offset + ret);
-		 addr++) {
+                 addr < (uint32_t *)(phys_ram_base + bios_offset + bios_size);
+                 addr++) {
                 *addr = bswap32(*addr);
             }
         }
 #endif
     }
 
-    /* If a kernel image has been specified, write a small bootloader
-       to the flash location. */
-    if (kernel_filename) {
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        loaderparams.kernel_cmdline = kernel_cmdline;
-        loaderparams.initrd_filename = initrd_filename;
-        kernel_entry = load_kernel(env);
-        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
-        write_bootloader(env, bios_offset, kernel_entry);
-    }
-
     /* Board ID = 0x420 (Malta Board with CoreLV)
        XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
        map to the board ID. */

Modified: trunk/src/host/qemu-neo1973/hw/pcnet.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcnet.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/pcnet.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -2043,15 +2043,15 @@
 }
 
 static CPUReadMemoryFunc *lance_mem_read[3] = {
+    NULL,
     lance_mem_readw,
-    lance_mem_readw,
-    lance_mem_readw,
+    NULL,
 };
 
 static CPUWriteMemoryFunc *lance_mem_write[3] = {
+    NULL,
     lance_mem_writew,
-    lance_mem_writew,
-    lance_mem_writew,
+    NULL,
 };
 
 void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,

Modified: trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -111,8 +111,8 @@
     else if (pfl->width == 4)
         boff = boff >> 2;
 
-    DPRINTF("%s: reading offset %08x under cmd %02x\n",
-                    __func__, boff, pfl->cmd);
+    DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x\n",
+            __func__, boff, pfl->cmd);
 
     switch (pfl->cmd) {
     case 0x00:
@@ -121,7 +121,8 @@
         switch (width) {
         case 1:
             ret = p[offset];
-            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
+            DPRINTF("%s: data offset " TARGET_FMT_lx " %02x\n",
+                    __func__, offset, ret);
             break;
         case 2:
 #if defined(TARGET_WORDS_BIGENDIAN)
@@ -131,7 +132,8 @@
             ret = p[offset];
             ret |= p[offset + 1] << 8;
 #endif
-            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
+            DPRINTF("%s: data offset " TARGET_FMT_lx " %04x\n",
+                    __func__, offset, ret);
             break;
         case 4:
 #if defined(TARGET_WORDS_BIGENDIAN)
@@ -146,7 +148,8 @@
             ret |= p[offset + 2] << 16;
             ret |= p[offset + 3] << 24;
 #endif
-            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
+            DPRINTF("%s: data offset " TARGET_FMT_lx " %08x\n",
+                    __func__, offset, ret);
             break;
         default:
             DPRINTF("BUG in %s\n", __func__);
@@ -208,8 +211,8 @@
     else
         offset -= pfl->base;
 
-    DPRINTF("%s: offset %08x %08x %d wcycle 0x%x\n",
-                    __func__, offset, value, width, pfl->wcycle);
+    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d wcycle 0x%x\n",
+            __func__, offset, value, width, pfl->wcycle);
 
     /* Set the device in I/O access mode */
     cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
@@ -230,8 +233,9 @@
             p = pfl->storage;
             offset &= ~(pfl->sector_len - 1);
 
-            DPRINTF("%s: block erase at 0x%x bytes 0x%x\n", __func__,
-                            offset, pfl->sector_len);
+            DPRINTF("%s: block erase at " TARGET_FMT_lx " bytes "
+                    TARGET_FMT_lx "\n",
+                    __func__, offset, pfl->sector_len);
 
             memset(p + offset, 0xff, pfl->sector_len);
             pflash_update(pfl, offset, pfl->sector_len);
@@ -278,7 +282,7 @@
 
             break;
         case 0xe8:
-            DPRINTF("%s: block write of 0x%x bytes\n", __func__, cmd);
+            DPRINTF("%s: block write of %x bytes\n", __func__, cmd);
             pfl->counter = cmd;
             pfl->wcycle++;
             break;
@@ -311,8 +315,9 @@
         switch (pfl->cmd) {
         case 0xe8: /* Block write */
             p = pfl->storage;
-            DPRINTF("%s: block write offset 0x%x value 0x%x counter 0x%x\n",
-                            __func__, offset, value, pfl->counter);
+            DPRINTF("%s: block write offset " TARGET_FMT_lx
+                    " value %x counter " TARGET_FMT_lx "\n",
+                    __func__, offset, value, pfl->counter);
             switch (width) {
             case 1:
                 p[offset] = value;
@@ -382,8 +387,8 @@
 
  error_flash:
     printf("%s: Unimplemented flash cmd sequence "
-                    "(offset 0x%x, wcycle 0x%x cmd 0x%x value 0x%x\n",
-                    __func__, offset, pfl->wcycle, pfl->cmd, value);
+           "(offset " TARGET_FMT_lx ", wcycle 0x%x cmd 0x%x value 0x%x\n",
+           __func__, offset, pfl->wcycle, pfl->cmd, value);
 
  reset_flash:
     cpu_register_physical_memory(pfl->base, pfl->total_len,
@@ -484,7 +489,7 @@
 }
 
 pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
-                                BlockDriverState *bs, target_ulong sector_len,
+                                BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
                                 uint16_t id2, uint16_t id3)
@@ -495,9 +500,11 @@
     total_len = sector_len * nb_blocs;
 
     /* XXX: to be fixed */
+#if 0
     if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
         total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
         return NULL;
+#endif
 
     pfl = qemu_mallocz(sizeof(pflash_t));
 

Added: trunk/src/host/qemu-neo1973/hw/sbi.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sbi.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/sbi.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -0,0 +1,167 @@
+/*
+ * QEMU Sparc SBI interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "sun4m.h"
+#include "console.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, args...) \
+do { printf("IRQ: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#define MAX_CPUS 16
+
+#define SBI_NREGS 16
+
+typedef struct SBIState {
+    uint32_t regs[SBI_NREGS];
+    uint32_t intreg_pending[MAX_CPUS];
+    qemu_irq *cpu_irqs[MAX_CPUS];
+    uint32_t pil_out[MAX_CPUS];
+} SBIState;
+
+#define SBI_SIZE (SBI_NREGS * 4)
+#define SBI_MASK (SBI_SIZE - 1)
+
+static void sbi_check_interrupts(void *opaque)
+{
+}
+
+static void sbi_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static void sbi_set_timer_irq_cpu(void *opaque, int cpu, int level)
+{
+}
+
+static uint32_t sbi_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SBIState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = (addr & SBI_MASK) >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sbi_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SBIState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & SBI_MASK) >> 2;
+    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
+    switch (saddr) {
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *sbi_mem_read[3] = {
+    NULL,
+    NULL,
+    sbi_mem_readl,
+};
+
+static CPUWriteMemoryFunc *sbi_mem_write[3] = {
+    NULL,
+    NULL,
+    sbi_mem_writel,
+};
+
+static void sbi_save(QEMUFile *f, void *opaque)
+{
+    SBIState *s = opaque;
+    unsigned int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        qemu_put_be32s(f, &s->intreg_pending[i]);
+    }
+}
+
+static int sbi_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SBIState *s = opaque;
+    unsigned int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        qemu_get_be32s(f, &s->intreg_pending[i]);
+    }
+    sbi_check_interrupts(s);
+
+    return 0;
+}
+
+static void sbi_reset(void *opaque)
+{
+    SBIState *s = opaque;
+    unsigned int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->intreg_pending[i] = 0;
+    }
+    sbi_check_interrupts(s);
+}
+
+void *sbi_init(target_phys_addr_t addr, qemu_irq **irq, qemu_irq **cpu_irq,
+               qemu_irq **parent_irq)
+{
+    unsigned int i;
+    int sbi_io_memory;
+    SBIState *s;
+
+    s = qemu_mallocz(sizeof(SBIState));
+    if (!s)
+        return NULL;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->cpu_irqs[i] = parent_irq[i];
+    }
+
+    sbi_io_memory = cpu_register_io_memory(0, sbi_mem_read, sbi_mem_write, s);
+    cpu_register_physical_memory(addr, SBI_SIZE, sbi_io_memory);
+
+    register_savevm("sbi", addr, 1, sbi_save, sbi_load, s);
+    qemu_register_reset(sbi_reset, s);
+    *irq = qemu_allocate_irqs(sbi_set_irq, s, 32);
+    *cpu_irq = qemu_allocate_irqs(sbi_set_timer_irq_cpu, s, MAX_CPUS);
+    sbi_reset(s);
+
+    return s;
+}

Modified: trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_intctl.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/slavio_intctl.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -59,7 +59,7 @@
 #endif
     qemu_irq *cpu_irqs[MAX_CPUS];
     const uint32_t *intbit_to_level;
-    uint32_t cputimer_bit;
+    uint32_t cputimer_lbit, cputimer_mbit;
     uint32_t pil_out[MAX_CPUS];
 } SLAVIO_INTCTLState;
 
@@ -68,9 +68,10 @@
 #define INTCTLM_MAXADDR 0x13
 #define INTCTLM_SIZE (INTCTLM_MAXADDR + 1)
 #define INTCTLM_MASK 0x1f
-#define MASTER_IRQ_MASK ~0x4fb2007f
+#define MASTER_IRQ_MASK ~0x0fa2007f
 #define MASTER_DISABLE 0x80000000
-#define CPU_IRQ_MASK 0xfffe0000
+#define CPU_SOFTIRQ_MASK 0xfffe0000
+#define CPU_HARDIRQ_MASK 0x0000fffe
 #define CPU_IRQ_INT15_IN 0x0004000
 #define CPU_IRQ_INT15_MASK 0x80000000
 
@@ -111,13 +112,13 @@
     case 1: // clear pending softints
         if (val & CPU_IRQ_INT15_IN)
             val |= CPU_IRQ_INT15_MASK;
-        val &= CPU_IRQ_MASK;
+        val &= CPU_SOFTIRQ_MASK;
         s->intreg_pending[cpu] &= ~val;
         slavio_check_interrupts(s);
         DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
         break;
     case 2: // set softint
-        val &= CPU_IRQ_MASK;
+        val &= CPU_SOFTIRQ_MASK;
         s->intreg_pending[cpu] |= val;
         slavio_check_interrupts(s);
         DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
@@ -128,15 +129,15 @@
 }
 
 static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
+    NULL,
+    NULL,
     slavio_intctl_mem_readl,
-    slavio_intctl_mem_readl,
-    slavio_intctl_mem_readl,
 };
 
 static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
+    NULL,
+    NULL,
     slavio_intctl_mem_writel,
-    slavio_intctl_mem_writel,
-    slavio_intctl_mem_writel,
 };
 
 // master system interrupt controller
@@ -145,13 +146,13 @@
     SLAVIO_INTCTLState *s = opaque;
     uint32_t saddr, ret;
 
-    saddr = (addr & INTCTLM_MAXADDR) >> 2;
+    saddr = (addr & INTCTLM_MASK) >> 2;
     switch (saddr) {
     case 0:
         ret = s->intregm_pending & ~MASTER_DISABLE;
         break;
     case 1:
-        ret = s->intregm_disabled;
+        ret = s->intregm_disabled & MASTER_IRQ_MASK;
         break;
     case 4:
         ret = s->target_cpu;
@@ -199,15 +200,15 @@
 }
 
 static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
+    NULL,
+    NULL,
     slavio_intctlm_mem_readl,
-    slavio_intctlm_mem_readl,
-    slavio_intctlm_mem_readl,
 };
 
 static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
+    NULL,
+    NULL,
     slavio_intctlm_mem_writel,
-    slavio_intctlm_mem_writel,
-    slavio_intctlm_mem_writel,
 };
 
 void slavio_pic_info(void *opaque)
@@ -257,7 +258,7 @@
                     pil_pending |= 1 << s->intbit_to_level[j];
             }
         }
-        pil_pending |= (s->intreg_pending[i] & CPU_IRQ_MASK) >> 16;
+        pil_pending |= (s->intreg_pending[i] & CPU_SOFTIRQ_MASK) >> 16;
 
         for (j = 0; j < MAX_PILS; j++) {
             if (pil_pending & (1 << j)) {
@@ -305,10 +306,13 @@
 
     DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
 
-    if (level)
-        s->intreg_pending[cpu] |= s->cputimer_bit;
-    else
-        s->intreg_pending[cpu] &= ~s->cputimer_bit;
+    if (level) {
+        s->intregm_pending |= s->cputimer_mbit;
+        s->intreg_pending[cpu] |= s->cputimer_lbit;
+    } else {
+        s->intregm_pending &= ~s->cputimer_mbit;
+        s->intreg_pending[cpu] &= ~s->cputimer_lbit;
+    }
 
     slavio_check_interrupts(s);
 }
@@ -386,7 +390,8 @@
     *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
 
     *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS);
-    s->cputimer_bit = 1 << s->intbit_to_level[cputimer];
+    s->cputimer_mbit = 1 << cputimer;
+    s->cputimer_lbit = 1 << intbit_to_level[cputimer];
     slavio_intctl_reset(s);
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/slavio_misc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_misc.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/slavio_misc.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -191,14 +191,14 @@
 
 static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
     slavio_misc_mem_readb,
-    slavio_misc_mem_readb,
-    slavio_misc_mem_readb,
+    NULL,
+    NULL,
 };
 
 static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
     slavio_misc_mem_writeb,
-    slavio_misc_mem_writeb,
-    slavio_misc_mem_writeb,
+    NULL,
+    NULL,
 };
 
 static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
@@ -241,18 +241,18 @@
 }
 
 static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
+    NULL,
+    NULL,
     slavio_sysctrl_mem_readl,
-    slavio_sysctrl_mem_readl,
-    slavio_sysctrl_mem_readl,
 };
 
 static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
+    NULL,
+    NULL,
     slavio_sysctrl_mem_writel,
-    slavio_sysctrl_mem_writel,
-    slavio_sysctrl_mem_writel,
 };
 
-static uint32_t slavio_led_mem_reads(void *opaque, target_phys_addr_t addr)
+static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     MiscState *s = opaque;
     uint32_t ret = 0, saddr;
@@ -270,7 +270,7 @@
     return ret;
 }
 
-static void slavio_led_mem_writes(void *opaque, target_phys_addr_t addr,
+static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
                                   uint32_t val)
 {
     MiscState *s = opaque;
@@ -289,15 +289,15 @@
 }
 
 static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
-    slavio_led_mem_reads,
-    slavio_led_mem_reads,
-    slavio_led_mem_reads,
+    NULL,
+    slavio_led_mem_readw,
+    NULL,
 };
 
 static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
-    slavio_led_mem_writes,
-    slavio_led_mem_writes,
-    slavio_led_mem_writes,
+    NULL,
+    slavio_led_mem_writew,
+    NULL,
 };
 
 static void slavio_misc_save(QEMUFile *f, void *opaque)

Modified: trunk/src/host/qemu-neo1973/hw/slavio_serial.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_serial.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/slavio_serial.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -305,7 +305,7 @@
             STATUS_CTS | STATUS_TXUNDRN;
     else
         s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
-    s->rregs[R_SPEC] = SPEC_BITS8;
+    s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
 
     s->rx = s->tx = 0;
     s->rxint = s->txint = 0;
@@ -641,14 +641,14 @@
 
 static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
     slavio_serial_mem_readb,
-    slavio_serial_mem_readb,
-    slavio_serial_mem_readb,
+    NULL,
+    NULL,
 };
 
 static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
     slavio_serial_mem_writeb,
-    slavio_serial_mem_writeb,
-    slavio_serial_mem_writeb,
+    NULL,
+    NULL,
 };
 
 static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)

Modified: trunk/src/host/qemu-neo1973/hw/slavio_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_timer.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/slavio_timer.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -104,7 +104,11 @@
     else
         limit = s->limit;
 
-    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
+    if (s->timer)
+        count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
+    else
+        count = 0;
+
     DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
             s->counthigh, s->count);
     s->count = count & TIMER_COUNT_MASK32;
@@ -190,15 +194,18 @@
             qemu_irq_lower(s->irq);
             s->limit = TIMER_MAX_COUNT64;
             DPRINTF("processor %d user timer reset\n", s->slave_index);
-            ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
+            if (s->timer)
+                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
         } else {
             // set limit, reset counter
             qemu_irq_lower(s->irq);
             s->limit = val & TIMER_MAX_COUNT32;
-            if (s->limit == 0) /* free-run */
-                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-            else
-                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
+            if (s->timer) {
+                if (s->limit == 0) /* free-run */
+                    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+                else
+                    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
+            }
         }
         break;
     case TIMER_COUNTER:
@@ -207,28 +214,33 @@
             qemu_irq_lower(s->irq);
             s->limit = TIMER_MAX_COUNT64;
             DPRINTF("processor %d user timer reset\n", s->slave_index);
-            ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
+            if (s->timer)
+                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
         } else
             DPRINTF("not user timer\n");
         break;
     case TIMER_COUNTER_NORST:
         // set limit without resetting counter
         s->limit = val & TIMER_MAX_COUNT32;
-        if (s->limit == 0)	/* free-run */
-            ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
-        else
-            ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
+        if (s->timer) {
+            if (s->limit == 0)	/* free-run */
+                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
+            else
+                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
+        }
         break;
     case TIMER_STATUS:
         if (slavio_timer_is_user(s)) {
             // start/stop user counter
             if ((val & 1) && !s->running) {
                 DPRINTF("processor %d user timer started\n", s->slave_index);
-                ptimer_run(s->timer, 0);
+                if (s->timer)
+                    ptimer_run(s->timer, 0);
                 s->running = 1;
             } else if (!(val & 1) && s->running) {
                 DPRINTF("processor %d user timer stopped\n", s->slave_index);
-                ptimer_stop(s->timer);
+                if (s->timer)
+                    ptimer_stop(s->timer);
                 s->running = 0;
             }
         }
@@ -241,6 +253,8 @@
                 if (val & (1 << i)) {
                     qemu_irq_lower(s->slave[i]->irq);
                     s->slave[i]->limit = -1ULL;
+                } else {
+                    ptimer_stop(s->slave[i]->timer);
                 }
                 if ((val & (1 << i)) != (s->slave_mode & (1 << i))) {
                     ptimer_stop(s->slave[i]->timer);
@@ -262,15 +276,15 @@
 }
 
 static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
+    NULL,
+    NULL,
     slavio_timer_mem_readl,
-    slavio_timer_mem_readl,
-    slavio_timer_mem_readl,
 };
 
 static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
+    NULL,
+    NULL,
     slavio_timer_mem_writel,
-    slavio_timer_mem_writel,
-    slavio_timer_mem_writel,
 };
 
 static void slavio_timer_save(QEMUFile *f, void *opaque)
@@ -280,29 +294,26 @@
     qemu_put_be64s(f, &s->limit);
     qemu_put_be32s(f, &s->count);
     qemu_put_be32s(f, &s->counthigh);
-    qemu_put_be32(f, 0); // Was irq
     qemu_put_be32s(f, &s->reached);
     qemu_put_be32s(f, &s->running);
-    qemu_put_be32s(f, 0); // Was mode
-    qemu_put_ptimer(f, s->timer);
+    if (s->timer)
+        qemu_put_ptimer(f, s->timer);
 }
 
 static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
 {
     SLAVIO_TIMERState *s = opaque;
-    uint32_t tmp;
 
-    if (version_id != 2)
+    if (version_id != 3)
         return -EINVAL;
 
     qemu_get_be64s(f, &s->limit);
     qemu_get_be32s(f, &s->count);
     qemu_get_be32s(f, &s->counthigh);
-    qemu_get_be32s(f, &tmp); // Was irq
     qemu_get_be32s(f, &s->reached);
     qemu_get_be32s(f, &s->running);
-    qemu_get_be32s(f, &tmp); // Was mode
-    qemu_get_ptimer(f, s->timer);
+    if (s->timer)
+        qemu_get_ptimer(f, s->timer);
 
     return 0;
 }
@@ -315,8 +326,10 @@
     s->count = 0;
     s->reached = 0;
     s->slave_mode = 0;
-    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-    ptimer_run(s->timer, 0);
+    if (!s->master || s->slave_index < s->master->num_slaves) {
+        ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+        ptimer_run(s->timer, 0);
+    }
     s->running = 1;
     qemu_irq_lower(s->irq);
 }
@@ -336,9 +349,11 @@
     s->irq = irq;
     s->master = master;
     s->slave_index = slave_index;
-    bh = qemu_bh_new(slavio_timer_irq, s);
-    s->timer = ptimer_init(bh);
-    ptimer_set_period(s->timer, TIMER_PERIOD);
+    if (!master || slave_index < master->num_slaves) {
+        bh = qemu_bh_new(slavio_timer_irq, s);
+        s->timer = ptimer_init(bh);
+        ptimer_set_period(s->timer, TIMER_PERIOD);
+    }
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
                                                     slavio_timer_mem_write, s);
@@ -348,7 +363,7 @@
     else
         cpu_register_physical_memory(addr, SYS_TIMER_SIZE,
                                      slavio_timer_io_memory);
-    register_savevm("slavio_timer", addr, 2, slavio_timer_save,
+    register_savevm("slavio_timer", addr, 3, slavio_timer_save,
                     slavio_timer_load, s);
     qemu_register_reset(slavio_timer_reset, s);
     slavio_timer_reset(s);

Modified: trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sparc32_dma.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/sparc32_dma.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -198,15 +198,15 @@
 }
 
 static CPUReadMemoryFunc *dma_mem_read[3] = {
+    NULL,
+    NULL,
     dma_mem_readl,
-    dma_mem_readl,
-    dma_mem_readl,
 };
 
 static CPUWriteMemoryFunc *dma_mem_write[3] = {
+    NULL,
+    NULL,
     dma_mem_writel,
-    dma_mem_writel,
-    dma_mem_writel,
 };
 
 static void dma_reset(void *opaque)

Added: trunk/src/host/qemu-neo1973/hw/sun4c_intctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4c_intctl.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/sun4c_intctl.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -0,0 +1,223 @@
+/*
+ * QEMU Sparc Sun4c interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "sun4m.h"
+#include "console.h"
+//#define DEBUG_IRQ_COUNT
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, args...) \
+do { printf("IRQ: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+/*
+ * Registers of interrupt controller in sun4c.
+ *
+ */
+
+#define MAX_PILS 16
+
+typedef struct Sun4c_INTCTLState {
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count;
+#endif
+    qemu_irq *cpu_irqs;
+    const uint32_t *intbit_to_level;
+    uint32_t pil_out;
+    uint8_t reg;
+    uint8_t pending;
+} Sun4c_INTCTLState;
+
+#define INTCTL_MAXADDR 0
+#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
+
+static void sun4c_check_interrupts(void *opaque);
+
+static uint32_t sun4c_intctl_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t ret;
+
+    ret = s->reg;
+    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
+    val &= 0xbf;
+    s->reg = val;
+    sun4c_check_interrupts(s);
+}
+
+static CPUReadMemoryFunc *sun4c_intctl_mem_read[3] = {
+    sun4c_intctl_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc *sun4c_intctl_mem_write[3] = {
+    sun4c_intctl_mem_writeb,
+    NULL,
+    NULL,
+};
+
+void sun4c_pic_info(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending, s->reg);
+}
+
+void sun4c_irq_info(void *opaque)
+{
+#ifndef DEBUG_IRQ_COUNT
+    term_printf("irq statistic code not compiled.\n");
+#else
+    Sun4c_INTCTLState *s = opaque;
+    int64_t count;
+
+    term_printf("IRQ statistics:\n");
+    count = s->irq_count[i];
+    if (count > 0)
+        term_printf("%2d: %" PRId64 "\n", i, count);
+#endif
+}
+
+static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
+
+static void sun4c_check_interrupts(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t pil_pending;
+    unsigned int i;
+
+    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
+    pil_pending = 0;
+    if (s->pending && !(s->reg & 0x80000000)) {
+        for (i = 0; i < 8; i++) {
+            if (s->pending & (1 << i))
+                pil_pending |= 1 << intbit_to_level[i];
+        }
+    }
+
+    for (i = 0; i < MAX_PILS; i++) {
+        if (pil_pending & (1 << i)) {
+            if (!(s->pil_out & (1 << i)))
+                qemu_irq_raise(s->cpu_irqs[i]);
+        } else {
+            if (s->pil_out & (1 << i))
+                qemu_irq_lower(s->cpu_irqs[i]);
+        }
+    }
+    s->pil_out = pil_pending;
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register
+ */
+static void sun4c_set_irq(void *opaque, int irq, int level)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+
+    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
+            level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count[pil]++;
+#endif
+            s->pending |= mask;
+        } else {
+            s->pending &= ~mask;
+        }
+        sun4c_check_interrupts(s);
+    }
+}
+
+static void sun4c_intctl_save(QEMUFile *f, void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    qemu_put_8s(f, &s->reg);
+    qemu_put_8s(f, &s->pending);
+}
+
+static int sun4c_intctl_load(QEMUFile *f, void *opaque, int version_id)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_8s(f, &s->reg);
+    qemu_get_8s(f, &s->pending);
+    sun4c_check_interrupts(s);
+
+    return 0;
+}
+
+static void sun4c_intctl_reset(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    s->reg = 1;
+    s->pending = 0;
+    sun4c_check_interrupts(s);
+}
+
+void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq,
+                        qemu_irq *parent_irq)
+{
+    int sun4c_intctl_io_memory;
+    Sun4c_INTCTLState *s;
+
+    s = qemu_mallocz(sizeof(Sun4c_INTCTLState));
+    if (!s)
+        return NULL;
+
+    sun4c_intctl_io_memory = cpu_register_io_memory(0, sun4c_intctl_mem_read,
+                                                    sun4c_intctl_mem_write, s);
+    cpu_register_physical_memory(addr, INTCTL_SIZE, sun4c_intctl_io_memory);
+    s->cpu_irqs = parent_irq;
+
+    register_savevm("sun4c_intctl", addr, 1, sun4c_intctl_save,
+                    sun4c_intctl_load, s);
+
+    qemu_register_reset(sun4c_intctl_reset, s);
+    *irq = qemu_allocate_irqs(sun4c_set_irq, s, 8);
+
+    sun4c_intctl_reset(s);
+    return s;
+}
+

Modified: trunk/src/host/qemu-neo1973/hw/sun4m.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1,5 +1,5 @@
 /*
- * QEMU Sun4m System Emulator
+ * QEMU Sun4m & Sun4d & Sun4c System Emulator
  *
  * Copyright (c) 2003-2005 Fabrice Bellard
  *
@@ -46,6 +46,18 @@
  * SPARCstation 20/xx, SPARCserver 20
  * SPARCstation 4
  *
+ * Sun4d architecture was used in the following machines:
+ *
+ * SPARCcenter 2000
+ * SPARCserver 1000
+ *
+ * Sun4c architecture was used in the following machines:
+ * SPARCstation 1/1+, SPARCserver 1/1+
+ * SPARCstation SLC
+ * SPARCstation IPC
+ * SPARCstation ELC
+ * SPARCstation IPX
+ *
  * See for example: http://www.sunhelp.org/faq/sunref1.html
  */
 
@@ -70,13 +82,14 @@
     target_phys_addr_t iommu_base, slavio_base;
     target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base;
     target_phys_addr_t serial_base, fd_base;
-    target_phys_addr_t dma_base, esp_base, le_base;
+    target_phys_addr_t idreg_base, dma_base, esp_base, le_base;
     target_phys_addr_t tcx_base, cs_base, power_base;
     target_phys_addr_t ecc_base;
     uint32_t ecc_version;
+    target_phys_addr_t sun4c_intctl_base, sun4c_counter_base;
     long vram_size, nvram_size;
-    // IRQ numbers are not PIL ones, but master interrupt controller register
-    // bit numbers
+    // IRQ numbers are not PIL ones, but master interrupt controller
+    // register bit numbers
     int intctl_g_intr, esp_irq, le_irq, clock_irq, clock1_irq;
     int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq;
     int machine_id; // For NVRAM
@@ -86,6 +99,26 @@
     const char * const default_cpu_model;
 };
 
+#define MAX_IOUNITS 5
+
+struct sun4d_hwdef {
+    target_phys_addr_t iounit_bases[MAX_IOUNITS], slavio_base;
+    target_phys_addr_t counter_base, nvram_base, ms_kb_base;
+    target_phys_addr_t serial_base;
+    target_phys_addr_t espdma_base, esp_base;
+    target_phys_addr_t ledma_base, le_base;
+    target_phys_addr_t tcx_base;
+    target_phys_addr_t sbi_base;
+    unsigned long vram_size, nvram_size;
+    // IRQ numbers are not PIL ones, but SBI register bit numbers
+    int esp_irq, le_irq, clock_irq, clock1_irq;
+    int ser_irq, ms_kb_irq, me_irq;
+    int machine_id; // For NVRAM
+    uint32_t iounit_version;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+};
+
 /* TSC handling */
 
 uint64_t cpu_get_tsc()
@@ -122,7 +155,7 @@
                        const char *boot_devices, uint32_t RAM_size,
                        uint32_t kernel_size,
                        int width, int height, int depth,
-                       int machine_id)
+                       int machine_id, const char *arch)
 {
     unsigned int i;
     uint32_t start, end;
@@ -140,7 +173,7 @@
     header->nvram_size = cpu_to_be16(0x2000);
     header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t));
     header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg));
-    strcpy(header->arch, "sun4m");
+    strcpy(header->arch, arch);
     header->nb_cpus = smp_cpus & 0xff;
     header->RAM0_base = 0;
     header->RAM0_size = cpu_to_be64((uint64_t)RAM_size);
@@ -203,12 +236,14 @@
 
 void pic_info()
 {
-    slavio_pic_info(slavio_intctl);
+    if (slavio_intctl)
+        slavio_pic_info(slavio_intctl);
 }
 
 void irq_info()
 {
-    slavio_irq_info(slavio_intctl);
+    if (slavio_intctl)
+        slavio_irq_info(slavio_intctl);
 }
 
 void cpu_check_irqs(CPUState *env)
@@ -350,7 +385,7 @@
     for(i = 0; i < smp_cpus; i++) {
         env = cpu_init(cpu_model);
         if (!env) {
-            fprintf(stderr, "Unable to find Sparc CPU definition\n");
+            fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
             exit(1);
         }
         cpu_sparc_set_id(env, i);
@@ -397,9 +432,9 @@
                 buf);
         exit(1);
     }
+    prom_offset += (ret + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
 
     /* set up devices */
-    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version);
     slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
                                        hwdef->intctl_base + 0x10000ULL,
                                        &hwdef->intbit_to_level[0],
@@ -407,6 +442,16 @@
                                        cpu_irqs,
                                        hwdef->clock_irq);
 
+    if (hwdef->idreg_base != (target_phys_addr_t)-1) {
+        stl_raw(phys_ram_base + prom_offset, 0xfe810103);
+
+        cpu_register_physical_memory(hwdef->idreg_base, sizeof(uint32_t),
+                                     prom_offset | IO_MEM_ROM);
+    }
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[hwdef->me_irq]);
+
     espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
                               iommu, &espdma_irq, &esp_reset);
 
@@ -480,12 +525,150 @@
 
     nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
-               graphic_height, graphic_depth, hwdef->machine_id);
+               graphic_height, graphic_depth, hwdef->machine_id, "Sun4m");
 
     if (hwdef->ecc_base != (target_phys_addr_t)-1)
         ecc_init(hwdef->ecc_base, hwdef->ecc_version);
 }
 
+static void sun4c_hw_init(const struct hwdef *hwdef, int RAM_size,
+                          const char *boot_device,
+                          DisplayState *ds, const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    unsigned int i;
+    void *iommu, *espdma, *ledma, *main_esp, *nvram;
+    qemu_irq *cpu_irqs, *slavio_irq, *espdma_irq, *ledma_irq;
+    qemu_irq *esp_reset, *le_reset;
+    unsigned long prom_offset, kernel_size;
+    int ret;
+    char buf[1024];
+    BlockDriverState *fd[MAX_FD];
+    int index;
+
+    /* init CPU */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    cpu_sparc_set_id(env, 0);
+
+    qemu_register_reset(main_cpu_reset, env);
+    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
+    env->prom_addr = hwdef->slavio_base;
+
+    /* allocate RAM */
+    if ((uint64_t)RAM_size > hwdef->max_mem) {
+        fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n",
+                (unsigned int)RAM_size / (1024 * 1024),
+                (unsigned int)hwdef->max_mem / (1024 * 1024));
+        exit(1);
+    }
+    cpu_register_physical_memory(0, RAM_size, 0);
+
+    /* load boot prom */
+    prom_offset = RAM_size + hwdef->vram_size;
+    cpu_register_physical_memory(hwdef->slavio_base,
+                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) &
+                                 TARGET_PAGE_MASK,
+                                 prom_offset | IO_MEM_ROM);
+
+    if (bios_name == NULL)
+        bios_name = PROM_FILENAME;
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
+    ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL);
+    if (ret < 0 || ret > PROM_SIZE_MAX)
+        ret = load_image(buf, phys_ram_base + prom_offset);
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n",
+                buf);
+        exit(1);
+    }
+    prom_offset += (ret + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+
+    /* set up devices */
+    slavio_intctl = sun4c_intctl_init(hwdef->sun4c_intctl_base,
+                                      &slavio_irq, cpu_irqs);
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[hwdef->me_irq]);
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
+                              iommu, &espdma_irq, &esp_reset);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[hwdef->le_irq], iommu, &ledma_irq,
+                             &le_reset);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
+             hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+
+    if (nd_table[0].model == NULL
+        || strcmp(nd_table[0].model, "lance") == 0) {
+        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
+    } else if (strcmp(nd_table[0].model, "?") == 0) {
+        fprintf(stderr, "qemu: Supported NICs: lance\n");
+        exit (1);
+    } else {
+        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+        exit (1);
+    }
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
+                        hwdef->nvram_size, 2);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq],
+                              nographic);
+    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
+    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+    slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
+                       serial_hds[1], serial_hds[0]);
+
+    if (hwdef->fd_base != (target_phys_addr_t)-1) {
+        /* there is zero or one floppy drive */
+        fd[1] = fd[0] = NULL;
+        index = drive_get_index(IF_FLOPPY, 0, 0);
+        if (index != -1)
+            fd[0] = drives_table[index].bdrv;
+
+        sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd);
+    }
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq,
+                        esp_reset);
+
+    for (i = 0; i < ESP_MAX_DEVS; i++) {
+        index = drive_get_index(IF_SCSI, 0, i);
+        if (index == -1)
+            continue;
+        esp_scsi_attach(main_esp, drives_table[index].bdrv, i);
+    }
+
+    kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline,
+                                    initrd_filename);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->machine_id, "Sun4c");
+}
+
 static const struct hwdef hwdefs[] = {
     /* SS-5 */
     {
@@ -499,11 +682,14 @@
         .fd_base      = 0x71400000,
         .counter_base = 0x71d00000,
         .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
         .dma_base     = 0x78400000,
         .esp_base     = 0x78800000,
         .le_base      = 0x78c00000,
         .power_base   = 0x7a000000,
         .ecc_base     = -1,
+        .sun4c_intctl_base  = -1,
+        .sun4c_counter_base = -1,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -516,7 +702,7 @@
         .me_irq = 30,
         .cs_irq = 5,
         .machine_id = 0x80,
-        .iommu_version = 0x04000000,
+        .iommu_version = 0x05000000,
         .intbit_to_level = {
             2, 3, 5, 7, 9, 11, 0, 14,   3, 5, 7, 9, 11, 13, 12, 12,
             6, 0, 4, 10, 8, 0, 11, 0,   0, 0, 0, 0, 15, 0, 15, 0,
@@ -536,12 +722,15 @@
         .fd_base      = 0xff1700000ULL,
         .counter_base = 0xff1300000ULL,
         .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
         .dma_base     = 0xef0400000ULL,
         .esp_base     = 0xef0800000ULL,
         .le_base      = 0xef0c00000ULL,
         .power_base   = 0xefa000000ULL,
         .ecc_base     = 0xf00000000ULL,
         .ecc_version  = 0x10000000, // version 0, implementation 1
+        .sun4c_intctl_base  = -1,
+        .sun4c_counter_base = -1,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -574,12 +763,15 @@
         .fd_base      = -1,
         .counter_base = 0xff1300000ULL,
         .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = -1,
         .dma_base     = 0xef0081000ULL,
         .esp_base     = 0xef0080000ULL,
         .le_base      = 0xef0060000ULL,
         .power_base   = 0xefa000000ULL,
         .ecc_base     = 0xf00000000ULL,
         .ecc_version  = 0x00000000, // version 0, implementation 0
+        .sun4c_intctl_base  = -1,
+        .sun4c_counter_base = -1,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -612,12 +804,15 @@
         .fd_base      = 0xff1700000ULL,
         .counter_base = 0xff1300000ULL,
         .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
         .dma_base     = 0xef0400000ULL,
         .esp_base     = 0xef0800000ULL,
         .le_base      = 0xef0c00000ULL,
         .power_base   = 0xefa000000ULL,
         .ecc_base     = 0xf00000000ULL,
         .ecc_version  = 0x20000000, // version 0, implementation 2
+        .sun4c_intctl_base  = -1,
+        .sun4c_counter_base = -1,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -638,6 +833,39 @@
         .max_mem = 0xffffffff, // XXX actually first 62GB ok
         .default_cpu_model = "TI SuperSparc II",
     },
+    /* SS-2 */
+    {
+        .iommu_base   = 0xf8000000,
+        .tcx_base     = 0xfe000000,
+        .cs_base      = -1,
+        .slavio_base  = 0xf6000000,
+        .ms_kb_base   = 0xf0000000,
+        .serial_base  = 0xf1000000,
+        .nvram_base   = 0xf2000000,
+        .fd_base      = 0xf7200000,
+        .counter_base = -1,
+        .intctl_base  = -1,
+        .dma_base     = 0xf8400000,
+        .esp_base     = 0xf8800000,
+        .le_base      = 0xf8c00000,
+        .power_base   = -1,
+        .sun4c_intctl_base  = 0xf5000000,
+        .sun4c_counter_base = 0xf3000000,
+        .vram_size    = 0x00100000,
+        .nvram_size   = 0x800,
+        .esp_irq = 2,
+        .le_irq = 3,
+        .clock_irq = 5,
+        .clock1_irq = 7,
+        .ms_kb_irq = 1,
+        .ser_irq = 1,
+        .fd_irq = 1,
+        .me_irq = 1,
+        .cs_irq = -1,
+        .machine_id = 0x55,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Cypress CY7C601",
+    },
 };
 
 /* SPARCstation 5 hardware initialisation */
@@ -680,6 +908,16 @@
                   kernel_cmdline, initrd_filename, cpu_model);
 }
 
+/* SPARCstation 2 hardware initialisation */
+static void ss2_init(int RAM_size, int vga_ram_size,
+                     const char *boot_device, DisplayState *ds,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    sun4c_hw_init(&hwdefs[4], RAM_size, boot_device, ds, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
 QEMUMachine ss5_machine = {
     "SS-5",
     "Sun4m platform, SPARCstation 5",
@@ -704,3 +942,249 @@
     ss20_init,
 };
 
+QEMUMachine ss2_machine = {
+    "SS-2",
+    "Sun4c platform, SPARCstation 2",
+    ss2_init,
+};
+
+static const struct sun4d_hwdef sun4d_hwdefs[] = {
+    /* SS-1000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            -1,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .vram_size    = 0x00100000,
+        .nvram_size   = 0x2000,
+        .esp_irq = 3,
+        .le_irq = 4,
+        .clock_irq = 14,
+        .clock1_irq = 10,
+        .ms_kb_irq = 12,
+        .ser_irq = 12,
+        .machine_id = 0x80,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xffffffff, // XXX actually first 62GB ok
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-2000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            0xfe4200000ULL,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .vram_size    = 0x00100000,
+        .nvram_size   = 0x2000,
+        .esp_irq = 3,
+        .le_irq = 4,
+        .clock_irq = 14,
+        .clock1_irq = 10,
+        .ms_kb_irq = 12,
+        .ser_irq = 12,
+        .machine_id = 0x80,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xffffffff, // XXX actually first 62GB ok
+        .default_cpu_model = "TI SuperSparc II",
+    },
+};
+
+static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, int RAM_size,
+                          const char *boot_device,
+                          DisplayState *ds, const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env, *envs[MAX_CPUS];
+    unsigned int i;
+    void *iounits[MAX_IOUNITS], *espdma, *ledma, *main_esp, *nvram, *sbi;
+    qemu_irq *cpu_irqs[MAX_CPUS], *sbi_irq, *sbi_cpu_irq,
+        *espdma_irq, *ledma_irq;
+    qemu_irq *esp_reset, *le_reset;
+    unsigned long prom_offset, kernel_size;
+    int ret;
+    char buf[1024];
+    int index;
+
+    /* init CPUs */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+            exit(1);
+        }
+        cpu_sparc_set_id(env, i);
+        envs[i] = env;
+        if (i == 0) {
+            qemu_register_reset(main_cpu_reset, env);
+        } else {
+            qemu_register_reset(secondary_cpu_reset, env);
+            env->halted = 1;
+        }
+        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
+        cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS);
+        env->prom_addr = hwdef->slavio_base;
+    }
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+    /* allocate RAM */
+    if ((uint64_t)RAM_size > hwdef->max_mem) {
+        fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n",
+                (unsigned int)RAM_size / (1024 * 1024),
+                (unsigned int)(hwdef->max_mem / (1024 * 1024)));
+        exit(1);
+    }
+    cpu_register_physical_memory(0, RAM_size, 0);
+
+    /* load boot prom */
+    prom_offset = RAM_size + hwdef->vram_size;
+    cpu_register_physical_memory(hwdef->slavio_base,
+                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) &
+                                 TARGET_PAGE_MASK,
+                                 prom_offset | IO_MEM_ROM);
+
+    if (bios_name == NULL)
+        bios_name = PROM_FILENAME;
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
+    ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL);
+    if (ret < 0 || ret > PROM_SIZE_MAX)
+        ret = load_image(buf, phys_ram_base + prom_offset);
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n",
+                buf);
+        exit(1);
+    }
+
+    /* set up devices */
+    sbi = sbi_init(hwdef->sbi_base, &sbi_irq, &sbi_cpu_irq, cpu_irqs);
+
+    for (i = 0; i < MAX_IOUNITS; i++)
+        if (hwdef->iounit_bases[i] != (target_phys_addr_t)-1)
+            iounits[i] = iommu_init(hwdef->iounit_bases[i],
+                                    hwdef->iounit_version,
+                                    sbi_irq[hwdef->me_irq]);
+
+    espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[hwdef->esp_irq],
+                              iounits[0], &espdma_irq, &esp_reset);
+
+    ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[hwdef->le_irq],
+                             iounits[0], &ledma_irq, &le_reset);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
+             hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+
+    if (nd_table[0].model == NULL
+        || strcmp(nd_table[0].model, "lance") == 0) {
+        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
+    } else if (strcmp(nd_table[0].model, "?") == 0) {
+        fprintf(stderr, "qemu: Supported NICs: lance\n");
+        exit (1);
+    } else {
+        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+        exit (1);
+    }
+
+    nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0,
+                        hwdef->nvram_size, 8);
+
+    slavio_timer_init_all(hwdef->counter_base, sbi_irq[hwdef->clock1_irq],
+                          sbi_cpu_irq, smp_cpus);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[hwdef->ms_kb_irq],
+                              nographic);
+    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
+    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+    slavio_serial_init(hwdef->serial_base, sbi_irq[hwdef->ser_irq],
+                       serial_hds[1], serial_hds[0]);
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq,
+                        esp_reset);
+
+    for (i = 0; i < ESP_MAX_DEVS; i++) {
+        index = drive_get_index(IF_SCSI, 0, i);
+        if (index == -1)
+            continue;
+        esp_scsi_attach(main_esp, drives_table[index].bdrv, i);
+    }
+
+    kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline,
+                                    initrd_filename);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->machine_id, "Sun4d");
+}
+
+/* SPARCserver 1000 hardware initialisation */
+static void ss1000_init(int RAM_size, int vga_ram_size,
+                        const char *boot_device, DisplayState *ds,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, ds, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCcenter 2000 hardware initialisation */
+static void ss2000_init(int RAM_size, int vga_ram_size,
+                        const char *boot_device, DisplayState *ds,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, ds, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+QEMUMachine ss1000_machine = {
+    "SS-1000",
+    "Sun4d platform, SPARCserver 1000",
+    ss1000_init,
+};
+
+QEMUMachine ss2000_machine = {
+    "SS-2000",
+    "Sun4d platform, SPARCcenter 2000",
+    ss2000_init,
+};

Modified: trunk/src/host/qemu-neo1973/hw/sun4m.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -4,7 +4,7 @@
 /* Devices used by sparc32 system.  */
 
 /* iommu.c */
-void *iommu_init(target_phys_addr_t addr, uint32_t version);
+void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq);
 void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
                                  uint8_t *buf, int len, int is_write);
 static inline void sparc_iommu_memory_read(void *opaque,
@@ -34,6 +34,14 @@
 void slavio_pic_info(void *opaque);
 void slavio_irq_info(void *opaque);
 
+/* sbi.c */
+void *sbi_init(target_phys_addr_t addr, qemu_irq **irq, qemu_irq **cpu_irq,
+               qemu_irq **parent_irq);
+
+/* sun4c_intctl.c */
+void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq,
+                        qemu_irq *parent_irq);
+
 /* slavio_timer.c */
 void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
                            qemu_irq *cpu_irqs, unsigned int num_cpus);

Modified: trunk/src/host/qemu-neo1973/hw/tcx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/tcx.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/hw/tcx.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -457,15 +457,15 @@
 }
 
 static CPUReadMemoryFunc *tcx_dac_read[3] = {
+    NULL,
+    NULL,
     tcx_dac_readl,
-    tcx_dac_readl,
-    tcx_dac_readl,
 };
 
 static CPUWriteMemoryFunc *tcx_dac_write[3] = {
+    NULL,
+    NULL,
     tcx_dac_writel,
-    tcx_dac_writel,
-    tcx_dac_writel,
 };
 
 static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
@@ -479,15 +479,15 @@
 }
 
 static CPUReadMemoryFunc *tcx_dummy_read[3] = {
+    NULL,
+    NULL,
     tcx_dummy_readl,
-    tcx_dummy_readl,
-    tcx_dummy_readl,
 };
 
 static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
+    NULL,
+    NULL,
     tcx_dummy_writel,
-    tcx_dummy_writel,
-    tcx_dummy_writel,
 };
 
 void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,

Modified: trunk/src/host/qemu-neo1973/linux-user/main.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/main.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/linux-user/main.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1,7 +1,7 @@
 /*
  *  qemu user main
  *
- *  Copyright (c) 2003 Fabrice Bellard
+ *  Copyright (c) 2003-2008 Fabrice Bellard
  *
  *  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
@@ -1892,10 +1892,11 @@
 
 void usage(void)
 {
-    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
-           "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
+           "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
            "Linux CPU emulator (compiled for %s emulation)\n"
            "\n"
+           "Standard options:\n"
            "-h                print this help\n"
            "-g port           wait gdb connection to port\n"
            "-L path           set the elf interpreter prefix (default=%s)\n"
@@ -1903,12 +1904,12 @@
            "-cpu model        select CPU (-cpu ? for list)\n"
            "-drop-ld-preload  drop LD_PRELOAD for target process\n"
            "\n"
-           "debug options:\n"
+           "Debug options:\n"
            "-d options   activate log (logfile=%s)\n"
            "-p pagesize  set the host page size to 'pagesize'\n"
            "-strace      log system calls\n"
            "\n"
-           "environment variables:\n"
+           "Environment variables:\n"
            "QEMU_STRACE       Print system calls and arguments similar to the\n"
            "                  'strace' program.  Enable by setting to any value.\n"
            ,

Modified: trunk/src/host/qemu-neo1973/pc-bios/README
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/README	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/pc-bios/README	2008-01-07 07:17:44 UTC (rev 3778)
@@ -14,8 +14,8 @@
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
-  The included Sparc32 and Sparc64 images are built from SVN
-  revision 181.
+  The included Sparc32 image is built from SVN revision 183
+  and Sparc64 from SVN revision 181.
 
 - The PXE roms come from Rom-o-Matic etherboot 5.4.2.
   pcnet32:pcnet32 -- [0x1022,0x2000]

Modified: trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
===================================================================
(Binary files differ)

Modified: trunk/src/host/qemu-neo1973/qemu-doc.texi
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-doc.texi	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/qemu-doc.texi	2008-01-07 07:17:44 UTC (rev 3778)
@@ -74,7 +74,7 @@
 @item PREP (PowerPC processor)
 @item G3 BW PowerMac (PowerPC processor)
 @item Mac99 PowerMac (PowerPC processor, in progress)
- at item Sun4m (32-bit Sparc processor)
+ at item Sun4m/Sun4c/Sun4d (32-bit Sparc processor)
 @item Sun4u (64-bit Sparc processor, in progress)
 @item Malta board (32-bit and 64-bit MIPS processors)
 @item ARM Integrator/CP (ARM)
@@ -2026,15 +2026,17 @@
 @section Sparc32 System emulator
 
 Use the executable @file{qemu-system-sparc} to simulate a SPARCstation
-5, SPARCstation 10, or SPARCserver 600MP (sun4m architecture). The
-emulation is somewhat complete.  SMP up to 16 CPUs is supported, but
-Linux limits the number of usable CPUs to 4.
+5, SPARCstation 10, SPARCstation 20, SPARCserver 600MP (sun4m
+architecture), SPARCstation 2 (sun4c architecture), SPARCserver 1000,
+or SPARCcenter 2000 (sun4d architecture). The emulation is somewhat
+complete.  SMP up to 16 CPUs is supported, but Linux limits the number
+of usable CPUs to 4.
 
-QEMU emulates the following sun4m peripherals:
+QEMU emulates the following sun4m/sun4d peripherals:
 
 @itemize @minus
 @item
-IOMMU
+IOMMU or IO-UNITs
 @item
 TCX Frame buffer
 @item
@@ -2054,7 +2056,7 @@
 
 The number of peripherals is fixed in the architecture.  Maximum
 memory size depends on the machine type, for SS-5 it is 256MB and for
-SS-10 and SS-600MP 2047MB.
+others 2047MB.
 
 Since version 0.8.2, QEMU uses OpenBIOS
 @url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable
@@ -2085,7 +2087,7 @@
  -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single'
 @end example
 
- at item -M [SS-5|SS-10|SS-600MP]
+ at item -M [SS-5|SS-10|SS-20|SS-600MP|SS-2|SS-1000|SS-2000]
 
 Set the emulated machine type. Default is SS-5.
 

Modified: trunk/src/host/qemu-neo1973/qemu-img.c
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-img.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/qemu-img.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1,7 +1,7 @@
 /*
  * QEMU disk image utility
  *
- * Copyright (c) 2003-2007 Fabrice Bellard
+ * Copyright (c) 2003-2008 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -83,7 +83,7 @@
 
 static void help(void)
 {
-    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2007 Fabrice Bellard\n"
+    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
            "usage: qemu-img command [command options]\n"
            "QEMU disk image utility\n"
            "\n"

Modified: trunk/src/host/qemu-neo1973/target-mips/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/cpu.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/cpu.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -162,6 +162,8 @@
 
     uint32_t SEGBITS;
     target_ulong SEGMask;
+    uint32_t PABITS;
+    target_ulong PAMask;
 
     int32_t CP0_Index;
     /* CP0_MVP* are per MVP registers. */
@@ -415,7 +417,7 @@
     int user_mode_only; /* user mode only simulation */
     uint32_t hflags;    /* CPU State */
     /* TMASK defines different execution modes */
-#define MIPS_HFLAG_TMASK  0x00FF
+#define MIPS_HFLAG_TMASK  0x01FF
 #define MIPS_HFLAG_MODE   0x0007 /* execution modes                    */
     /* The KSU flags must be the lowest bits in hflags. The flag order
        must be the same as defined for CP0 Status. This allows to use
@@ -429,16 +431,20 @@
 #define MIPS_HFLAG_CP0    0x0010 /* CP0 enabled                        */
 #define MIPS_HFLAG_FPU    0x0020 /* FPU enabled                        */
 #define MIPS_HFLAG_F64    0x0040 /* 64-bit FPU enabled                 */
-#define MIPS_HFLAG_RE     0x0080 /* Reversed endianness                */
+    /* True if the MIPS IV COP1X instructions can be used.  This also
+       controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S
+       and RSQRT.D.  */
+#define MIPS_HFLAG_COP1X  0x0080 /* COP1X instructions enabled         */
+#define MIPS_HFLAG_RE     0x0100 /* Reversed endianness                */
     /* If translation is interrupted between the branch instruction and
      * the delay slot, record what type of branch it is so that we can
      * resume translation properly.  It might be possible to reduce
      * this from three bits to two.  */
-#define MIPS_HFLAG_BMASK  0x0700
-#define MIPS_HFLAG_B      0x0100 /* Unconditional branch               */
-#define MIPS_HFLAG_BC     0x0200 /* Conditional branch                 */
-#define MIPS_HFLAG_BL     0x0300 /* Likely branch                      */
-#define MIPS_HFLAG_BR     0x0400 /* branch to register (can't link TB) */
+#define MIPS_HFLAG_BMASK  0x0e00
+#define MIPS_HFLAG_B      0x0200 /* Unconditional branch               */
+#define MIPS_HFLAG_BC     0x0400 /* Conditional branch                 */
+#define MIPS_HFLAG_BL     0x0600 /* Likely branch                      */
+#define MIPS_HFLAG_BR     0x0800 /* branch to register (can't link TB) */
     target_ulong btarget;        /* Jump / branch target               */
     int bcond;                   /* Branch condition (if needed)       */
 
@@ -521,40 +527,37 @@
     EXCP_SRESET,
     EXCP_DSS,
     EXCP_DINT,
+    EXCP_DDBL,
+    EXCP_DDBS,
     EXCP_NMI,
     EXCP_MCHECK,
-    EXCP_EXT_INTERRUPT,
+    EXCP_EXT_INTERRUPT, /* 8 */
     EXCP_DFWATCH,
-    EXCP_DIB, /* 8 */
+    EXCP_DIB,
     EXCP_IWATCH,
     EXCP_AdEL,
     EXCP_AdES,
     EXCP_TLBF,
     EXCP_IBE,
-    EXCP_DBp,
+    EXCP_DBp, /* 16 */
     EXCP_SYSCALL,
-    EXCP_BREAK, /* 16 */
+    EXCP_BREAK,
     EXCP_CpU,
     EXCP_RI,
     EXCP_OVERFLOW,
     EXCP_TRAP,
     EXCP_FPE,
-    EXCP_DDBS,
-    EXCP_DWATCH,
-    EXCP_LAE, /* 24 */
-    EXCP_SAE,
+    EXCP_DWATCH, /* 24 */
     EXCP_LTLBL,
     EXCP_TLBL,
     EXCP_TLBS,
     EXCP_DBE,
-    EXCP_DDBL,
     EXCP_THREAD,
-    EXCP_MTCP0         = 0x104, /* mtmsr instruction:               */
-                                /* may change privilege level       */
-    EXCP_BRANCH        = 0x108, /* branch instruction               */
-    EXCP_ERET          = 0x10C, /* return from interrupt            */
-    EXCP_SYSCALL_USER  = 0x110, /* System call in user mode only    */
-    EXCP_FLUSH         = 0x109,
+    EXCP_MDMX,
+    EXCP_C2E,
+    EXCP_CACHE, /* 32 */
+
+    EXCP_LAST = EXCP_CACHE,
 };
 
 int cpu_mips_exec(CPUMIPSState *s);

Modified: trunk/src/host/qemu-neo1973/target-mips/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/exec.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/exec.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -79,6 +79,20 @@
 void do_maddu (void);
 void do_msub (void);
 void do_msubu (void);
+void do_muls (void);
+void do_mulsu (void);
+void do_macc (void);
+void do_macchi (void);
+void do_maccu (void);
+void do_macchiu (void);
+void do_msac (void);
+void do_msachi (void);
+void do_msacu (void);
+void do_msachiu (void);
+void do_mulhi (void);
+void do_mulhiu (void);
+void do_mulshi (void);
+void do_mulshiu (void);
 #endif
 #if defined(TARGET_MIPS64)
 void do_ddiv (void);
@@ -223,8 +237,8 @@
 
 static always_inline void compute_hflags(CPUState *env)
 {
-    env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 |
-                     MIPS_HFLAG_FPU | MIPS_HFLAG_KSU);
+    env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
+                     MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU);
     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
         !(env->CP0_Status & (1 << CP0St_ERL)) &&
         !(env->hflags & MIPS_HFLAG_DM)) {
@@ -243,6 +257,20 @@
         env->hflags |= MIPS_HFLAG_FPU;
     if (env->CP0_Status & (1 << CP0St_FR))
         env->hflags |= MIPS_HFLAG_F64;
+    if (env->insn_flags & ISA_MIPS32R2) {
+        if (env->fpu->fcr0 & FCR0_F64)
+            env->hflags |= MIPS_HFLAG_COP1X;
+    } else if (env->insn_flags & ISA_MIPS32) {
+        if (env->hflags & MIPS_HFLAG_64)
+            env->hflags |= MIPS_HFLAG_COP1X;
+    } else if (env->insn_flags & ISA_MIPS4) {
+        /* All supported MIPS IV CPUs use the XX (CU3) to enable
+           and disable the MIPS IV extensions to the MIPS III ISA.
+           Some other MIPS IV CPUs ignore the bit, so the check here
+           would be too restrictive for them.  */
+        if (env->CP0_Status & (1 << CP0St_CU3))
+            env->hflags |= MIPS_HFLAG_COP1X;
+    }
 }
 
 #endif /* !defined(__QEMU_MIPS_EXEC_H__) */

Modified: trunk/src/host/qemu-neo1973/target-mips/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/helper.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/helper.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -148,10 +148,9 @@
         }
     } else if (address < 0xC000000000000000ULL) {
         /* xkphys */
-        /* XXX: Assumes PABITS = 36 (correct for MIPS64R1) */
         if (kernel_mode && KX &&
-            (address & 0x07FFFFFFFFFFFFFFULL) <= 0x0000000FFFFFFFFFULL) {
-            *physical = address & 0x0000000FFFFFFFFFULL;
+            (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
+            *physical = address & env->PAMask;
             *prot = PAGE_READ | PAGE_WRITE;
 	} else {
 	    ret = TLBRET_BADADDR;
@@ -319,20 +318,59 @@
     return ret;
 }
 
-#if defined(CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
+static const char * const excp_names[EXCP_LAST + 1] = {
+    [EXCP_RESET] = "reset",
+    [EXCP_SRESET] = "soft reset",
+    [EXCP_DSS] = "debug single step",
+    [EXCP_DINT] = "debug interrupt",
+    [EXCP_NMI] = "non-maskable interrupt",
+    [EXCP_MCHECK] = "machine check",
+    [EXCP_EXT_INTERRUPT] = "interrupt",
+    [EXCP_DFWATCH] = "deferred watchpoint",
+    [EXCP_DIB] = "debug instruction breakpoint",
+    [EXCP_IWATCH] = "instruction fetch watchpoint",
+    [EXCP_AdEL] = "address error load",
+    [EXCP_AdES] = "address error store",
+    [EXCP_TLBF] = "TLB refill",
+    [EXCP_IBE] = "instruction bus error",
+    [EXCP_DBp] = "debug breakpoint",
+    [EXCP_SYSCALL] = "syscall",
+    [EXCP_BREAK] = "break",
+    [EXCP_CpU] = "coprocessor unusable",
+    [EXCP_RI] = "reserved instruction",
+    [EXCP_OVERFLOW] = "arithmetic overflow",
+    [EXCP_TRAP] = "trap",
+    [EXCP_FPE] = "floating point",
+    [EXCP_DDBS] = "debug data break store",
+    [EXCP_DWATCH] = "data watchpoint",
+    [EXCP_LTLBL] = "TLB modify",
+    [EXCP_TLBL] = "TLB load",
+    [EXCP_TLBS] = "TLB store",
+    [EXCP_DBE] = "data bus error",
+    [EXCP_DDBL] = "debug data break load",
+    [EXCP_THREAD] = "thread",
+    [EXCP_MDMX] = "MDMX",
+    [EXCP_C2E] = "precise coprocessor 2",
+    [EXCP_CACHE] = "cache error",
+};
+#endif
+
 void do_interrupt (CPUState *env)
 {
-    env->exception_index = EXCP_NONE;
-}
-#else
-void do_interrupt (CPUState *env)
-{
+#if !defined(CONFIG_USER_ONLY)
     target_ulong offset;
     int cause = -1;
+    const char *name;
 
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n",
-                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index);
+        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
+            name = "unknown";
+        else
+            name = excp_names[env->exception_index];
+
+        fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
+                __func__, env->PC[env->current_tc], env->CP0_EPC, name);
     }
     if (env->exception_index == EXCP_EXT_INTERRUPT &&
         (env->hflags & MIPS_HFLAG_DM))
@@ -404,24 +442,14 @@
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
         env->PC[env->current_tc] = (int32_t)0xBFC00000;
         break;
-    case EXCP_MCHECK:
-        cause = 24;
-        goto set_EPC;
     case EXCP_EXT_INTERRUPT:
         cause = 0;
         if (env->CP0_Cause & (1 << CP0Ca_IV))
             offset = 0x200;
         goto set_EPC;
-    case EXCP_DWATCH:
-        cause = 23;
-        /* XXX: TODO: manage defered watch exceptions */
+    case EXCP_LTLBL:
+        cause = 1;
         goto set_EPC;
-    case EXCP_AdEL:
-        cause = 4;
-        goto set_EPC;
-    case EXCP_AdES:
-        cause = 5;
-        goto set_EPC;
     case EXCP_TLBL:
         cause = 2;
         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
@@ -438,6 +466,28 @@
                 offset = 0x000;
         }
         goto set_EPC;
+    case EXCP_TLBS:
+        cause = 3;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#if defined(TARGET_MIPS64)
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+
+            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
+        goto set_EPC;
+    case EXCP_AdEL:
+        cause = 4;
+        goto set_EPC;
+    case EXCP_AdES:
+        cause = 5;
+        goto set_EPC;
     case EXCP_IBE:
         cause = 6;
         goto set_EPC;
@@ -467,27 +517,29 @@
     case EXCP_FPE:
         cause = 15;
         goto set_EPC;
-    case EXCP_LTLBL:
-        cause = 1;
+    case EXCP_C2E:
+        cause = 18;
         goto set_EPC;
-    case EXCP_TLBS:
-        cause = 3;
-        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
-#if defined(TARGET_MIPS64)
-            int R = env->CP0_BadVAddr >> 62;
-            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
-            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
-            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
-
-            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
-                offset = 0x080;
-            else
-#endif
-                offset = 0x000;
-        }
+    case EXCP_MDMX:
+        cause = 22;
         goto set_EPC;
+    case EXCP_DWATCH:
+        cause = 23;
+        /* XXX: TODO: manage defered watch exceptions */
+        goto set_EPC;
+    case EXCP_MCHECK:
+        cause = 24;
+        goto set_EPC;
     case EXCP_THREAD:
         cause = 25;
+        goto set_EPC;
+    case EXCP_CACHE:
+        cause = 30;
+        if (env->CP0_Status & (1 << CP0St_BEV)) {
+            offset = 0x100;
+        } else {
+            offset = 0x20000100;
+        }
     set_EPC:
         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
             if (env->hflags & MIPS_HFLAG_BMASK) {
@@ -521,15 +573,15 @@
         exit(1);
     }
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n"
+        fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
                 "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
-                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index,
+                __func__, env->PC[env->current_tc], env->CP0_EPC, cause,
                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
                 env->CP0_DEPC);
     }
+#endif /* !defined(CONFIG_USER_ONLY) */
     env->exception_index = EXCP_NONE;
 }
-#endif /* !defined(CONFIG_USER_ONLY) */
 
 void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
 {

Modified: trunk/src/host/qemu-neo1973/target-mips/mips-defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/mips-defs.h	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/mips-defs.h	2008-01-07 07:17:44 UTC (rev 3778)
@@ -4,7 +4,7 @@
 /* If we want to use host float regs... */
 //#define USE_HOST_FLOAT_REGS
 
-/* real pages are variable size... */
+/* Real pages are variable size... */
 #define TARGET_PAGE_BITS 12
 #define MIPS_TLB_MAX 128
 
@@ -29,7 +29,7 @@
 #define		ISA_MIPS64	0x00000080
 #define		ISA_MIPS64R2	0x00000100
 
-/* MIPS ASE */
+/* MIPS ASEs. */
 #define		ASE_MIPS16	0x00001000
 #define		ASE_MIPS3D	0x00002000
 #define		ASE_MDMX	0x00004000
@@ -38,19 +38,23 @@
 #define		ASE_MT		0x00020000
 #define		ASE_SMARTMIPS	0x00040000
 
-/* Chip specific instructions.   */
-/* Currently void */
+/* Chip specific instructions. */
+#define		INSN_VR54XX	0x80000000
 
-/* MIPS CPU defines.  */
+/* MIPS CPU defines. */
 #define		CPU_MIPS1	(ISA_MIPS1)
 #define		CPU_MIPS2	(CPU_MIPS1 | ISA_MIPS2)
 #define		CPU_MIPS3	(CPU_MIPS2 | ISA_MIPS3)
 #define		CPU_MIPS4	(CPU_MIPS3 | ISA_MIPS4)
+#define		CPU_VR54XX	(CPU_MIPS4 | INSN_VR54XX)
+
 #define		CPU_MIPS5	(CPU_MIPS4 | ISA_MIPS5)
 
+/* MIPS Technologies "Release 1" */
 #define		CPU_MIPS32	(CPU_MIPS2 | ISA_MIPS32)
 #define		CPU_MIPS64	(CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
 
+/* MIPS Technologies "Release 2" */
 #define		CPU_MIPS32R2	(CPU_MIPS32 | ISA_MIPS32R2)
 #define		CPU_MIPS64R2	(CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
 

Modified: trunk/src/host/qemu-neo1973/target-mips/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/op.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -781,6 +781,90 @@
     FORCE_RET();
 }
 
+/* Multiplication variants of the vr54xx. */
+void op_muls (void)
+{
+    CALL_FROM_TB0(do_muls);
+    FORCE_RET();
+}
+
+void op_mulsu (void)
+{
+    CALL_FROM_TB0(do_mulsu);
+    FORCE_RET();
+}
+
+void op_macc (void)
+{
+    CALL_FROM_TB0(do_macc);
+    FORCE_RET();
+}
+
+void op_macchi (void)
+{
+    CALL_FROM_TB0(do_macchi);
+    FORCE_RET();
+}
+
+void op_maccu (void)
+{
+    CALL_FROM_TB0(do_maccu);
+    FORCE_RET();
+}
+void op_macchiu (void)
+{
+    CALL_FROM_TB0(do_macchiu);
+    FORCE_RET();
+}
+
+void op_msac (void)
+{
+    CALL_FROM_TB0(do_msac);
+    FORCE_RET();
+}
+
+void op_msachi (void)
+{
+    CALL_FROM_TB0(do_msachi);
+    FORCE_RET();
+}
+
+void op_msacu (void)
+{
+    CALL_FROM_TB0(do_msacu);
+    FORCE_RET();
+}
+
+void op_msachiu (void)
+{
+    CALL_FROM_TB0(do_msachiu);
+    FORCE_RET();
+}
+
+void op_mulhi (void)
+{
+    CALL_FROM_TB0(do_mulhi);
+    FORCE_RET();
+}
+
+void op_mulhiu (void)
+{
+    CALL_FROM_TB0(do_mulhiu);
+    FORCE_RET();
+}
+
+void op_mulshi (void)
+{
+    CALL_FROM_TB0(do_mulshi);
+    FORCE_RET();
+}
+
+void op_mulshiu (void)
+{
+    CALL_FROM_TB0(do_mulshiu);
+    FORCE_RET();
+}
+
 #else /* TARGET_LONG_BITS > HOST_LONG_BITS */
 
 static always_inline uint64_t get_HILO (void)
@@ -795,6 +879,18 @@
     env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
+static always_inline void set_HIT0_LO (uint64_t HILO)
+{
+    env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
+static always_inline void set_HI_LOT0 (uint64_t HILO)
+{
+    T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
 void op_mult (void)
 {
     set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
@@ -842,6 +938,92 @@
     set_HILO(get_HILO() - tmp);
     FORCE_RET();
 }
+
+/* Multiplication variants of the vr54xx. */
+void op_muls (void)
+{
+    set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_mulsu (void)
+{
+    set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
+void op_macc (void)
+{
+    set_HI_LOT0(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_macchi (void)
+{
+    set_HIT0_LO(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_maccu (void)
+{
+    set_HI_LOT0(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
+void op_macchiu (void)
+{
+    set_HIT0_LO(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
+void op_msac (void)
+{
+    set_HI_LOT0(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_msachi (void)
+{
+    set_HIT0_LO(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_msacu (void)
+{
+    set_HI_LOT0(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
+void op_msachiu (void)
+{
+    set_HIT0_LO(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
+void op_mulhi (void)
+{
+    set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    FORCE_RET();
+}
+
+void op_mulhiu (void)
+{
+    set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    FORCE_RET();
+}
+
+void op_mulshi (void)
+{
+    set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+    FORCE_RET();
+}
+
+void op_mulshiu (void)
+{
+    set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+    FORCE_RET();
+}
+
 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
 
 #if defined(TARGET_MIPS64)
@@ -1563,7 +1745,7 @@
 
 void op_mtc0_entrylo0 (void)
 {
-    /* Large physaddr not implemented */
+    /* Large physaddr (PABITS) not implemented */
     /* 1k pages not implemented */
     env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
     FORCE_RET();
@@ -1700,7 +1882,7 @@
 
 void op_mtc0_entrylo1 (void)
 {
-    /* Large physaddr not implemented */
+    /* Large physaddr (PABITS) not implemented */
     /* 1k pages not implemented */
     env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
     FORCE_RET();
@@ -1722,7 +1904,7 @@
 void op_mtc0_pagegrain (void)
 {
     /* SmartMIPS not implemented */
-    /* Large physaddr not implemented */
+    /* Large physaddr (PABITS) not implemented */
     /* 1k pages not implemented */
     env->CP0_PageGrain = 0;
     FORCE_RET();

Modified: trunk/src/host/qemu-neo1973/target-mips/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -172,6 +172,18 @@
     env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
+static always_inline void set_HIT0_LO (uint64_t HILO)
+{
+    env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    T0 = env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
+static always_inline void set_HI_LOT0 (uint64_t HILO)
+{
+    T0 = env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
+}
+
 void do_mult (void)
 {
     set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
@@ -213,8 +225,79 @@
     tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
     set_HILO(get_HILO() - tmp);
 }
-#endif
 
+/* Multiplication variants of the vr54xx. */
+void do_muls (void)
+{
+    set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_mulsu (void)
+{
+    set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_macc (void)
+{
+    set_HI_LOT0(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_macchi (void)
+{
+    set_HIT0_LO(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_maccu (void)
+{
+    set_HI_LOT0(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_macchiu (void)
+{
+    set_HIT0_LO(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_msac (void)
+{
+    set_HI_LOT0(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_msachi (void)
+{
+    set_HIT0_LO(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_msacu (void)
+{
+    set_HI_LOT0(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_msachiu (void)
+{
+    set_HIT0_LO(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+
+void do_mulhi (void)
+{
+    set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+}
+
+void do_mulhiu (void)
+{
+    set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+}
+
+void do_mulshi (void)
+{
+    set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
+}
+
+void do_mulshiu (void)
+{
+    set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
+}
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
 #if HOST_LONG_BITS < 64
 void do_div (void)
 {
@@ -230,9 +313,16 @@
 void do_ddiv (void)
 {
     if (T1 != 0) {
-        lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
-        env->LO[0][env->current_tc] = res.quot;
-        env->HI[0][env->current_tc] = res.rem;
+        int64_t arg0 = (int64_t)T0;
+        int64_t arg1 = (int64_t)T1;
+        if (arg0 == ((int64_t)-1 << 63) && arg1 == (int64_t)-1) {
+            env->LO[0][env->current_tc] = arg0;
+            env->HI[0][env->current_tc] = 0;
+        } else {
+            lldiv_t res = lldiv(arg0, arg1);
+            env->LO[0][env->current_tc] = res.quot;
+            env->HI[0][env->current_tc] = res.rem;
+        }
     }
 }
 

Modified: trunk/src/host/qemu-neo1973/target-mips/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/translate.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -214,6 +214,26 @@
     OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
 };
 
+/* Multiplication variants of the vr54xx. */
+#define MASK_MUL_VR54XX(op)   MASK_SPECIAL(op) | (op & (0x1F << 6))
+
+enum {
+    OPC_VR54XX_MULS    = (0x03 << 6) | OPC_MULT,
+    OPC_VR54XX_MULSU   = (0x03 << 6) | OPC_MULTU,
+    OPC_VR54XX_MACC    = (0x05 << 6) | OPC_MULT,
+    OPC_VR54XX_MACCU   = (0x05 << 6) | OPC_MULTU,
+    OPC_VR54XX_MSAC    = (0x07 << 6) | OPC_MULT,
+    OPC_VR54XX_MSACU   = (0x07 << 6) | OPC_MULTU,
+    OPC_VR54XX_MULHI   = (0x09 << 6) | OPC_MULT,
+    OPC_VR54XX_MULHIU  = (0x09 << 6) | OPC_MULTU,
+    OPC_VR54XX_MULSHI  = (0x0B << 6) | OPC_MULT,
+    OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
+    OPC_VR54XX_MACCHI  = (0x0D << 6) | OPC_MULT,
+    OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU,
+    OPC_VR54XX_MSACHI  = (0x0F << 6) | OPC_MULT,
+    OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU,
+};
+
 /* REGIMM (rt field) opcodes */
 #define MASK_REGIMM(op)    MASK_OP_MAJOR(op) | (op & (0x1F << 16))
 
@@ -774,9 +794,22 @@
         generate_exception_err(ctx, EXCP_CpU, 1);
 }
 
+/* Verify that the processor is running with COP1X instructions enabled.
+   This is associated with the nabla symbol in the MIPS32 and MIPS64
+   opcode tables.  */
+
+static always_inline void check_cop1x(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* Verify that the processor is running with 64-bit floating-point
+   operations enabled.  */
+
 static always_inline void check_cp1_64bitmode(DisasContext *ctx)
 {
-    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64)))
+    if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X)))
         generate_exception(ctx, EXCP_RI);
 }
 
@@ -1530,6 +1563,80 @@
     MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
 }
 
+static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
+                            int rd, int rs, int rt)
+{
+    const char *opn = "mul vr54xx";
+
+    GEN_LOAD_REG_T0(rs);
+    GEN_LOAD_REG_T1(rt);
+
+    switch (opc) {
+    case OPC_VR54XX_MULS:
+        gen_op_muls();
+        opn = "muls";
+	break;
+    case OPC_VR54XX_MULSU:
+        gen_op_mulsu();
+        opn = "mulsu";
+	break;
+    case OPC_VR54XX_MACC:
+        gen_op_macc();
+        opn = "macc";
+	break;
+    case OPC_VR54XX_MACCU:
+        gen_op_maccu();
+        opn = "maccu";
+	break;
+    case OPC_VR54XX_MSAC:
+        gen_op_msac();
+        opn = "msac";
+	break;
+    case OPC_VR54XX_MSACU:
+        gen_op_msacu();
+        opn = "msacu";
+	break;
+    case OPC_VR54XX_MULHI:
+        gen_op_mulhi();
+        opn = "mulhi";
+	break;
+    case OPC_VR54XX_MULHIU:
+        gen_op_mulhiu();
+        opn = "mulhiu";
+	break;
+    case OPC_VR54XX_MULSHI:
+        gen_op_mulshi();
+        opn = "mulshi";
+	break;
+    case OPC_VR54XX_MULSHIU:
+        gen_op_mulshiu();
+        opn = "mulshiu";
+	break;
+    case OPC_VR54XX_MACCHI:
+        gen_op_macchi();
+        opn = "macchi";
+	break;
+    case OPC_VR54XX_MACCHIU:
+        gen_op_macchiu();
+        opn = "macchiu";
+	break;
+    case OPC_VR54XX_MSACHI:
+        gen_op_msachi();
+        opn = "msachi";
+	break;
+    case OPC_VR54XX_MSACHIU:
+        gen_op_msachiu();
+        opn = "msachiu";
+	break;
+    default:
+        MIPS_INVAL("mul vr54xx");
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    GEN_STORE_T0_REG(rd);
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
 static void gen_cl (DisasContext *ctx, uint32_t opc,
                     int rd, int rs)
 {
@@ -5084,12 +5191,14 @@
         opn = "movn.s";
         break;
     case FOP(21, 16):
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_recip_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "recip.s";
         break;
     case FOP(22, 16):
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_rsqrt_s();
         GEN_STORE_FTN_FREG(fd, WT2);
@@ -5172,7 +5281,7 @@
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         if (ctx->opcode & (1 << 6)) {
-            check_cp1_64bitmode(ctx);
+            check_cop1x(ctx);
             gen_cmpabs_s(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
@@ -5325,14 +5434,14 @@
         opn = "movn.d";
         break;
     case FOP(21, 17):
-        check_cp1_registers(ctx, fs | fd);
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_recip_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "recip.d";
         break;
     case FOP(22, 17):
-        check_cp1_registers(ctx, fs | fd);
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_rsqrt_d();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -5387,7 +5496,8 @@
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         if (ctx->opcode & (1 << 6)) {
-            check_cp1_64bitmode(ctx);
+            check_cop1x(ctx);
+            check_cp1_registers(ctx, fs | ft);
             gen_cmpabs_d(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
@@ -5720,8 +5830,6 @@
     const char *opn = "extended float load/store";
     int store = 0;
 
-    /* All of those work only on 64bit FPUs. */
-    check_cp1_64bitmode(ctx);
     if (base == 0) {
         if (index == 0)
             gen_op_reset_T0();
@@ -5738,33 +5846,41 @@
        memory access. */
     switch (opc) {
     case OPC_LWXC1:
+        check_cop1x(ctx);
         op_ldst(lwc1);
         GEN_STORE_FTN_FREG(fd, WT0);
         opn = "lwxc1";
         break;
     case OPC_LDXC1:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd);
         op_ldst(ldc1);
         GEN_STORE_FTN_FREG(fd, DT0);
         opn = "ldxc1";
         break;
     case OPC_LUXC1:
+        check_cp1_64bitmode(ctx);
         op_ldst(luxc1);
         GEN_STORE_FTN_FREG(fd, DT0);
         opn = "luxc1";
         break;
     case OPC_SWXC1:
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         op_ldst(swc1);
         opn = "swxc1";
         store = 1;
         break;
     case OPC_SDXC1:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         op_ldst(sdc1);
         opn = "sdxc1";
         store = 1;
         break;
     case OPC_SUXC1:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(DT0, fs);
         op_ldst(suxc1);
         opn = "suxc1";
@@ -5784,10 +5900,9 @@
 {
     const char *opn = "flt3_arith";
 
-    /* All of those work only on 64bit FPUs. */
-    check_cp1_64bitmode(ctx);
     switch (opc) {
     case OPC_ALNV_PS:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_REG_T0(fr);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
@@ -5796,6 +5911,7 @@
         opn = "alnv.ps";
         break;
     case OPC_MADD_S:
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5804,6 +5920,8 @@
         opn = "madd.s";
         break;
     case OPC_MADD_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5812,6 +5930,7 @@
         opn = "madd.d";
         break;
     case OPC_MADD_PS:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5824,6 +5943,7 @@
         opn = "madd.ps";
         break;
     case OPC_MSUB_S:
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5832,6 +5952,8 @@
         opn = "msub.s";
         break;
     case OPC_MSUB_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5840,6 +5962,7 @@
         opn = "msub.d";
         break;
     case OPC_MSUB_PS:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5852,6 +5975,7 @@
         opn = "msub.ps";
         break;
     case OPC_NMADD_S:
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5860,6 +5984,8 @@
         opn = "nmadd.s";
         break;
     case OPC_NMADD_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5868,6 +5994,7 @@
         opn = "nmadd.d";
         break;
     case OPC_NMADD_PS:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5880,6 +6007,7 @@
         opn = "nmadd.ps";
         break;
     case OPC_NMSUB_S:
+        check_cop1x(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5888,6 +6016,8 @@
         opn = "nmsub.s";
         break;
     case OPC_NMSUB_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5896,6 +6026,7 @@
         opn = "nmsub.d";
         break;
     case OPC_NMSUB_PS:
+        check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5973,7 +6104,12 @@
             gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_MULT ... OPC_DIVU:
-            gen_muldiv(ctx, op1, rs, rt);
+            if (sa) {
+                check_insn(env, ctx, INSN_VR54XX);
+                op1 = MASK_MUL_VR54XX(ctx->opcode);
+                gen_mul_vr54xx(ctx, op1, rd, rs, rt);
+            } else
+                gen_muldiv(ctx, op1, rs, rt);
             break;
         case OPC_JR ... OPC_JALR:
             gen_compute_branch(ctx, op1, rs, rd, sa);
@@ -6366,6 +6502,7 @@
 #endif
             case OPC_BC1ANY2:
             case OPC_BC1ANY4:
+                check_cop1x(ctx);
                 check_insn(env, ctx, ASE_MIPS3D);
                 /* fall through */
             case OPC_BC1:

Modified: trunk/src/host/qemu-neo1973/target-mips/translate_init.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate_init.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-mips/translate_init.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -21,12 +21,9 @@
 
 /* CPU / CPU family specific config register values. */
 
-/* Have config1, is MIPS32R1, uses TLB, no virtual icache,
-   uncached coherency */
+/* Have config1, uncached coherency */
 #define MIPS_CONFIG0                                              \
-  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
-   (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) |    \
-   (0x2 << CP0C0_K0))
+  ((1 << CP0C0_M) | (0x2 << CP0C0_K0))
 
 /* Have config2, no coprocessor2 attached, no MDMX support attached,
    no performance counters, watch registers present,
@@ -41,7 +38,7 @@
 #define MIPS_CONFIG2                                              \
 ((1 << CP0C2_M))
 
-/* No config4, no DSP ASE, no large physaddr,
+/* No config4, no DSP ASE, no large physaddr (PABITS),
    no external interrupt controller, no vectored interupts,
    no 1kb pages, no SmartMIPS ASE, no trace logic */
 #define MIPS_CONFIG3                                              \
@@ -53,6 +50,18 @@
    Define a major version 1, minor version 0. */
 #define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
 
+/* MMU types, the first four entries have the same layout as the
+   CP0C0_MT field.  */
+enum mips_mmu_types {
+    MMU_TYPE_NONE,
+    MMU_TYPE_R4000,
+    MMU_TYPE_RESERVED,
+    MMU_TYPE_FMT,
+    MMU_TYPE_R3000,
+    MMU_TYPE_R6000,
+    MMU_TYPE_R8000
+};
+
 struct mips_def_t {
     const unsigned char *name;
     int32_t CP0_PRid;
@@ -69,6 +78,7 @@
     int32_t CP0_SRSCtl;
     int32_t CP1_fcr0;
     int32_t SEGBITS;
+    int32_t PABITS;
     int32_t CP0_SRSConf0_rw_bitmask;
     int32_t CP0_SRSConf0;
     int32_t CP0_SRSConf1_rw_bitmask;
@@ -80,6 +90,7 @@
     int32_t CP0_SRSConf4_rw_bitmask;
     int32_t CP0_SRSConf4;
     int insn_flags;
+    enum mips_mmu_types mmu_type;
 };
 
 /*****************************************************************************/
@@ -89,7 +100,7 @@
     {
         .name = "4Kc",
         .CP0_PRid = 0x00018000,
-        .CP0_Config0 = MIPS_CONFIG0,
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -98,15 +109,17 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "4Km",
         .CP0_PRid = 0x00018300,
         /* Config1 implemented, fixed mapping MMU,
            no virtual icache, uncached coherency. */
-        .CP0_Config0 = (1 << CP0C0_M) |
-                    (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0),
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -115,12 +128,15 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
     },
     {
         .name = "4KEcR1",
         .CP0_PRid = 0x00018400,
-        .CP0_Config0 = MIPS_CONFIG0,
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -129,15 +145,15 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "4KEmR1",
         .CP0_PRid = 0x00018500,
-        /* Config1 implemented, fixed mapping MMU,
-           no virtual icache, uncached coherency. */
-        .CP0_Config0 = (1 << CP0C0_M) |
-                    (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0),
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -146,12 +162,16 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
     },
     {
         .name = "4KEc",
         .CP0_PRid = 0x00019000,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -160,15 +180,16 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "4KEm",
         .CP0_PRid = 0x00019100,
-        /* Config1 implemented, MIPS32R2, fixed mapping MMU,
-           no virtual icache, uncached coherency. */
-        .CP0_Config0 = (1 << CP0C0_M) | (0x1 << CP0C0_AR) |
-                    (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_FMT << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -177,12 +198,16 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
     },
     {
         .name = "24Kc",
         .CP0_PRid = 0x00019300,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -192,12 +217,16 @@
         .CCRes = 2,
         /* No DSP implemented. */
         .CP0_Status_rw_bitmask = 0x1278FF1F,
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "24Kf",
         .CP0_PRid = 0x00019300,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -209,12 +238,16 @@
         .CP0_Status_rw_bitmask = 0x3678FF1F,
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "34Kf",
         .CP0_PRid = 0x00019500,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
 		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
@@ -249,30 +282,50 @@
         .CP0_SRSConf4_rw_bitmask = 0x3fffffff,
         .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
                     (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+        .SEGBITS = 32,
+        .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT,
+        .mmu_type = MMU_TYPE_R4000,
     },
 #if defined(TARGET_MIPS64)
     {
         .name = "R4000",
         .CP0_PRid = 0x00000400,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
-        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
-		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
-		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
-        .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3,
+        /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
+        .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
+	/* Note: Config1 is only used internally, the R4000 has only Config0. */
+        .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
         .SYNCI_Step = 16,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x3678FFFF,
-	/* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */
+	/* The R4000 has a full 64bit FPU but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 40,
+        .PABITS = 36,
         .insn_flags = CPU_MIPS3,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
+        .name = "VR5432",
+        .CP0_PRid = 0x00005400,
+        /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
+        .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
+        .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x3678FFFF,
+        /* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .PABITS = 32,
+        .insn_flags = CPU_VR54XX,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
         .name = "5Kc",
         .CP0_PRid = 0x00018100,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) |
 		    (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
@@ -283,12 +336,15 @@
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x32F8FFFF,
         .SEGBITS = 42,
+        .PABITS = 36,
         .insn_flags = CPU_MIPS64,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "5Kf",
         .CP0_PRid = 0x00018100,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
 		    (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
 		    (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
@@ -302,14 +358,17 @@
         .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 42,
+        .PABITS = 36,
         .insn_flags = CPU_MIPS64,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
         .name = "20Kc",
 	/* We emulate a later version of the 20Kc, earlier ones had a broken
            WAIT instruction. */
         .CP0_PRid = 0x000182a0,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (1 << CP0C0_VI),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                    (MMU_TYPE_R4000 << CP0C0_MT) | (1 << CP0C0_VI),
         .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
 		    (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
 		    (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
@@ -324,28 +383,36 @@
                     (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 40,
+        .PABITS = 36,
         .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
+        .mmu_type = MMU_TYPE_R4000,
     },
     {
 	/* A generic CPU providing MIPS64 Release 2 features.
            FIXME: Eventually this should be replaced by a real CPU model. */
         .name = "MIPS64R2-generic",
         .CP0_PRid = 0x00010000,
-        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (0x1 << CP0C0_AR),
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
         .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
 		    (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
 		    (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
 		    (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
         .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x36FBFFFF,
-        .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_L) |
-                    (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
-                    (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
-        .SEGBITS = 40,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
+                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
+                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 42,
+        /* The architectural limit is 59, but we have hardcoded 36 bit
+           in some places...
+        .PABITS = 59, */ /* the architectural limit */
+        .PABITS = 36,
         .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
+        .mmu_type = MMU_TYPE_R4000,
     },
 #endif
 };
@@ -399,20 +466,19 @@
 {
     env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext));
 
-    /* There are more full-featured MMU variants in older MIPS CPUs,
-       R3000, R6000 and R8000 come to mind. If we ever support them,
-       this check will need to look up a different place than those
-       newfangled config registers. */
-    switch ((env->CP0_Config0 >> CP0C0_MT) & 3) {
-        case 0:
+    switch (def->mmu_type) {
+        case MMU_TYPE_NONE:
             no_mmu_init(env, def);
             break;
-        case 1:
+        case MMU_TYPE_R4000:
             r4k_mmu_init(env, def);
             break;
-        case 3:
+        case MMU_TYPE_FMT:
             fixed_mmu_init(env, def);
             break;
+        case MMU_TYPE_R3000:
+        case MMU_TYPE_R6000:
+        case MMU_TYPE_R8000:
         default:
             cpu_abort(env, "MMU type not supported\n");
     }
@@ -477,17 +543,16 @@
     env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask;
     env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
     env->CP0_SRSCtl = def->CP0_SRSCtl;
+    env->SEGBITS = def->SEGBITS;
+    env->SEGMask = (target_ulong)((1ULL << def->SEGBITS) - 1);
 #if defined(TARGET_MIPS64)
-    if (def->insn_flags & ISA_MIPS3)
-    {
+    if (def->insn_flags & ISA_MIPS3) {
         env->hflags |= MIPS_HFLAG_64;
-        env->SEGBITS = def->SEGBITS;
-        env->SEGMask = (3ULL << 62) | ((1ULL << def->SEGBITS) - 1);
-    } else {
-        env->SEGBITS = 32;
-        env->SEGMask = 0xFFFFFFFF;
+        env->SEGMask |= 3ULL << 62;
     }
 #endif
+    env->PABITS = def->PABITS;
+    env->PAMask = (target_ulong)((1ULL << def->PABITS) - 1);
     env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask;
     env->CP0_SRSConf0 = def->CP0_SRSConf0;
     env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask;

Modified: trunk/src/host/qemu-neo1973/target-sparc/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/helper.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-sparc/helper.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -129,7 +129,7 @@
 
     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
     /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde_ptr = ((env->mmuregs[1] & ~63)<< 4) + (env->mmuregs[2] << 2);
     pde = ldl_phys(pde_ptr);
 
     /* Ctx pde */

Modified: trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/op_helper.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/target-sparc/op_helper.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -6,6 +6,7 @@
 //#define DEBUG_MXCC
 //#define DEBUG_UNALIGNED
 //#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
 
 #ifdef DEBUG_MMU
 #define DPRINTF_MMU(fmt, args...) \
@@ -21,6 +22,13 @@
 #define DPRINTF_MXCC(fmt, args...)
 #endif
 
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, args...) \
+do { printf("ASI: " fmt , ##args); } while (0)
+#else
+#define DPRINTF_ASI(fmt, args...)
+#endif
+
 void raise_exception(int tt)
 {
     env->exception_index = tt;
@@ -229,11 +237,34 @@
 }
 #endif
 
+#ifdef DEBUG_ASI
+static void dump_asi(const char * txt, uint32_t addr, int asi, int size,
+                     uint32_t r1, uint32_t r2)
+{
+    switch (size)
+    {
+    case 1:
+        DPRINTF_ASI("%s %08x asi 0x%02x = %02x\n", txt, addr, asi, r1 & 0xff);
+        break;
+    case 2:
+        DPRINTF_ASI("%s %08x asi 0x%02x = %04x\n", txt, addr, asi, r1 & 0xffff);
+        break;
+    case 4:
+        DPRINTF_ASI("%s %08x asi 0x%02x = %08x\n", txt, addr, asi, r1);
+        break;
+    case 8:
+        DPRINTF_ASI("%s %08x asi 0x%02x = %016llx\n", txt, addr, asi,
+                    r2 | ((uint64_t)r1 << 32));
+        break;
+    }
+}
+#endif
+
 void helper_ld_asi(int asi, int size, int sign)
 {
     uint32_t ret = 0;
     uint64_t tmp;
-#ifdef DEBUG_MXCC
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
     uint32_t last_T0 = T0;
 #endif
 
@@ -306,6 +337,10 @@
             DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
         }
         break;
+    case 5: // Turbosparc ITLB Diagnostic
+    case 6: // Turbosparc DTLB Diagnostic
+    case 7: // Turbosparc IOTLB Diagnostic
+        break;
     case 9: /* Supervisor code access */
         switch(size) {
         case 1:
@@ -387,8 +422,7 @@
             break;
         }
         break;
-    case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
-    case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
         switch(size) {
         case 1:
             ret = ldub_phys((target_phys_addr_t)T0
@@ -411,12 +445,15 @@
             break;
         }
         break;
+    case 0x30: // Turbosparc secondary cache diagnostic
+    case 0x31: // Turbosparc RAM snoop
+    case 0x32: // Turbosparc page table descriptor diagnostic
     case 0x39: /* data cache diagnostic register */
         ret = 0;
         break;
-    case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
+    case 8: /* User code access, XXX */
     default:
-        do_unassigned_access(T0, 0, 0, 1);
+        do_unassigned_access(T0, 0, 0, asi);
         ret = 0;
         break;
     }
@@ -435,6 +472,9 @@
     }
     else
         T1 = ret;
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_T0, asi, size, T1, T0);
+#endif
 }
 
 void helper_st_asi(int asi, int size)
@@ -542,8 +582,8 @@
 #ifdef DEBUG_MMU
             dump_mmu(env);
 #endif
-            return;
         }
+        break;
     case 4: /* write MMU regs */
         {
             int reg = (T0 >> 8) & 0x1f;
@@ -587,8 +627,12 @@
 #ifdef DEBUG_MMU
             dump_mmu(env);
 #endif
-            return;
         }
+        break;
+    case 5: // Turbosparc ITLB Diagnostic
+    case 6: // Turbosparc DTLB Diagnostic
+    case 7: // Turbosparc IOTLB Diagnostic
+        break;
     case 0xa: /* User data access */
         switch(size) {
         case 1:
@@ -646,7 +690,7 @@
                 stl_kernel(dst, temp);
             }
         }
-        return;
+        break;
     case 0x1f: /* Block fill, stda access */
         {
             // value (T1, T2)
@@ -661,7 +705,7 @@
             for (i = 0; i < 32; i += 8, dst += 8)
                 stq_kernel(dst, val);
         }
-        return;
+        break;
     case 0x20: /* MMU passthrough */
         {
             switch(size) {
@@ -680,9 +724,8 @@
                 break;
             }
         }
-        return;
-    case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
-    case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
         {
             switch(size) {
             case 1:
@@ -705,21 +748,25 @@
                 break;
             }
         }
-        return;
-    case 0x30: /* store buffer tags */
-    case 0x31: /* store buffer data or Ross RT620 I-cache flush */
-    case 0x32: /* store buffer control */
+        break;
+    case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
+    case 0x31: // store buffer data, Ross RT620 I-cache flush or
+               // Turbosparc snoop RAM
+    case 0x32: // store buffer control or Turbosparc page table descriptor diagnostic
     case 0x36: /* I-cache flash clear */
     case 0x37: /* D-cache flash clear */
     case 0x38: /* breakpoint diagnostics */
     case 0x4c: /* breakpoint action */
         break;
+    case 8: /* User code access, XXX */
     case 9: /* Supervisor code access, XXX */
-    case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
     default:
-        do_unassigned_access(T0, 1, 0, 1);
-        return;
+        do_unassigned_access(T0, 1, 0, asi);
+        break;
     }
+#ifdef DEBUG_ASI
+    dump_asi("write", T0, asi, size, T1, T2);
+#endif
 }
 
 #endif /* CONFIG_USER_ONLY */
@@ -1646,13 +1693,66 @@
 }
 
 #ifdef TARGET_SPARC64
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x50] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_TMISS] = "Instruction Access MMU Miss",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CLRWIN] = "Clean Windows",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_DMISS] = "Data Access MMU Miss",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DPROT] = "Data Protection Error",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_PRIV_ACT] = "Privileged Action",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
 void do_interrupt(int intno)
 {
 #ifdef DEBUG_PCALL
     if (loglevel & CPU_LOG_INT) {
         static int count;
-        fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
-                count, intno,
+        const char *name;
+
+        if (intno < 0 || intno >= 0x180 || (intno > 0x4f && intno < 0x80))
+            name = "Unknown";
+        else if (intno >= 0x100)
+            name = "Trap Instruction";
+        else if (intno >= 0xc0)
+            name = "Window Fill";
+        else if (intno >= 0x80)
+            name = "Window Spill";
+        else {
+            name = excp_names[intno];
+            if (!name)
+                name = "Unknown";
+        }
+
+        fprintf(logfile, "%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+                " SP=%016" PRIx64 "\n",
+                count, name, intno,
                 env->pc,
                 env->npc, env->regwptr[6]);
         cpu_dump_state(env, logfile, fprintf, 0);
@@ -1705,6 +1805,41 @@
     env->exception_index = 0;
 }
 #else
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_WIN_OVF] = "Window Overflow",
+    [TT_WIN_UNF] = "Window Underflow",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
 void do_interrupt(int intno)
 {
     int cwp;
@@ -1712,8 +1847,20 @@
 #ifdef DEBUG_PCALL
     if (loglevel & CPU_LOG_INT) {
         static int count;
-        fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
-                count, intno,
+        const char *name;
+
+        if (intno < 0 || intno >= 0x100)
+            name = "Unknown";
+        else if (intno >= 0x80)
+            name = "Trap Instruction";
+        else {
+            name = excp_names[intno];
+            if (!name)
+                name = "Unknown";
+        }
+
+        fprintf(logfile, "%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+                count, name, intno,
                 env->pc,
                 env->npc, env->regwptr[6]);
         cpu_dump_state(env, logfile, fprintf, 0);
@@ -1832,6 +1979,17 @@
        generated code */
     saved_env = env;
     env = cpu_single_env;
+#ifdef DEBUG_UNASSIGNED
+    if (is_asi)
+        printf("Unassigned mem %s access to " TARGET_FMT_plx " asi 0x%02x from "
+               TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", addr, is_asi,
+               env->pc);
+    else
+        printf("Unassigned mem %s access to " TARGET_FMT_plx " from "
+               TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", addr, env->pc);
+#endif
     if (env->mmuregs[3]) /* Fault status register */
         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
     if (is_asi)
@@ -1845,10 +2003,6 @@
     env->mmuregs[3] |= (5 << 2) | 2;
     env->mmuregs[4] = addr; /* Fault address register */
     if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
-#ifdef DEBUG_UNASSIGNED
-        printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
-               "\n", addr, env->pc);
-#endif
         if (is_exec)
             raise_exception(TT_CODE_ACCESS);
         else

Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c	2008-01-06 01:02:26 UTC (rev 3777)
+++ trunk/src/host/qemu-neo1973/vl.c	2008-01-07 07:17:44 UTC (rev 3778)
@@ -1,7 +1,7 @@
 /*
  * QEMU System Emulator
  *
- * Copyright (c) 2003-2007 Fabrice Bellard
+ * Copyright (c) 2003-2008 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -828,7 +828,7 @@
 };
 
 #define ALARM_FLAG_DYNTICKS  0x1
-#define ALARM_FLAG_MODIFIED  0x2
+#define ALARM_FLAG_EXPIRED   0x2
 
 static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
 {
@@ -840,11 +840,6 @@
     if (!alarm_has_dynticks(t))
         return;
 
-    if (!(t->flags & ALARM_FLAG_MODIFIED))
-        return;
-
-    t->flags &= ~(ALARM_FLAG_MODIFIED);
-
     t->rearm(t);
 }
 
@@ -1018,8 +1013,6 @@
 {
     QEMUTimer **pt, *t;
 
-    alarm_timer->flags |= ALARM_FLAG_MODIFIED;
-
     /* NOTE: this code must be signal safe because
        qemu_timer_expired() can be called from a signal. */
     pt = &active_timers[ts->clock->type];
@@ -1058,6 +1051,11 @@
     ts->expire_time = expire_time;
     ts->next = *pt;
     *pt = ts;
+
+    /* Rearm if necessary  */
+    if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 &&
+        pt == &active_timers[ts->clock->type])
+        qemu_rearm_alarm_timer(alarm_timer);
 }
 
 #ifdef TIMER_DEBUG
@@ -1218,12 +1216,13 @@
 #endif
         CPUState *env = next_cpu;
 
+        alarm_timer->flags |= ALARM_FLAG_EXPIRED;
+
         /* FIXME Ugly hack only to make usb-gadgetfs work */
         if (!alarm_has_dynticks(alarm_timer) && !cpu_single_env)
             return;
 
         if (env) {
-            alarm_timer->flags |= ALARM_FLAG_MODIFIED;
             /* stop the currently executing cpu because a timer occured */
             cpu_interrupt(env, CPU_INTERRUPT_EXIT);
 #ifdef USE_KQEMU
@@ -1408,7 +1407,7 @@
 
     if (!active_timers[QEMU_TIMER_REALTIME] &&
                 !active_timers[QEMU_TIMER_VIRTUAL])
-            return;
+        return;
 
     nearest_delta_us = qemu_next_deadline();
 
@@ -1535,7 +1534,7 @@
 
     if (!active_timers[QEMU_TIMER_REALTIME] &&
                 !active_timers[QEMU_TIMER_VIRTUAL])
-            return;
+        return;
 
     nearest_delta_us = qemu_next_deadline();
     nearest_delta_us /= 1000;
@@ -7651,7 +7650,10 @@
     qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
                     qemu_get_clock(rt_clock));
 
-    qemu_rearm_alarm_timer(alarm_timer);
+    if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
+        alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED);
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
 
     /* Check bottom-halves last in case any of the earlier events triggered
        them.  */
@@ -7741,7 +7743,7 @@
 
 static void help(int exitcode)
 {
-    printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
+    printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
            "usage: %s [options] [disk_image]\n"
            "\n"
            "'disk_image' is a raw hard image image for IDE hard disk 0\n"
@@ -8150,6 +8152,9 @@
     qemu_register_machine(&ss10_machine);
     qemu_register_machine(&ss600mp_machine);
     qemu_register_machine(&ss20_machine);
+    qemu_register_machine(&ss2_machine);
+    qemu_register_machine(&ss1000_machine);
+    qemu_register_machine(&ss2000_machine);
 #endif
 #elif defined(TARGET_ARM)
     qemu_register_machine(&integratorcp_machine);





More information about the commitlog mailing list