Embedded PowerPC Device Control Registers infrastructure.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2653 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/hw/ppc.c b/hw/ppc.c
index f5c4500..f502271 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -547,6 +547,101 @@
     }
 }
 
+/*****************************************************************************/
+/* Embedded PowerPC Device Control Registers */
+typedef struct ppc_dcrn_t ppc_dcrn_t;
+struct ppc_dcrn_t {
+    dcr_read_cb dcr_read;
+    dcr_write_cb dcr_write;
+    void *opaque;
+};
+
+#define DCRN_NB 1024
+struct ppc_dcr_t {
+    ppc_dcrn_t dcrn[DCRN_NB];
+    int (*read_error)(int dcrn);
+    int (*write_error)(int dcrn);
+};
+
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_read == NULL)
+        goto error;
+    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
+
+    return 0;
+
+ error:
+    if (dcr_env->read_error != NULL)
+        return (*dcr_env->read_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_write == NULL)
+        goto error;
+    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
+
+    return 0;
+
+ error:
+    if (dcr_env->write_error != NULL)
+        return (*dcr_env->write_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
+{
+    ppc_dcr_t *dcr_env;
+    ppc_dcrn_t *dcr;
+
+    dcr_env = env->dcr_env;
+    if (dcr_env == NULL)
+        return -1;
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        return -1;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->opaque != NULL ||
+        dcr->dcr_read != NULL ||
+        dcr->dcr_write != NULL)
+        return -1;
+    dcr->opaque = opaque;
+    dcr->dcr_read = dcr_read;
+    dcr->dcr_write = dcr_write;
+
+    return 0;
+}
+
+int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
+                  int (*write_error)(int dcrn))
+{
+    ppc_dcr_t *dcr_env;
+
+    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
+    if (dcr_env == NULL)
+        return -1;
+    dcr_env->read_error = read_error;
+    dcr_env->write_error = write_error;
+    env->dcr_env = dcr_env;
+
+    return 0;
+}
+
+
 #if 0
 /*****************************************************************************/
 /* Handle system reset (for now, just stop emulation) */
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 0560a38..2a2c440 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -730,8 +730,6 @@
     /* Time base and decrementer */
     ppc_tb_t *tb_env;
     /* Device control registers */
-    int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val);
-    int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val);
     ppc_dcr_t *dcr_env;
 
     /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
@@ -863,6 +861,10 @@
 #endif
 #endif
 
+/* Device control registers */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp);
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
+
 #define TARGET_PAGE_BITS 12
 #include "cpu-all.h"
 
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index e1fff7f..a65da36 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1249,20 +1249,26 @@
 {
     target_ulong val;
     
-    if (unlikely(env->dcr_read == NULL))
+    if (unlikely(env->dcr_env == NULL)) {
+        printf("No DCR environment\n");
         do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
-    else if (unlikely((*env->dcr_read)(env->dcr_env, T0, &val) != 0))
+    } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
+        printf("DCR read error\n");
         do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
-    else
+    } else {
         T0 = val;
+    }
 }
 
 void do_store_dcr (void)
 {
-    if (unlikely(env->dcr_write == NULL))
+    if (unlikely(env->dcr_env == NULL)) {
+        printf("No DCR environment\n");
         do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
-    else if (unlikely((*env->dcr_write)(env->dcr_env, T0, T1) != 0))
+    } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
+        printf("DCR write error\n");
         do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+    }
 }
 
 void do_load_403_pb (int num)
diff --git a/vl.h b/vl.h
index b40ff37..df76a9f 100644
--- a/vl.h
+++ b/vl.h
@@ -1147,6 +1147,13 @@
 #ifdef TARGET_PPC
 /* PowerPC hardware exceptions management helpers */
 ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val);
+int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
+                  int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb drc_read, dcr_write_cb dcr_write);
 #endif
 void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);