commit 4b6a83fb0c34a6fcc7bb1058284e3c3674e54421
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Wed Jun 20 11:57:06 2012 +0000

    target-arm: initial coprocessor register framework
    
    Initial infrastructure for data-driven registration of
    coprocessor register implementations.
    
    We still fall back to the old-style switch statements pending
    complete conversion of all existing registers.
    
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index bbb1d05..7032423 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -137,6 +137,107 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     g_slist_free(list);
 }
 
+void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
+                                       const ARMCPRegInfo *r, void *opaque)
+{
+    /* Define implementations of coprocessor registers.
+     * We store these in a hashtable because typically
+     * there are less than 150 registers in a space which
+     * is 16*16*16*8*8 = 262144 in size.
+     * Wildcarding is supported for the crm, opc1 and opc2 fields.
+     * If a register is defined twice then the second definition is
+     * used, so this can be used to define some generic registers and
+     * then override them with implementation specific variations.
+     * At least one of the original and the second definition should
+     * include ARM_CP_OVERRIDE in its type bits -- this is just a guard
+     * against accidental use.
+     */
+    int crm, opc1, opc2;
+    int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
+    int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
+    int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
+    int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
+    int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
+    int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
+    /* 64 bit registers have only CRm and Opc1 fields */
+    assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
+    /* Check that the register definition has enough info to handle
+     * reads and writes if they are permitted.
+     */
+    if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) {
+        if (r->access & PL3_R) {
+            assert(r->fieldoffset || r->readfn);
+        }
+        if (r->access & PL3_W) {
+            assert(r->fieldoffset || r->writefn);
+        }
+    }
+    /* Bad type field probably means missing sentinel at end of reg list */
+    assert(cptype_valid(r->type));
+    for (crm = crmmin; crm <= crmmax; crm++) {
+        for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
+            for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
+                uint32_t *key = g_new(uint32_t, 1);
+                ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
+                int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
+                *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
+                r2->opaque = opaque;
+                /* Make sure reginfo passed to helpers for wildcarded regs
+                 * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
+                 */
+                r2->crm = crm;
+                r2->opc1 = opc1;
+                r2->opc2 = opc2;
+                /* Overriding of an existing definition must be explicitly
+                 * requested.
+                 */
+                if (!(r->type & ARM_CP_OVERRIDE)) {
+                    ARMCPRegInfo *oldreg;
+                    oldreg = g_hash_table_lookup(cpu->cp_regs, key);
+                    if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
+                        fprintf(stderr, "Register redefined: cp=%d %d bit "
+                                "crn=%d crm=%d opc1=%d opc2=%d, "
+                                "was %s, now %s\n", r2->cp, 32 + 32 * is64,
+                                r2->crn, r2->crm, r2->opc1, r2->opc2,
+                                oldreg->name, r2->name);
+                        assert(0);
+                    }
+                }
+                g_hash_table_insert(cpu->cp_regs, key, r2);
+            }
+        }
+    }
+}
+
+void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
+                                    const ARMCPRegInfo *regs, void *opaque)
+{
+    /* Define a whole list of registers */
+    const ARMCPRegInfo *r;
+    for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
+        define_one_arm_cp_reg_with_opaque(cpu, r, opaque);
+    }
+}
+
+const ARMCPRegInfo *get_arm_cp_reginfo(ARMCPU *cpu, uint32_t encoded_cp)
+{
+    return g_hash_table_lookup(cpu->cp_regs, &encoded_cp);
+}
+
+int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t value)
+{
+    /* Helper coprocessor write function for write-ignore registers */
+    return 0;
+}
+
+int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value)
+{
+    /* Helper coprocessor write function for read-as-zero registers */
+    *value = 0;
+    return 0;
+}
+
 static int bad_mode_switch(CPUARMState *env, int mode)
 {
     /* Return true if it is not valid for us to switch to
