qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH][SPARC] Rework ASI instructions


From: Aurelien Jarno
Subject: [Qemu-devel] [PATCH][SPARC] Rework ASI instructions
Date: Fri, 21 Sep 2007 18:04:10 +0200
User-agent: Mutt/1.5.13 (2006-08-11)

Hi all,

The current implementation of ASI instructions on the SPARC target is
correct for most cases on SPARC32, but is completely wrong on SPARC64.

The current implementation assumes that the ASI is encoded in the 
instruction, which is correct on SPARC32, but wrong on SPARC64 where
the ASI register can be used if an immediate offset is specified the 
instructions instead. Moreover when the immediate ASI does not 
correspond to a normal memory access, the instructions are mapped to 
a load or a store. This does not work (and even on SPARC32) for 
instructions that loads and store at the same time (e.g. SWAPA, 
LDSTUBA).

The patch fixes that by defining ops for all those instructions, and
calling helper_ld_asi() and helper_st_asi(). At the same times it fixes
load instructions that are signed (e.g. LDSBA, LDSHA), and implements
a few ASI on SPARC64: as if user primary, as if user primary LE, primary
LE, primary no-fault LE.

Please note that the LDFA, LDDFA, STFA and STDFA instructions are still
not correctly implemented, but this is not a regression.

With this patch I am able to boot a 64-bit Linux kernel on the 
sparc64-softmmu target up to the point where it queries OpenBIOS 
about the memory. This fails because OpenBIOS does not export the
correct device.

Cheers,
Aurelien

Index: target-sparc/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-sparc/exec.h,v
retrieving revision 1.19
diff -u -d -p -r1.19 exec.h
--- target-sparc/exec.h 3 Jun 2007 17:44:37 -0000       1.19
+++ target-sparc/exec.h 21 Sep 2007 15:58:12 -0000
@@ -50,7 +50,7 @@ void cpu_unlock(void);
 void cpu_loop_exit(void);
 void helper_flush(target_ulong addr);
 void helper_ld_asi(int asi, int size, int sign);
-void helper_st_asi(int asi, int size, int sign);
+void helper_st_asi(int asi, int size);
 void helper_rett(void);
 void helper_ldfsr(void);
 void set_cwp(int new_cwp);
Index: target-sparc/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-sparc/op.c,v
retrieving revision 1.39
diff -u -d -p -r1.39 op.c
--- target-sparc/op.c   20 Sep 2007 15:21:32 -0000      1.39
+++ target-sparc/op.c   21 Sep 2007 15:58:12 -0000
@@ -1862,10 +1862,126 @@ void OPPROTO op_ld_asi_reg()
 void OPPROTO op_st_asi_reg()
 {
     T0 += PARAM1;
-    helper_st_asi(env->asi, PARAM2, PARAM3);
+    helper_st_asi(env->asi, PARAM2);
+}
+
+void OPPROTO op_ldstub_asi_reg()             /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    helper_ld_asi(env->asi, 1, 0);
+    tmp = T1;
+    T1 = 0xff;
+    helper_st_asi(env->asi, 1);
+    T1 = tmp;
+}
+
+void OPPROTO op_swap_asi_reg()               /* XXX: should be atomically */
+{
+    target_ulong tmp1, tmp2;
+
+    T0 += PARAM1;
+    tmp1 = T1;
+    helper_ld_asi(env->asi, 4, 0);
+    tmp2 = T1;
+    T1 = tmp1;
+    helper_st_asi(env->asi, 4);
+    T1 = tmp2;
+}
+
+void OPPROTO op_ldda_asi()
+{
+    helper_ld_asi(PARAM1, 8, 0);
+    T0 = T1 & 0xffffffffUL;
+    T1 >>= 32;
+}
+
+void OPPROTO op_ldda_asi_reg()
+{
+    T0 += PARAM1;
+    helper_ld_asi(env->asi, 8, 0);
+    T0 = T1 & 0xffffffffUL;
+    T1 >>= 32;
+}
+
+void OPPROTO op_stda_asi()
+{
+    T1 <<= 32;
+    T1 += T2 & 0xffffffffUL;
+    helper_st_asi(PARAM1, 8);
+}
+
+void OPPROTO op_stda_asi_reg()
+{
+    T0 += PARAM1;
+    T1 <<= 32;
+    T1 += T2 & 0xffffffffUL;
+    helper_st_asi(env->asi, 8);
+}
+
+void OPPROTO op_cas_asi()                    /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    tmp = T1 & 0xffffffffUL;
+    helper_ld_asi(PARAM1, 4, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2 & 0xffffffffUL;
+        helper_st_asi(PARAM1, 4);
+        T1 = tmp;
+    }
+    T1 &= 0xffffffffUL;
+}
+
+void OPPROTO op_cas_asi_reg()                /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    tmp = T1 & 0xffffffffUL;
+    helper_ld_asi(env->asi, 4, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2 & 0xffffffffUL;
+        helper_st_asi(env->asi, 4);
+        T1 = tmp;
+    }
+    T1 &= 0xffffffffUL;
+}
+
+void OPPROTO op_casx_asi()                   /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    tmp = T1;
+    helper_ld_asi(PARAM1, 8, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2;
+        helper_st_asi(PARAM1, 8);
+        T1 = tmp;
+    }
+}
+
+void OPPROTO op_casx_asi_reg()               /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    tmp = T1;
+    helper_ld_asi(env->asi, 8, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2;
+        helper_st_asi(env->asi, 8);
+        T1 = tmp;
+    }
 }
 #endif
 
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
 void OPPROTO op_ld_asi()
 {
     helper_ld_asi(PARAM1, PARAM2, PARAM3);
@@ -1873,8 +1989,32 @@ void OPPROTO op_ld_asi()
 
 void OPPROTO op_st_asi()
 {
-    helper_st_asi(PARAM1, PARAM2, PARAM3);
+    helper_st_asi(PARAM1, PARAM2);
+}
+
+void OPPROTO op_ldstub_asi()                 /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    helper_ld_asi(PARAM1, 1, 0);
+    tmp = T1;
+    T1 = 0xff;
+    helper_st_asi(PARAM1, 1);
+    T1 = tmp;
+}
+
+void OPPROTO op_swap_asi()                   /* XXX: should be atomically */
+{
+    target_ulong tmp1, tmp2;
+
+    tmp1 = T1;
+    helper_ld_asi(PARAM1, 4, 0);
+    tmp2 = T1;
+    T1 = tmp1;
+    helper_st_asi(PARAM1, 4);
+    T1 = tmp2;
 }
+#endif
 
 #ifdef TARGET_SPARC64
 // This function uses non-native bit order
Index: target-sparc/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-sparc/op_helper.c,v
retrieving revision 1.36
diff -u -d -p -r1.36 op_helper.c
--- target-sparc/op_helper.c    20 Sep 2007 14:54:22 -0000      1.36
+++ target-sparc/op_helper.c    21 Sep 2007 15:58:12 -0000
@@ -137,16 +137,8 @@ GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1,
 GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
 #endif
 
-#if defined(CONFIG_USER_ONLY)
-void helper_ld_asi(int asi, int size, int sign)
-{
-}
-
-void helper_st_asi(int asi, int size, int sign)
-{
-}
-#else
 #ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
 void helper_ld_asi(int asi, int size, int sign)
 {
     uint32_t ret = 0;
@@ -200,6 +192,42 @@ void helper_ld_asi(int asi, int size, in
             break;
         }
         break;
+    case 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            ret = ldub_user(T0);
+            break;
+        case 2:
+            ret = lduw_user(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(T0 & ~3);
+            break;
+        case 8:
+            ret = ldl_user(T0 & ~3);
+            T0 = ldl_user((T0 + 4) & ~3);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            ret = ldub_kernel(T0);
+            break;
+        case 2:
+            ret = lduw_kernel(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(T0 & ~3);
+            break;
+        case 8:
+            ret = ldl_kernel(T0 & ~3);
+            T0 = ldl_kernel((T0 + 4) & ~3);
+            break;
+        }
+        break;
     case 0xc: /* I-cache tag */
     case 0xd: /* I-cache data */
     case 0xe: /* D-cache tag */
@@ -253,10 +281,22 @@ void helper_ld_asi(int asi, int size, in
         ret = 0;
         break;
     }
-    T1 = ret;
+    if (sign) {
+        switch(size) {
+        case 1:
+            T1 = (int8_t) ret;
+        case 2:
+            T1 = (int16_t) ret;
+        default:
+            T1 = ret;
+            break;
+        }
+    }
+    else
+        T1 = ret;
 }
 
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
 {
     switch(asi) {
     case 2: /* SuperSparc MXCC registers */
@@ -325,6 +365,42 @@ void helper_st_asi(int asi, int size, in
 #endif
             return;
         }
+    case 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            stb_user(T0, T1);
+            break;
+        case 2:
+            stw_user(T0 & ~1, T1);
+            break;
+        default:
+        case 4:
+            stl_user(T0 & ~3, T1);
+            break;
+        case 8:
+            stl_user(T0 & ~3, T1);
+            stl_user((T0 + 4) & ~3, T2);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            stb_kernel(T0, T1);
+            break;
+        case 2:
+            stw_kernel(T0 & ~1, T1);
+            break;
+        default:
+        case 4:
+            stl_kernel(T0 & ~3, T1);
+            break;
+        case 8:
+            stl_kernel(T0 & ~3, T1);
+            stl_kernel((T0 + 4) & ~3, T2);
+            break;
+        }
+        break;
     case 0xc: /* I-cache tag */
     case 0xd: /* I-cache data */
     case 0xe: /* D-cache tag */
@@ -422,7 +498,143 @@ void helper_st_asi(int asi, int size, in
     }
 }
 
-#else
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+void helper_ld_asi(int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    switch (asi) {
+    case 0x80: // Primary
+    case 0x82: // Primary no-fault
+    case 0x88: // Primary LE
+    case 0x8a: // Primary no-fault LE
+        {
+            switch(size) {
+            case 1:
+                ret = ldub_raw(T0);
+                break;
+            case 2:
+                ret = lduw_raw(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_raw(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(T0 & ~7);
+                break;
+            }
+        }
+        break;
+    case 0x81: // Secondary
+    case 0x83: // Secondary no-fault
+    case 0x89: // Secondary LE
+    case 0x8b: // Secondary no-fault LE
+        // XXX
+        break;
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0x8a: // Primary no-fault LE
+    case 0x8b: // Secondary no-fault LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+        case 4:
+            ret = bswap32(ret);
+        case 8:
+            ret = bswap64(ret);
+        default:
+            break;
+        }
+    default:
+        break;
+    }            
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+        case 2:
+            ret = (int16_t) ret;
+        case 4:
+            ret = (int32_t) ret;
+        default:
+            break;
+        }
+    }
+    T1 = ret;
+}
+
+void helper_st_asi(int asi, int size)
+{
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            T0 = bswap16(T0);
+        case 4:
+            T0 = bswap32(T0);
+        case 8:
+            T0 = bswap64(T0);
+        default:
+            break;
+        }
+    default:
+        break;
+    }            
+
+    switch(asi) {
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        {
+            switch(size) {
+            case 1:
+                stb_raw(T0, T1);
+                break;
+            case 2:
+                stw_raw(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_raw(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_raw(T0 & ~7, T1);
+                break;
+            }
+        }
+        break;
+    case 0x81: // Secondary
+    case 0x89: // Secondary LE
+        // XXX
+        return;
+
+    case 0x82: // Primary no-fault, RO
+    case 0x83: // Secondary no-fault, RO
+    case 0x8a: // Primary no-fault LE, RO
+    case 0x8b: // Secondary no-fault LE, RO
+    default:
+        do_unassigned_access(T0, 1, 0, 1);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
 
 void helper_ld_asi(int asi, int size, int sign)
 {
@@ -432,8 +644,50 @@ void helper_ld_asi(int asi, int size, in
         raise_exception(TT_PRIV_ACT);
 
     switch (asi) {
+    case 0x10: // As if user primary
+    case 0x18: // As if user primary LE
+    case 0x80: // Primary
+    case 0x82: // Primary no-fault
+    case 0x88: // Primary LE
+    case 0x8a: // Primary no-fault LE
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            switch(size) {
+            case 1:
+                ret = ldub_kernel(T0);
+                break;
+            case 2:
+                ret = lduw_kernel(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_kernel(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_kernel(T0 & ~7);
+                break;
+            }
+        } else {
+            switch(size) {
+            case 1:
+                ret = ldub_user(T0);
+                break;
+            case 2:
+                ret = lduw_user(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_user(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_user(T0 & ~7);
+                break;
+            }
+        }
+        break;
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
         {
             switch(size) {
             case 1:
@@ -454,20 +708,14 @@ void helper_ld_asi(int asi, int size, in
         }
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x10: // As if user primary
     case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
     case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
     case 0x24: // Nucleus quad LDD 128 bit atomic
     case 0x2c: // Nucleus quad LDD 128 bit atomic
     case 0x4a: // UPA config
-    case 0x82: // Primary no-fault
+    case 0x81: // Secondary
     case 0x83: // Secondary no-fault
-    case 0x88: // Primary LE
     case 0x89: // Secondary LE
-    case 0x8a: // Primary no-fault LE
     case 0x8b: // Secondary no-fault LE
         // XXX
         break;
@@ -540,17 +788,120 @@ void helper_ld_asi(int asi, int size, in
         ret = 0;
         break;
     }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0x8a: // Primary no-fault LE
+    case 0x8b: // Secondary no-fault LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+        case 4:
+            ret = bswap32(ret);
+        case 8:
+            ret = bswap64(ret);
+        default:
+            break;
+        }
+    default:
+        break;
+    }            
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+        case 2:
+            ret = (int16_t) ret;
+        case 4:
+            ret = (int32_t) ret;
+        default:
+            break;
+        }
+    }
     T1 = ret;
 }
 
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
 {
     if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
         raise_exception(TT_PRIV_ACT);
 
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x81: // Secondary
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            T0 = bswap16(T0);
+        case 4:
+            T0 = bswap32(T0);
+        case 8:
+            T0 = bswap64(T0);
+        default:
+            break;
+        }
+    default:
+        break;
+    }            
+
     switch(asi) {
+    case 0x10: // As if user primary
+    case 0x18: // As if user primary LE
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            switch(size) {
+            case 1:
+                stb_kernel(T0, T1);
+                break;
+            case 2:
+                stw_kernel(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_kernel(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_kernel(T0 & ~7, T1);
+                break;
+            }
+        } else {
+            switch(size) {
+            case 1:
+                stb_user(T0, T1);
+                break;
+            case 2:
+                stw_user(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_user(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_user(T0 & ~7, T1);
+                break;
+            }
+        }
+        break;
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
         {
             switch(size) {
             case 1:
@@ -571,16 +922,11 @@ void helper_st_asi(int asi, int size, in
         return;
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x10: // As if user primary
     case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
     case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
     case 0x24: // Nucleus quad LDD 128 bit atomic
     case 0x2c: // Nucleus quad LDD 128 bit atomic
     case 0x4a: // UPA config
-    case 0x88: // Primary LE
     case 0x89: // Secondary LE
         // XXX
         return;
@@ -756,8 +1102,8 @@ void helper_st_asi(int asi, int size, in
         return;
     }
 }
-#endif
-#endif /* !CONFIG_USER_ONLY */
+#endif /* CONFIG_USER_ONLY */
+#endif /* TARGET_SPARC64 */
 
 #ifndef TARGET_SPARC64
 void helper_rett()
Index: target-sparc/op_mem.h
===================================================================
RCS file: /sources/qemu/qemu/target-sparc/op_mem.h,v
retrieving revision 1.9
diff -u -d -p -r1.9 op_mem.h
--- target-sparc/op_mem.h       20 Sep 2007 14:54:22 -0000      1.9
+++ target-sparc/op_mem.h       21 Sep 2007 15:58:12 -0000
@@ -76,33 +76,6 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (v
 }
 
 #ifdef TARGET_SPARC64
-/* XXX: Should be Atomically */
-/* XXX: There are no cas[x] instructions, only cas[x]a */
-void OPPROTO glue(op_cas, MEMSUFFIX)(void)
-{
-    uint32_t tmp;
-
-    tmp = glue(ldl, MEMSUFFIX)(T0);
-    T2 &=  0xffffffffULL;
-    if (tmp == (T1 & 0xffffffffULL)) {
-        glue(stl, MEMSUFFIX)(T0, T2);
-    }
-    T2 = tmp;
-}
-
-void OPPROTO glue(op_casx, MEMSUFFIX)(void)
-{
-    uint64_t tmp;
-
-    // XXX
-    tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
-    tmp |= glue(ldl, MEMSUFFIX)(T0);
-    if (tmp == T1) {
-        glue(stq, MEMSUFFIX)(T0, T2);
-    }
-    T2 = tmp;
-}
-
 void OPPROTO glue(op_lduw, MEMSUFFIX)(void)
 {
     T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff);
Index: target-sparc/translate.c
===================================================================
RCS file: /sources/qemu/qemu/target-sparc/translate.c,v
retrieving revision 1.68
diff -u -d -p -r1.68 translate.c
--- target-sparc/translate.c    20 Sep 2007 14:54:22 -0000      1.68
+++ target-sparc/translate.c    21 Sep 2007 15:58:12 -0000
@@ -353,112 +353,27 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store
 #endif
 #endif
 
-#ifdef TARGET_SPARC64
-// 'a' versions allowed to user depending on asi
-#if defined(CONFIG_USER_ONLY)
+/* moves */
+#ifdef CONFIG_USER_ONLY
 #define supervisor(dc) 0
+#ifdef TARGET_SPARC64
 #define hypervisor(dc) 0
+#endif
 #define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)                                              \
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {                                                                   \
-        int asi, offset;                                                \
-                                                                        \
-        if (IS_IMM) {                                                   \
-            offset = GET_FIELD(insn, 25, 31);                           \
-            if (is_ld)                                                  \
-                gen_op_ld_asi_reg(offset, size, sign);                  \
-            else                                                        \
-                gen_op_st_asi_reg(offset, size, sign);                  \
-            return;                                                     \
-        }                                                               \
-        asi = GET_FIELD(insn, 19, 26);                                  \
-        switch (asi) {                                                  \
-        case 0x80: /* Primary address space */                          \
-            gen_op_##width##_raw();                                     \
-            break;                                                      \
-        case 0x82: /* Primary address space, non-faulting load */       \
-            gen_op_##width##_raw();                                     \
-            break;                                                      \
-        default:                                                        \
-            break;                                                      \
-        }                                                               \
-    }
-
 #else
+#define supervisor(dc) (dc->mem_idx == 1)
+#ifdef TARGET_SPARC64
+#define hypervisor(dc) (dc->mem_idx == 2)
+#endif
 #define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
 #define OP_LD_TABLE(width)                                              \
     static GenOpFunc * const gen_op_##width[] = {                       \
         &gen_op_##width##_user,                                         \
         &gen_op_##width##_kernel,                                       \
-    };                                                                  \
-                                                                        \
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {                                                                   \
-        int asi, offset;                                                \
-                                                                        \
-        if (IS_IMM) {                                                   \
-            offset = GET_FIELD(insn, 25, 31);                           \
-            if (is_ld)                                                  \
-                gen_op_ld_asi_reg(offset, size, sign);                  \
-            else                                                        \
-                gen_op_st_asi_reg(offset, size, sign);                  \
-            return;                                                     \
-        }                                                               \
-        asi = GET_FIELD(insn, 19, 26);                                  \
-        if (is_ld)                                                      \
-            gen_op_ld_asi(asi, size, sign);                             \
-        else                                                            \
-            gen_op_st_asi(asi, size, sign);                             \
-    }
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#define hypervisor(dc) (dc->mem_idx == 2)
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define supervisor(dc) 0
-#else
-#define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc * const gen_op_##width[] = {                                 \
-    &gen_op_##width##_user,                                                   \
-    &gen_op_##width##_kernel,                                                 \
-};                                                                            \
-                                                                              \
-static void gen_op_##width##a(int insn, int is_ld, int size, int sign)        \
-{                                                                             \
-    int asi;                                                                  \
-                                                                              \
-    asi = GET_FIELD(insn, 19, 26);                                            \
-    switch (asi) {                                                            \
-        case 10: /* User data access */                                       \
-            gen_op_##width##_user();                                          \
-            break;                                                            \
-        case 11: /* Supervisor data access */                                 \
-            gen_op_##width##_kernel();                                        \
-            break;                                                            \
-        case 0x20 ... 0x2f: /* MMU passthrough */                             \
-            if (is_ld)                                                        \
-                gen_op_ld_asi(asi, size, sign);                               \
-            else                                                              \
-                gen_op_st_asi(asi, size, sign);                               \
-            break;                                                            \
-        default:                                                              \
-            if (is_ld)                                                        \
-                gen_op_ld_asi(asi, size, sign);                               \
-            else                                                              \
-                gen_op_st_asi(asi, size, sign);                               \
-            break;                                                            \
-    }                                                                         \
-}
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#endif
+    };
 #endif
 
+#ifndef CONFIG_USER_ONLY
 OP_LD_TABLE(ld);
 OP_LD_TABLE(st);
 OP_LD_TABLE(ldub);
@@ -481,8 +396,164 @@ OP_LD_TABLE(lduw);
 OP_LD_TABLE(ldsw);
 OP_LD_TABLE(ldx);
 OP_LD_TABLE(stx);
-OP_LD_TABLE(cas);
-OP_LD_TABLE(casx);
+#endif
+#endif
+
+/* asi moves */
+#ifdef TARGET_SPARC64
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ld_asi_reg(offset, size, sign);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ld_asi(asi, size, sign);
+    }
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_st_asi_reg(offset, size);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_st_asi(asi, size);
+    }
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_swap_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_swap_asi(asi);
+    }
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldstub_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldstub_asi(asi);
+    }
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldda_asi(asi);
+    }
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_stda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_stda_asi(asi);
+    }
+}
+
+static inline void gen_cas_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_cas_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_cas_asi(asi);
+    }
+}
+
+static inline void gen_casx_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_casx_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_casx_asi(asi);
+    }
+}
+
+#elif !defined(CONFIG_USER_ONLY)
+
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, size, sign);
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, size);
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ldstub_asi(asi);
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_swap_asi(asi);
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, 8, 0);
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, 8);
+}
 #endif
 
 static inline void gen_movl_imm_TN(int reg, uint32_t imm)
@@ -2796,7 +2867,12 @@ static void disas_sparc_insn(DisasContex
             rs1 = GET_FIELD(insn, 13, 17);
             save_state(dc);
             gen_movl_reg_T0(rs1);
-            if (IS_IMM) {       /* immediate */
+            if (xop == 0x3c || xop == 0x3e)
+            {
+                rs2 = GET_FIELD(insn, 27, 31);
+                gen_movl_reg_T1(rs2);
+            }
+            else if (IS_IMM) {       /* immediate */
                 rs2 = GET_FIELDs(insn, 19, 31);
 #if defined(OPTIM)
                 if (rs2 != 0) {
@@ -2873,16 +2949,10 @@ static void disas_sparc_insn(DisasContex
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#ifdef CONFIG_USER_ONLY
-                    gen_op_check_align_T0_3();
-#endif
-                    gen_op_lda(insn, 1, 4, 0);
-#else
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_lduwa(insn, 1, 4, 0);
-#endif
+                    gen_ld_asi(insn, 4, 0);
                     break;
                 case 0x11:      /* load unsigned byte alternate */
 #ifndef TARGET_SPARC64
@@ -2891,7 +2961,7 @@ static void disas_sparc_insn(DisasContex
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_lduba(insn, 1, 1, 0);
+                    gen_ld_asi(insn, 1, 0);
                     break;
                 case 0x12:      /* load unsigned halfword alternate */
 #ifndef TARGET_SPARC64
@@ -2899,11 +2969,10 @@ static void disas_sparc_insn(DisasContex
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_lduha(insn, 1, 2, 0);
+                    gen_ld_asi(insn, 2, 0);
                     break;
                 case 0x13:      /* load double word alternate */
 #ifndef TARGET_SPARC64
@@ -2915,7 +2984,7 @@ static void disas_sparc_insn(DisasContex
                     if (rd & 1)
                         goto illegal_insn;
                     gen_op_check_align_T0_7();
-                    gen_op_ldda(insn, 1, 8, 0);
+                    gen_ldda_asi(insn);
                     gen_movl_T0_reg(rd + 1);
                     break;
                 case 0x19:      /* load signed byte alternate */
@@ -2925,7 +2994,7 @@ static void disas_sparc_insn(DisasContex
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_ldsba(insn, 1, 1, 1);
+                    gen_ld_asi(insn, 1, 1);
                     break;
                 case 0x1a:      /* load signed halfword alternate */
 #ifndef TARGET_SPARC64
@@ -2933,11 +3002,10 @@ static void disas_sparc_insn(DisasContex
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_ldsha(insn, 1, 2 ,1);
+                    gen_ld_asi(insn, 2, 1);
                     break;
                 case 0x1d:      /* ldstuba -- XXX: should be atomically */
 #ifndef TARGET_SPARC64
@@ -2946,7 +3014,7 @@ static void disas_sparc_insn(DisasContex
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_ldstuba(insn, 1, 1, 0);
+                    gen_ldstub_asi(insn);
                     break;
                 case 0x1f:      /* swap reg with alt. memory. Also atomically 
*/
 #ifndef TARGET_SPARC64
@@ -2954,12 +3022,11 @@ static void disas_sparc_insn(DisasContex
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-                    gen_movl_reg_T1(rd);
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_swapa(insn, 1, 4, 0);
+                    gen_movl_reg_T1(rd);
+                    gen_swap_asi(insn);
                     break;
 
 #ifndef TARGET_SPARC64
@@ -2967,17 +3034,6 @@ static void disas_sparc_insn(DisasContex
                 case 0x31: /* ldcsr */
                 case 0x33: /* lddc */
                     goto ncp_insn;
-                    /* avoid warnings */
-                    (void) &gen_op_stfa;
-                    (void) &gen_op_stdfa;
-                    (void) &gen_op_ldfa;
-                    (void) &gen_op_lddfa;
-#else
-                    (void) &gen_op_lda;
-#if !defined(CONFIG_USER_ONLY)
-                    (void) &gen_op_cas;
-                    (void) &gen_op_casx;
-#endif
 #endif
 #endif
 #ifdef TARGET_SPARC64
@@ -2995,11 +3051,11 @@ static void disas_sparc_insn(DisasContex
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_ldswa(insn, 1, 4, 1);
+                    gen_ld_asi(insn, 4, 1);
                     break;
                 case 0x1b: /* V9 ldxa */
                     gen_op_check_align_T0_7();
-                    gen_op_ldxa(insn, 1, 8, 0);
+                    gen_ld_asi(insn, 8, 0);
                     break;
                 case 0x2d: /* V9 prefetch, no effect */
                     goto skip_move;
@@ -3007,13 +3063,12 @@ static void disas_sparc_insn(DisasContex
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_ldfa(insn, 1, 8, 0); // XXX
-                    break;
+                    gen_ld_asi(insn, 8, 0); // XXX
+                    goto skip_move;
                 case 0x33: /* V9 lddfa */
                     gen_op_check_align_T0_7();
-                    gen_op_lddfa(insn, 1, 8, 0); // XXX
-
-                    break;
+                    gen_ld_asi(insn, 8, 0); // XXX
+                    goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
                 case 0x32: /* V9 ldqfa */
@@ -3092,7 +3147,7 @@ static void disas_sparc_insn(DisasContex
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_sta(insn, 0, 4, 0);
+                    gen_st_asi(insn, 4);
                     break;
                 case 0x15:
 #ifndef TARGET_SPARC64
@@ -3101,7 +3156,7 @@ static void disas_sparc_insn(DisasContex
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_stba(insn, 0, 1, 0);
+                    gen_st_asi(insn, 1);
                     break;
                 case 0x16:
 #ifndef TARGET_SPARC64
@@ -3113,7 +3168,7 @@ static void disas_sparc_insn(DisasContex
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_stha(insn, 0, 2, 0);
+                    gen_st_asi(insn, 2);
                     break;
                 case 0x17:
 #ifndef TARGET_SPARC64
@@ -3127,7 +3182,7 @@ static void disas_sparc_insn(DisasContex
                     gen_op_check_align_T0_7();
                     flush_T2(dc);
                     gen_movl_reg_T2(rd + 1);
-                    gen_op_stda(insn, 0, 8, 0);
+                    gen_stda_asi(insn);
                     break;
 #endif
 #ifdef TARGET_SPARC64
@@ -3137,7 +3192,7 @@ static void disas_sparc_insn(DisasContex
                     break;
                 case 0x1e: /* V9 stxa */
                     gen_op_check_align_T0_7();
-                    gen_op_stxa(insn, 0, 8, 0); // XXX
+                    gen_st_asi(insn, 8);
                     break;
 #endif
                 default:
@@ -3184,21 +3239,27 @@ static void disas_sparc_insn(DisasContex
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_stfa(insn, 0, 0, 0); // XXX
+                    gen_st_asi(insn, 0); // XXX
                     break;
                 case 0x37: /* V9 stdfa */
                     gen_op_check_align_T0_7();
-                    gen_op_stdfa(insn, 0, 0, 0); // XXX
+                    gen_st_asi(insn, 0); // XXX
                     break;
                 case 0x3c: /* V9 casa */
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_casa(insn, 0, 4, 0); // XXX
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_cas_asi(insn);
+                    gen_movl_T1_reg(rd);
                     break;
                 case 0x3e: /* V9 casxa */
                     gen_op_check_align_T0_7();
-                    gen_op_casxa(insn, 0, 8, 0); // XXX
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_casx_asi(insn);
+                    gen_movl_T1_reg(rd);
                     break;
                 case 0x36: /* V9 stqfa */
                     goto nfpu_insn;

-- 
  .''`.  Aurelien Jarno             | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]