f9f54c25c0f6e0087ab78f5db44a67a792f06bd0
[fw/openocd] / src / target / mips64.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4  * Support for processors implementing MIPS64 instruction set
5  *
6  * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com>
7  * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru>
8  * Copyright (C) 2014 by Antony Pavlov <antonynpavlov@gmail.com>
9  * Copyright (C) 2014 by Peter Mamonov <pmamonov@gmail.com>
10  *
11  * Based on the work of:
12  *   Copyright (C) 2008 by Spencer Oliver
13  *   Copyright (C) 2008 by David T.L. Wong
14  *   Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev
15  */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "mips64.h"
22
23 static const struct {
24         unsigned id;
25         const char *name;
26         enum reg_type type;
27         const char *group;
28         const char *feature;
29         int flag;
30 } mips64_regs[] = {
31         {  0,  "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
32         {  1,  "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
33         {  2,  "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
34         {  3,  "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
35         {  4,  "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
36         {  5,  "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
37         {  6,  "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
38         {  7,  "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
39         {  8,  "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
40         {  9,  "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
41         { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
42         { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
43         { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
44         { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
45         { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
46         { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
47         { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
48         { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
49         { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
50         { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
51         { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
52         { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
53         { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
54         { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
55         { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
56         { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
57         { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
58         { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
59         { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
60         { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
61         { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
62         { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
63         { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
64         { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 },
65         { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL,
66                 "org.gnu.gdb.mips.cpu", 0 },
67         { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL,
68                 "org.gnu.gdb.mips.cp0", 0 },
69         { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL,
70                 "org.gnu.gdb.mips.cp0", 0 },
71         { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL,
72                 "org.gnu.gdb.mips.cp0", 0 },
73         { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL,
74                 "org.gnu.gdb.mips.cp0", 0 },
75         { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL,
76                 "org.gnu.gdb.mips.cp0", 0 },
77         { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL,
78                 "org.gnu.gdb.mips.cp0", 0 },
79         { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL,
80                 "org.gnu.gdb.mips.cp0", 0 },
81         { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL,
82                 "org.gnu.gdb.mips.cp0", 0 },
83         { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL,
84                 "org.gnu.gdb.mips.cp0", 0 },
85         { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL,
86                 "org.gnu.gdb.mips.cp0", 0 },
87         { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL,
88                 "org.gnu.gdb.mips.cp0", 0 },
89         { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL,
90                 "org.gnu.gdb.mips.cp0", 0 },
91         { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL,
92                 "org.gnu.gdb.mips.cp0", 0 },
93         { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL,
94                 "org.gnu.gdb.mips.cp0", 0 },
95         { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL,
96                 "org.gnu.gdb.mips.cp0", 0 },
97         { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL,
98                 "org.gnu.gdb.mips.cp0", 0 },
99         { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL,
100                 "org.gnu.gdb.mips.cp0", 0 },
101         { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL,
102                 "org.gnu.gdb.mips.cp0", 0 },
103         { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL,
104                 "org.gnu.gdb.mips.cp0", 0 },
105         { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL,
106                 "org.gnu.gdb.mips.cp0", 0 },
107         { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL,
108                 "org.gnu.gdb.mips.cp0", 0 },
109         { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL,
110                 "org.gnu.gdb.mips.cp0", 0 },
111         { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL,
112                 "org.gnu.gdb.mips.cp0", 0 },
113         { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL,
114                 "org.gnu.gdb.mips.cp0", 0 },
115         { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL,
116                 "org.gnu.gdb.mips.cp0", 0 },
117         { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL,
118                 "org.gnu.gdb.mips.cp0", 0 },
119         { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL,
120                 "org.gnu.gdb.mips.cp0", 0 },
121         { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL,
122                 "org.gnu.gdb.mips.cp0", 0 },
123         { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL,
124                 "org.gnu.gdb.mips.cp0", 0 },
125         { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL,
126                 "org.gnu.gdb.mips.cp0", 0 },
127         { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL,
128                 "org.gnu.gdb.mips.cp0", 0 },
129         { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL,
130                 "org.gnu.gdb.mips.cp0", 0 },
131         { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL,
132                 "org.gnu.gdb.mips.cp0", 0 },
133         { MIPS64_NUM_CORE_C0_REGS + 0,  "f0", REG_TYPE_IEEE_DOUBLE, NULL,
134                  "org.gnu.gdb.mips.fpu", 0 },
135         { MIPS64_NUM_CORE_C0_REGS + 1,  "f1", REG_TYPE_IEEE_DOUBLE, NULL,
136                  "org.gnu.gdb.mips.fpu", 0 },
137         { MIPS64_NUM_CORE_C0_REGS + 2,  "f2", REG_TYPE_IEEE_DOUBLE, NULL,
138                  "org.gnu.gdb.mips.fpu", 0 },
139         { MIPS64_NUM_CORE_C0_REGS + 3,  "f3", REG_TYPE_IEEE_DOUBLE, NULL,
140                  "org.gnu.gdb.mips.fpu", 0 },
141         { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL,
142                  "org.gnu.gdb.mips.fpu", 0 },
143         { MIPS64_NUM_CORE_C0_REGS + 5,  "f5", REG_TYPE_IEEE_DOUBLE, NULL,
144                  "org.gnu.gdb.mips.fpu", 0 },
145         { MIPS64_NUM_CORE_C0_REGS + 6,  "f6", REG_TYPE_IEEE_DOUBLE, NULL,
146                  "org.gnu.gdb.mips.fpu", 0 },
147         { MIPS64_NUM_CORE_C0_REGS + 7,  "f7", REG_TYPE_IEEE_DOUBLE, NULL,
148                  "org.gnu.gdb.mips.fpu", 0 },
149         { MIPS64_NUM_CORE_C0_REGS + 8,  "f8", REG_TYPE_IEEE_DOUBLE, NULL,
150                  "org.gnu.gdb.mips.fpu", 0 },
151         { MIPS64_NUM_CORE_C0_REGS + 9,  "f9", REG_TYPE_IEEE_DOUBLE, NULL,
152                  "org.gnu.gdb.mips.fpu", 0 },
153         { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL,
154                  "org.gnu.gdb.mips.fpu", 0 },
155         { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL,
156                  "org.gnu.gdb.mips.fpu", 0 },
157         { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL,
158                  "org.gnu.gdb.mips.fpu", 0 },
159         { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL,
160                  "org.gnu.gdb.mips.fpu", 0 },
161         { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL,
162                  "org.gnu.gdb.mips.fpu", 0 },
163         { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL,
164                  "org.gnu.gdb.mips.fpu", 0 },
165         { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL,
166                  "org.gnu.gdb.mips.fpu", 0 },
167         { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL,
168                  "org.gnu.gdb.mips.fpu", 0 },
169         { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL,
170                  "org.gnu.gdb.mips.fpu", 0 },
171         { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL,
172                  "org.gnu.gdb.mips.fpu", 0 },
173         { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL,
174                  "org.gnu.gdb.mips.fpu", 0 },
175         { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL,
176                  "org.gnu.gdb.mips.fpu", 0 },
177         { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL,
178                  "org.gnu.gdb.mips.fpu", 0 },
179         { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL,
180                  "org.gnu.gdb.mips.fpu", 0 },
181         { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL,
182                  "org.gnu.gdb.mips.fpu", 0 },
183         { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL,
184                  "org.gnu.gdb.mips.fpu", 0 },
185         { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL,
186                  "org.gnu.gdb.mips.fpu", 0 },
187         { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL,
188                  "org.gnu.gdb.mips.fpu", 0 },
189         { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL,
190                  "org.gnu.gdb.mips.fpu", 0 },
191         { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL,
192                  "org.gnu.gdb.mips.fpu", 0 },
193         { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL,
194                  "org.gnu.gdb.mips.fpu", 0 },
195         { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL,
196                  "org.gnu.gdb.mips.fpu", 0 },
197         { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float",
198                 "org.gnu.gdb.mips.fpu", 0 },
199         { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float",
200                 "org.gnu.gdb.mips.fpu", 0 },
201         { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float",
202                 "org.gnu.gdb.mips.fpu", 0 },
203         { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float",
204                 "org.gnu.gdb.mips.fpu", 0 },
205         { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float",
206                 "org.gnu.gdb.mips.fpu", 0 },
207         { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float",
208                 "org.gnu.gdb.mips.fpu", 0 },
209 };
210
211 static int reg_type2size(enum reg_type type)
212 {
213         switch (type) {
214         case REG_TYPE_UINT32:
215         case REG_TYPE_INT:
216                 return 32;
217         case REG_TYPE_UINT64:
218         case REG_TYPE_IEEE_DOUBLE:
219                 return 64;
220         default:
221                 return 64;
222         }
223 }
224
225 static int mips64_get_core_reg(struct reg *reg)
226 {
227         int retval;
228         struct mips64_core_reg *mips64_reg = reg->arch_info;
229         struct target *target = mips64_reg->target;
230         struct mips64_common *mips64_target = target->arch_info;
231
232         if (target->state != TARGET_HALTED)
233                 return ERROR_TARGET_NOT_HALTED;
234
235         retval = mips64_target->read_core_reg(target, mips64_reg->num);
236
237         return retval;
238 }
239
240 static int mips64_set_core_reg(struct reg *reg, uint8_t *buf)
241 {
242         struct mips64_core_reg *mips64_reg = reg->arch_info;
243         struct target *target = mips64_reg->target;
244         uint64_t value = buf_get_u64(buf, 0, 64);
245
246         if (target->state != TARGET_HALTED)
247                 return ERROR_TARGET_NOT_HALTED;
248
249         buf_set_u64(reg->value, 0, 64, value);
250         reg->dirty = 1;
251         reg->valid = 1;
252
253         return ERROR_OK;
254 }
255
256 static int mips64_read_core_reg(struct target *target, int num)
257 {
258         uint64_t reg_value;
259
260         /* get pointers to arch-specific information */
261         struct mips64_common *mips64 = target->arch_info;
262
263         if ((num < 0) || (num >= MIPS64_NUM_REGS))
264                 return ERROR_COMMAND_ARGUMENT_INVALID;
265
266         reg_value = mips64->core_regs[num];
267         buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value);
268         mips64->core_cache->reg_list[num].valid = 1;
269         mips64->core_cache->reg_list[num].dirty = 0;
270
271         return ERROR_OK;
272 }
273
274 static int mips64_write_core_reg(struct target *target, int num)
275 {
276         uint64_t reg_value;
277
278         /* get pointers to arch-specific information */
279         struct mips64_common *mips64 = target->arch_info;
280
281         if ((num < 0) || (num >= MIPS64_NUM_REGS))
282                 return ERROR_COMMAND_ARGUMENT_INVALID;
283
284         reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64);
285         mips64->core_regs[num] = reg_value;
286         LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value);
287         mips64->core_cache->reg_list[num].valid = 1;
288         mips64->core_cache->reg_list[num].dirty = 0;
289
290         return ERROR_OK;
291 }
292
293 int mips64_invalidate_core_regs(struct target *target)
294 {
295         /* get pointers to arch-specific information */
296         struct mips64_common *mips64 = target->arch_info;
297         unsigned int i;
298
299         for (i = 0; i < mips64->core_cache->num_regs; i++) {
300                 mips64->core_cache->reg_list[i].valid = 0;
301                 mips64->core_cache->reg_list[i].dirty = 0;
302         }
303
304         return ERROR_OK;
305 }
306
307
308 int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
309         int *reg_list_size, enum target_register_class reg_class)
310 {
311         /* get pointers to arch-specific information */
312         struct mips64_common *mips64 = target->arch_info;
313         register int i;
314
315         /* include floating point registers */
316         *reg_list_size = MIPS64_NUM_REGS;
317         *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
318
319         for (i = 0; i < MIPS64_NUM_REGS; i++)
320                 (*reg_list)[i] = &mips64->core_cache->reg_list[i];
321
322         return ERROR_OK;
323 }
324
325 int mips64_save_context(struct target *target)
326 {
327         int retval;
328         struct mips64_common *mips64 = target->arch_info;
329         struct mips_ejtag *ejtag_info = &mips64->ejtag_info;
330
331         retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs);
332         if (retval != ERROR_OK)
333                 return retval;
334
335         for (unsigned i = 0; i < MIPS64_NUM_REGS; i++)
336                         retval = mips64->read_core_reg(target, i);
337
338         return retval;
339 }
340
341 int mips64_restore_context(struct target *target)
342 {
343         struct mips64_common *mips64 = target->arch_info;
344         struct mips_ejtag *ejtag_info = &mips64->ejtag_info;
345
346         for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) {
347                 if (mips64->core_cache->reg_list[i].dirty)
348                         mips64->write_core_reg(target, i);
349         }
350
351         return mips64_pracc_write_regs(ejtag_info, mips64->core_regs);
352 }
353
354 int mips64_arch_state(struct target *target)
355 {
356         struct mips64_common *mips64 = target->arch_info;
357         struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC];
358
359         if (mips64->common_magic != MIPS64_COMMON_MAGIC) {
360                 LOG_ERROR("BUG: called for a non-MIPS64 target");
361                 exit(-1);
362         }
363
364         LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "",
365                  debug_reason_name(target), buf_get_u64(pc->value, 0, 64));
366
367         return ERROR_OK;
368 }
369
370 static const struct reg_arch_type mips64_reg_type = {
371         .get = mips64_get_core_reg,
372         .set = mips64_set_core_reg,
373 };
374
375 int mips64_build_reg_cache(struct target *target)
376 {
377         /* get pointers to arch-specific information */
378         struct mips64_common *mips64 = target->arch_info;
379         struct reg_cache **cache_p, *cache;
380         struct mips64_core_reg *arch_info = NULL;
381         struct reg *reg_list = NULL;
382         unsigned i;
383
384         cache = calloc(1, sizeof(*cache));
385         if (!cache) {
386                 LOG_ERROR("unable to allocate cache");
387                 return ERROR_FAIL;
388         }
389
390         reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list));
391         if (!reg_list) {
392                 LOG_ERROR("unable to allocate reg_list");
393                 goto alloc_fail;
394         }
395
396         arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info));
397         if (!arch_info) {
398                 LOG_ERROR("unable to allocate arch_info");
399                 goto alloc_fail;
400         }
401
402         for (i = 0; i < MIPS64_NUM_REGS; i++) {
403                 struct mips64_core_reg *a = &arch_info[i];
404                 struct reg *r = &reg_list[i];
405
406                 r->arch_info = &arch_info[i];
407                 r->caller_save = true;  /* gdb defaults to true */
408                 r->exist = true;
409                 r->feature = &a->feature;
410                 r->feature->name = mips64_regs[i].feature;
411                 r->group = mips64_regs[i].group;
412                 r->name = mips64_regs[i].name;
413                 r->number = i;
414                 r->reg_data_type = &a->reg_data_type;
415                 r->reg_data_type->type = mips64_regs[i].type;
416                 r->size = reg_type2size(mips64_regs[i].type);
417                 r->type = &mips64_reg_type;
418                 r->value = &a->value[0];
419
420                 a->mips64_common = mips64;
421                 a->num = mips64_regs[i].id;
422                 a->target = target;
423         }
424
425         cache->name = "mips64 registers";
426         cache->reg_list = reg_list;
427         cache->num_regs = MIPS64_NUM_REGS;
428
429         cache_p = register_get_last_cache_p(&target->reg_cache);
430         (*cache_p) = cache;
431
432         mips64->core_cache = cache;
433
434         return ERROR_OK;
435
436 alloc_fail:
437         free(cache);
438         free(reg_list);
439         free(arch_info);
440
441         return ERROR_FAIL;
442 }
443
444 int mips64_init_arch_info(struct target *target, struct mips64_common *mips64,
445                           struct jtag_tap *tap)
446 {
447         mips64->bp_scanned = false;
448         mips64->common_magic = MIPS64_COMMON_MAGIC;
449         mips64->data_break_list = NULL;
450         mips64->ejtag_info.tap = tap;
451         mips64->fast_data_area = NULL;
452         mips64->mips64mode32 = false;
453         mips64->read_core_reg = mips64_read_core_reg;
454         mips64->write_core_reg = mips64_write_core_reg;
455
456         return ERROR_OK;
457 }
458
459 int mips64_run_algorithm(struct target *target, int num_mem_params,
460                          struct mem_param *mem_params, int num_reg_params,
461                          struct reg_param *reg_params, target_addr_t entry_point,
462                          target_addr_t exit_point, int timeout_ms, void *arch_info)
463 {
464         /* TODO */
465         return ERROR_OK;
466 }
467
468 int mips64_examine(struct target *target)
469 {
470         struct mips64_common *mips64 = target->arch_info;
471
472         if (target_was_examined(target))
473                 return ERROR_OK;
474
475         /* TODO: why we do not do mips64_configure_break_unit() here? */
476         mips64->bp_scanned = false;
477         mips64->num_data_bpoints = 0;
478         mips64->num_data_bpoints_avail = 0;
479         mips64->num_inst_bpoints = 0;
480         mips64->num_inst_bpoints_avail = 0;
481
482         target_set_examined(target);
483
484         return ERROR_OK;
485 }
486
487 static int mips64_configure_i_break_unit(struct target *target)
488 {
489         /* get pointers to arch-specific information */
490         struct mips64_common *mips64 = target->arch_info;
491         struct mips64_comparator *ibl;
492         uint64_t bpinfo;
493         int retval;
494         int i;
495
496         /* get number of inst breakpoints */
497         retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo);
498         if (retval != ERROR_OK)
499                 return retval;
500
501         mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F;
502         mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints;
503         ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl));
504         if (!ibl) {
505                 LOG_ERROR("unable to allocate inst_break_list");
506                 return ERROR_FAIL;
507         }
508
509         for (i = 0; i < mips64->num_inst_bpoints; i++)
510                 ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i);
511
512         mips64->inst_break_list = ibl;
513         /* clear IBIS reg */
514         retval = target_write_u64(target, EJTAG64_V25_IBS, 0);
515         if (retval != ERROR_OK)
516                 return retval;
517
518         return ERROR_OK;
519 }
520
521 static int mips64_configure_d_break_unit(struct target *target)
522 {
523         struct mips64_common *mips64 = target->arch_info;
524         struct mips64_comparator *dbl;
525         uint64_t bpinfo;
526         int retval;
527         int i;
528
529         /* get number of data breakpoints */
530         retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo);
531         if (retval != ERROR_OK)
532                 return retval;
533
534         mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F;
535         mips64->num_data_bpoints_avail = mips64->num_data_bpoints;
536
537         dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl));
538
539         if (!dbl) {
540                 LOG_ERROR("unable to allocate data_break_list");
541                 return ERROR_FAIL;
542         }
543
544         for (i = 0; i < mips64->num_data_bpoints; i++)
545                 dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i);
546
547         mips64->data_break_list = dbl;
548
549         /* clear DBIS reg */
550         retval = target_write_u64(target, EJTAG64_V25_DBS, 0);
551         if (retval != ERROR_OK)
552                 return retval;
553
554         return ERROR_OK;
555 }
556
557 int mips64_configure_break_unit(struct target *target)
558 {
559         struct mips64_common *mips64 = target->arch_info;
560         uint64_t dcr;
561         int retval;
562
563         if (mips64->bp_scanned)
564                 return ERROR_OK;
565
566         /* get info about breakpoint support */
567         retval = target_read_u64(target, EJTAG64_DCR, &dcr);
568         if (retval != ERROR_OK)
569                 return retval;
570
571         if (dcr & EJTAG64_DCR_IB) {
572                 retval = mips64_configure_i_break_unit(target);
573                 if (retval != ERROR_OK)
574                         return retval;
575         }
576
577         if (dcr & EJTAG64_DCR_DB) {
578                 retval = mips64_configure_d_break_unit(target);
579                 if (retval != ERROR_OK)
580                         return retval;
581         }
582
583         LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr,
584                   mips64->num_inst_bpoints, mips64->num_data_bpoints);
585
586         mips64->bp_scanned = true;
587
588         return ERROR_OK;
589 }
590
591 int mips64_enable_interrupts(struct target *target, bool enable)
592 {
593         int retval;
594         bool update = false;
595         uint64_t dcr;
596
597         /* read debug control register */
598         retval = target_read_u64(target, EJTAG64_DCR, &dcr);
599         if (retval != ERROR_OK)
600                 return retval;
601
602         if (enable) {
603                 if (!(dcr & EJTAG64_DCR_INTE)) {
604                         /* enable interrupts */
605                         dcr |= EJTAG64_DCR_INTE;
606                         update = true;
607                 }
608         } else {
609                 if (dcr & EJTAG64_DCR_INTE) {
610                         /* disable interrupts */
611                         dcr &= ~(uint64_t)EJTAG64_DCR_INTE;
612                         update = true;
613                 }
614         }
615
616         if (update) {
617                 retval = target_write_u64(target, EJTAG64_DCR, dcr);
618                 if (retval != ERROR_OK)
619                         return retval;
620         }
621
622         return ERROR_OK;
623 }