Revision 4b6a83fb target-arm/helper.c
b/target-arm/helper.c | ||
---|---|---|
137 | 137 |
g_slist_free(list); |
138 | 138 |
} |
139 | 139 |
|
140 |
void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, |
|
141 |
const ARMCPRegInfo *r, void *opaque) |
|
142 |
{ |
|
143 |
/* Define implementations of coprocessor registers. |
|
144 |
* We store these in a hashtable because typically |
|
145 |
* there are less than 150 registers in a space which |
|
146 |
* is 16*16*16*8*8 = 262144 in size. |
|
147 |
* Wildcarding is supported for the crm, opc1 and opc2 fields. |
|
148 |
* If a register is defined twice then the second definition is |
|
149 |
* used, so this can be used to define some generic registers and |
|
150 |
* then override them with implementation specific variations. |
|
151 |
* At least one of the original and the second definition should |
|
152 |
* include ARM_CP_OVERRIDE in its type bits -- this is just a guard |
|
153 |
* against accidental use. |
|
154 |
*/ |
|
155 |
int crm, opc1, opc2; |
|
156 |
int crmmin = (r->crm == CP_ANY) ? 0 : r->crm; |
|
157 |
int crmmax = (r->crm == CP_ANY) ? 15 : r->crm; |
|
158 |
int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1; |
|
159 |
int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1; |
|
160 |
int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2; |
|
161 |
int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2; |
|
162 |
/* 64 bit registers have only CRm and Opc1 fields */ |
|
163 |
assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn))); |
|
164 |
/* Check that the register definition has enough info to handle |
|
165 |
* reads and writes if they are permitted. |
|
166 |
*/ |
|
167 |
if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) { |
|
168 |
if (r->access & PL3_R) { |
|
169 |
assert(r->fieldoffset || r->readfn); |
|
170 |
} |
|
171 |
if (r->access & PL3_W) { |
|
172 |
assert(r->fieldoffset || r->writefn); |
|
173 |
} |
|
174 |
} |
|
175 |
/* Bad type field probably means missing sentinel at end of reg list */ |
|
176 |
assert(cptype_valid(r->type)); |
|
177 |
for (crm = crmmin; crm <= crmmax; crm++) { |
|
178 |
for (opc1 = opc1min; opc1 <= opc1max; opc1++) { |
|
179 |
for (opc2 = opc2min; opc2 <= opc2max; opc2++) { |
|
180 |
uint32_t *key = g_new(uint32_t, 1); |
|
181 |
ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); |
|
182 |
int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; |
|
183 |
*key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2); |
|
184 |
r2->opaque = opaque; |
|
185 |
/* Make sure reginfo passed to helpers for wildcarded regs |
|
186 |
* has the correct crm/opc1/opc2 for this reg, not CP_ANY: |
|
187 |
*/ |
|
188 |
r2->crm = crm; |
|
189 |
r2->opc1 = opc1; |
|
190 |
r2->opc2 = opc2; |
|
191 |
/* Overriding of an existing definition must be explicitly |
|
192 |
* requested. |
|
193 |
*/ |
|
194 |
if (!(r->type & ARM_CP_OVERRIDE)) { |
|
195 |
ARMCPRegInfo *oldreg; |
|
196 |
oldreg = g_hash_table_lookup(cpu->cp_regs, key); |
|
197 |
if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) { |
|
198 |
fprintf(stderr, "Register redefined: cp=%d %d bit " |
|
199 |
"crn=%d crm=%d opc1=%d opc2=%d, " |
|
200 |
"was %s, now %s\n", r2->cp, 32 + 32 * is64, |
|
201 |
r2->crn, r2->crm, r2->opc1, r2->opc2, |
|
202 |
oldreg->name, r2->name); |
|
203 |
assert(0); |
|
204 |
} |
|
205 |
} |
|
206 |
g_hash_table_insert(cpu->cp_regs, key, r2); |
|
207 |
} |
|
208 |
} |
|
209 |
} |
|
210 |
} |
|
211 |
|
|
212 |
void define_arm_cp_regs_with_opaque(ARMCPU *cpu, |
|
213 |
const ARMCPRegInfo *regs, void *opaque) |
|
214 |
{ |
|
215 |
/* Define a whole list of registers */ |
|
216 |
const ARMCPRegInfo *r; |
|
217 |
for (r = regs; r->type != ARM_CP_SENTINEL; r++) { |
|
218 |
define_one_arm_cp_reg_with_opaque(cpu, r, opaque); |
|
219 |
} |
|
220 |
} |
|
221 |
|
|
222 |
const ARMCPRegInfo *get_arm_cp_reginfo(ARMCPU *cpu, uint32_t encoded_cp) |
|
223 |
{ |
|
224 |
return g_hash_table_lookup(cpu->cp_regs, &encoded_cp); |
|
225 |
} |
|
226 |
|
|
227 |
int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, |
|
228 |
uint64_t value) |
|
229 |
{ |
|
230 |
/* Helper coprocessor write function for write-ignore registers */ |
|
231 |
return 0; |
|
232 |
} |
|
233 |
|
|
234 |
int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) |
|
235 |
{ |
|
236 |
/* Helper coprocessor write function for read-as-zero registers */ |
|
237 |
*value = 0; |
|
238 |
return 0; |
|
239 |
} |
|
240 |
|
|
140 | 241 |
static int bad_mode_switch(CPUARMState *env, int mode) |
141 | 242 |
{ |
142 | 243 |
/* Return true if it is not valid for us to switch to |
Also available in: Unified diff