openocd/src/target/openrisc/or1k.c
Marc Schink fb43f1ff4e target: Rework 'set' variable of break-/watchpoints
The 'set' variable name suggests a boolean data type which determines
whether a breakpoint (or watchpoint) is active. However, it is also
used to store the number of the breakpoint.

This encoding leads to inconsistent value assignments: boolean and
integer values are mixed. Also, associated hardware comparator
numbers, which are usually numbered from 0, cannot be used directly.
An additional offset is required to store the comparator numbers.

In order to make the code more readable and the value assignment more
consistent, change the variable name to 'is_set', its data type to 'bool'
and introduce a dedicated variable for the break-/watchpoint
number.

In order to make the review easier, the data types of various related
variables (e.g. number of breakpoints) are not changed.

While at it, fix a few coding style issues.

Change-Id: I2193f5639247cce6b80580d4c1c6afee916aeb82
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: https://review.openocd.org/c/openocd/+/6319
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
2022-03-19 09:14:39 +00:00

1464 lines
46 KiB
C

/***************************************************************************
* Copyright (C) 2011 by Julius Baxter *
* julius@opencores.org *
* *
* Copyright (C) 2013 by Marek Czerski *
* ma.czerski@gmail.com *
* *
* Copyright (C) 2013 by Franck Jullien *
* elec4fun@gmail.com *
* *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <jtag/jtag.h>
#include <target/register.h>
#include <target/target.h>
#include <target/breakpoints.h>
#include <target/target_type.h>
#include <helper/time_support.h>
#include <helper/fileio.h>
#include "or1k_tap.h"
#include "or1k.h"
#include "or1k_du.h"
LIST_HEAD(tap_list);
LIST_HEAD(du_list);
static int or1k_remove_breakpoint(struct target *target,
struct breakpoint *breakpoint);
static int or1k_read_core_reg(struct target *target, int num);
static int or1k_write_core_reg(struct target *target, int num);
static struct or1k_core_reg *or1k_core_reg_list_arch_info;
static const struct or1k_core_reg_init or1k_init_reg_list[] = {
{"r0", GROUP0 + 1024, "org.gnu.gdb.or1k.group0", NULL},
{"r1", GROUP0 + 1025, "org.gnu.gdb.or1k.group0", NULL},
{"r2", GROUP0 + 1026, "org.gnu.gdb.or1k.group0", NULL},
{"r3", GROUP0 + 1027, "org.gnu.gdb.or1k.group0", NULL},
{"r4", GROUP0 + 1028, "org.gnu.gdb.or1k.group0", NULL},
{"r5", GROUP0 + 1029, "org.gnu.gdb.or1k.group0", NULL},
{"r6", GROUP0 + 1030, "org.gnu.gdb.or1k.group0", NULL},
{"r7", GROUP0 + 1031, "org.gnu.gdb.or1k.group0", NULL},
{"r8", GROUP0 + 1032, "org.gnu.gdb.or1k.group0", NULL},
{"r9", GROUP0 + 1033, "org.gnu.gdb.or1k.group0", NULL},
{"r10", GROUP0 + 1034, "org.gnu.gdb.or1k.group0", NULL},
{"r11", GROUP0 + 1035, "org.gnu.gdb.or1k.group0", NULL},
{"r12", GROUP0 + 1036, "org.gnu.gdb.or1k.group0", NULL},
{"r13", GROUP0 + 1037, "org.gnu.gdb.or1k.group0", NULL},
{"r14", GROUP0 + 1038, "org.gnu.gdb.or1k.group0", NULL},
{"r15", GROUP0 + 1039, "org.gnu.gdb.or1k.group0", NULL},
{"r16", GROUP0 + 1040, "org.gnu.gdb.or1k.group0", NULL},
{"r17", GROUP0 + 1041, "org.gnu.gdb.or1k.group0", NULL},
{"r18", GROUP0 + 1042, "org.gnu.gdb.or1k.group0", NULL},
{"r19", GROUP0 + 1043, "org.gnu.gdb.or1k.group0", NULL},
{"r20", GROUP0 + 1044, "org.gnu.gdb.or1k.group0", NULL},
{"r21", GROUP0 + 1045, "org.gnu.gdb.or1k.group0", NULL},
{"r22", GROUP0 + 1046, "org.gnu.gdb.or1k.group0", NULL},
{"r23", GROUP0 + 1047, "org.gnu.gdb.or1k.group0", NULL},
{"r24", GROUP0 + 1048, "org.gnu.gdb.or1k.group0", NULL},
{"r25", GROUP0 + 1049, "org.gnu.gdb.or1k.group0", NULL},
{"r26", GROUP0 + 1050, "org.gnu.gdb.or1k.group0", NULL},
{"r27", GROUP0 + 1051, "org.gnu.gdb.or1k.group0", NULL},
{"r28", GROUP0 + 1052, "org.gnu.gdb.or1k.group0", NULL},
{"r29", GROUP0 + 1053, "org.gnu.gdb.or1k.group0", NULL},
{"r30", GROUP0 + 1054, "org.gnu.gdb.or1k.group0", NULL},
{"r31", GROUP0 + 1055, "org.gnu.gdb.or1k.group0", NULL},
{"ppc", GROUP0 + 18, "org.gnu.gdb.or1k.group0", NULL},
{"npc", GROUP0 + 16, "org.gnu.gdb.or1k.group0", NULL},
{"sr", GROUP0 + 17, "org.gnu.gdb.or1k.group0", NULL},
{"vr", GROUP0 + 0, "org.gnu.gdb.or1k.group0", "system"},
{"upr", GROUP0 + 1, "org.gnu.gdb.or1k.group0", "system"},
{"cpucfgr", GROUP0 + 2, "org.gnu.gdb.or1k.group0", "system"},
{"dmmucfgr", GROUP0 + 3, "org.gnu.gdb.or1k.group0", "system"},
{"immucfgr", GROUP0 + 4, "org.gnu.gdb.or1k.group0", "system"},
{"dccfgr", GROUP0 + 5, "org.gnu.gdb.or1k.group0", "system"},
{"iccfgr", GROUP0 + 6, "org.gnu.gdb.or1k.group0", "system"},
{"dcfgr", GROUP0 + 7, "org.gnu.gdb.or1k.group0", "system"},
{"pccfgr", GROUP0 + 8, "org.gnu.gdb.or1k.group0", "system"},
{"fpcsr", GROUP0 + 20, "org.gnu.gdb.or1k.group0", "system"},
{"epcr0", GROUP0 + 32, "org.gnu.gdb.or1k.group0", "system"},
{"epcr1", GROUP0 + 33, "org.gnu.gdb.or1k.group0", "system"},
{"epcr2", GROUP0 + 34, "org.gnu.gdb.or1k.group0", "system"},
{"epcr3", GROUP0 + 35, "org.gnu.gdb.or1k.group0", "system"},
{"epcr4", GROUP0 + 36, "org.gnu.gdb.or1k.group0", "system"},
{"epcr5", GROUP0 + 37, "org.gnu.gdb.or1k.group0", "system"},
{"epcr6", GROUP0 + 38, "org.gnu.gdb.or1k.group0", "system"},
{"epcr7", GROUP0 + 39, "org.gnu.gdb.or1k.group0", "system"},
{"epcr8", GROUP0 + 40, "org.gnu.gdb.or1k.group0", "system"},
{"epcr9", GROUP0 + 41, "org.gnu.gdb.or1k.group0", "system"},
{"epcr10", GROUP0 + 42, "org.gnu.gdb.or1k.group0", "system"},
{"epcr11", GROUP0 + 43, "org.gnu.gdb.or1k.group0", "system"},
{"epcr12", GROUP0 + 44, "org.gnu.gdb.or1k.group0", "system"},
{"epcr13", GROUP0 + 45, "org.gnu.gdb.or1k.group0", "system"},
{"epcr14", GROUP0 + 46, "org.gnu.gdb.or1k.group0", "system"},
{"epcr15", GROUP0 + 47, "org.gnu.gdb.or1k.group0", "system"},
{"eear0", GROUP0 + 48, "org.gnu.gdb.or1k.group0", "system"},
{"eear1", GROUP0 + 49, "org.gnu.gdb.or1k.group0", "system"},
{"eear2", GROUP0 + 50, "org.gnu.gdb.or1k.group0", "system"},
{"eear3", GROUP0 + 51, "org.gnu.gdb.or1k.group0", "system"},
{"eear4", GROUP0 + 52, "org.gnu.gdb.or1k.group0", "system"},
{"eear5", GROUP0 + 53, "org.gnu.gdb.or1k.group0", "system"},
{"eear6", GROUP0 + 54, "org.gnu.gdb.or1k.group0", "system"},
{"eear7", GROUP0 + 55, "org.gnu.gdb.or1k.group0", "system"},
{"eear8", GROUP0 + 56, "org.gnu.gdb.or1k.group0", "system"},
{"eear9", GROUP0 + 57, "org.gnu.gdb.or1k.group0", "system"},
{"eear10", GROUP0 + 58, "org.gnu.gdb.or1k.group0", "system"},
{"eear11", GROUP0 + 59, "org.gnu.gdb.or1k.group0", "system"},
{"eear12", GROUP0 + 60, "org.gnu.gdb.or1k.group0", "system"},
{"eear13", GROUP0 + 61, "org.gnu.gdb.or1k.group0", "system"},
{"eear14", GROUP0 + 62, "org.gnu.gdb.or1k.group0", "system"},
{"eear15", GROUP0 + 63, "org.gnu.gdb.or1k.group0", "system"},
{"esr0", GROUP0 + 64, "org.gnu.gdb.or1k.group0", "system"},
{"esr1", GROUP0 + 65, "org.gnu.gdb.or1k.group0", "system"},
{"esr2", GROUP0 + 66, "org.gnu.gdb.or1k.group0", "system"},
{"esr3", GROUP0 + 67, "org.gnu.gdb.or1k.group0", "system"},
{"esr4", GROUP0 + 68, "org.gnu.gdb.or1k.group0", "system"},
{"esr5", GROUP0 + 69, "org.gnu.gdb.or1k.group0", "system"},
{"esr6", GROUP0 + 70, "org.gnu.gdb.or1k.group0", "system"},
{"esr7", GROUP0 + 71, "org.gnu.gdb.or1k.group0", "system"},
{"esr8", GROUP0 + 72, "org.gnu.gdb.or1k.group0", "system"},
{"esr9", GROUP0 + 73, "org.gnu.gdb.or1k.group0", "system"},
{"esr10", GROUP0 + 74, "org.gnu.gdb.or1k.group0", "system"},
{"esr11", GROUP0 + 75, "org.gnu.gdb.or1k.group0", "system"},
{"esr12", GROUP0 + 76, "org.gnu.gdb.or1k.group0", "system"},
{"esr13", GROUP0 + 77, "org.gnu.gdb.or1k.group0", "system"},
{"esr14", GROUP0 + 78, "org.gnu.gdb.or1k.group0", "system"},
{"esr15", GROUP0 + 79, "org.gnu.gdb.or1k.group0", "system"},
{"dmmuucr", GROUP1 + 0, "org.gnu.gdb.or1k.group1", "dmmu"},
{"dmmuupr", GROUP1 + 1, "org.gnu.gdb.or1k.group1", "dmmu"},
{"dtlbeir", GROUP1 + 2, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbmr0", GROUP1 + 4, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbmr1", GROUP1 + 5, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbmr2", GROUP1 + 6, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbmr3", GROUP1 + 7, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbtr0", GROUP1 + 8, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbtr1", GROUP1 + 9, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbtr2", GROUP1 + 10, "org.gnu.gdb.or1k.group1", "dmmu"},
{"datbtr3", GROUP1 + 11, "org.gnu.gdb.or1k.group1", "dmmu"},
{"immucr", GROUP2 + 0, "org.gnu.gdb.or1k.group2", "immu"},
{"immupr", GROUP2 + 1, "org.gnu.gdb.or1k.group2", "immu"},
{"itlbeir", GROUP2 + 2, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbmr0", GROUP2 + 4, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbmr1", GROUP2 + 5, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbmr2", GROUP2 + 6, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbmr3", GROUP2 + 7, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbtr0", GROUP2 + 8, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbtr1", GROUP2 + 9, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbtr2", GROUP2 + 10, "org.gnu.gdb.or1k.group2", "immu"},
{"iatbtr3", GROUP2 + 11, "org.gnu.gdb.or1k.group2", "immu"},
{"dccr", GROUP3 + 0, "org.gnu.gdb.or1k.group3", "dcache"},
{"dcbpr", GROUP3 + 1, "org.gnu.gdb.or1k.group3", "dcache"},
{"dcbfr", GROUP3 + 2, "org.gnu.gdb.or1k.group3", "dcache"},
{"dcbir", GROUP3 + 3, "org.gnu.gdb.or1k.group3", "dcache"},
{"dcbwr", GROUP3 + 4, "org.gnu.gdb.or1k.group3", "dcache"},
{"dcblr", GROUP3 + 5, "org.gnu.gdb.or1k.group3", "dcache"},
{"iccr", GROUP4 + 0, "org.gnu.gdb.or1k.group4", "icache"},
{"icbpr", GROUP4 + 1, "org.gnu.gdb.or1k.group4", "icache"},
{"icbir", GROUP4 + 2, "org.gnu.gdb.or1k.group4", "icache"},
{"icblr", GROUP4 + 3, "org.gnu.gdb.or1k.group4", "icache"},
{"maclo", GROUP5 + 0, "org.gnu.gdb.or1k.group5", "mac"},
{"machi", GROUP5 + 1, "org.gnu.gdb.or1k.group5", "mac"},
{"dvr0", GROUP6 + 0, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr1", GROUP6 + 1, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr2", GROUP6 + 2, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr3", GROUP6 + 3, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr4", GROUP6 + 4, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr5", GROUP6 + 5, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr6", GROUP6 + 6, "org.gnu.gdb.or1k.group6", "debug"},
{"dvr7", GROUP6 + 7, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr0", GROUP6 + 8, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr1", GROUP6 + 9, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr2", GROUP6 + 10, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr3", GROUP6 + 11, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr4", GROUP6 + 12, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr5", GROUP6 + 13, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr6", GROUP6 + 14, "org.gnu.gdb.or1k.group6", "debug"},
{"dcr7", GROUP6 + 15, "org.gnu.gdb.or1k.group6", "debug"},
{"dmr1", GROUP6 + 16, "org.gnu.gdb.or1k.group6", "debug"},
{"dmr2", GROUP6 + 17, "org.gnu.gdb.or1k.group6", "debug"},
{"dcwr0", GROUP6 + 18, "org.gnu.gdb.or1k.group6", "debug"},
{"dcwr1", GROUP6 + 19, "org.gnu.gdb.or1k.group6", "debug"},
{"dsr", GROUP6 + 20, "org.gnu.gdb.or1k.group6", "debug"},
{"drr", GROUP6 + 21, "org.gnu.gdb.or1k.group6", "debug"},
{"pccr0", GROUP7 + 0, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr1", GROUP7 + 1, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr2", GROUP7 + 2, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr3", GROUP7 + 3, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr4", GROUP7 + 4, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr5", GROUP7 + 5, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr6", GROUP7 + 6, "org.gnu.gdb.or1k.group7", "perf"},
{"pccr7", GROUP7 + 7, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr0", GROUP7 + 8, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr1", GROUP7 + 9, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr2", GROUP7 + 10, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr3", GROUP7 + 11, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr4", GROUP7 + 12, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr5", GROUP7 + 13, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr6", GROUP7 + 14, "org.gnu.gdb.or1k.group7", "perf"},
{"pcmr7", GROUP7 + 15, "org.gnu.gdb.or1k.group7", "perf"},
{"pmr", GROUP8 + 0, "org.gnu.gdb.or1k.group8", "power"},
{"picmr", GROUP9 + 0, "org.gnu.gdb.or1k.group9", "pic"},
{"picsr", GROUP9 + 2, "org.gnu.gdb.or1k.group9", "pic"},
{"ttmr", GROUP10 + 0, "org.gnu.gdb.or1k.group10", "timer"},
{"ttcr", GROUP10 + 1, "org.gnu.gdb.or1k.group10", "timer"},
};
static int or1k_add_reg(struct target *target, struct or1k_core_reg *new_reg)
{
struct or1k_common *or1k = target_to_or1k(target);
int reg_list_size = or1k->nb_regs * sizeof(struct or1k_core_reg);
or1k_core_reg_list_arch_info = realloc(or1k_core_reg_list_arch_info,
reg_list_size + sizeof(struct or1k_core_reg));
memcpy(&or1k_core_reg_list_arch_info[or1k->nb_regs], new_reg,
sizeof(struct or1k_core_reg));
or1k_core_reg_list_arch_info[or1k->nb_regs].list_num = or1k->nb_regs;
or1k->nb_regs++;
return ERROR_OK;
}
static int or1k_create_reg_list(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
LOG_DEBUG("-");
or1k_core_reg_list_arch_info = malloc(ARRAY_SIZE(or1k_init_reg_list) *
sizeof(struct or1k_core_reg));
for (int i = 0; i < (int)ARRAY_SIZE(or1k_init_reg_list); i++) {
or1k_core_reg_list_arch_info[i].name = or1k_init_reg_list[i].name;
or1k_core_reg_list_arch_info[i].spr_num = or1k_init_reg_list[i].spr_num;
or1k_core_reg_list_arch_info[i].group = or1k_init_reg_list[i].group;
or1k_core_reg_list_arch_info[i].feature = or1k_init_reg_list[i].feature;
or1k_core_reg_list_arch_info[i].list_num = i;
or1k_core_reg_list_arch_info[i].target = NULL;
or1k_core_reg_list_arch_info[i].or1k_common = NULL;
}
or1k->nb_regs = ARRAY_SIZE(or1k_init_reg_list);
struct or1k_core_reg new_reg;
new_reg.target = NULL;
new_reg.or1k_common = NULL;
char name[32];
for (int way = 0; way < 4; way++) {
for (int i = 0; i < 128; i++) {
sprintf(name, "dtlbw%dmr%d", way, i);
new_reg.name = strdup(name);
new_reg.spr_num = GROUP1 + 512 + i + (way * 256);
new_reg.feature = "org.gnu.gdb.or1k.group1";
new_reg.group = "dmmu";
or1k_add_reg(target, &new_reg);
sprintf(name, "dtlbw%dtr%d", way, i);
new_reg.name = strdup(name);
new_reg.spr_num = GROUP1 + 640 + i + (way * 256);
new_reg.feature = "org.gnu.gdb.or1k.group1";
new_reg.group = "dmmu";
or1k_add_reg(target, &new_reg);
sprintf(name, "itlbw%dmr%d", way, i);
new_reg.name = strdup(name);
new_reg.spr_num = GROUP2 + 512 + i + (way * 256);
new_reg.feature = "org.gnu.gdb.or1k.group2";
new_reg.group = "immu";
or1k_add_reg(target, &new_reg);
sprintf(name, "itlbw%dtr%d", way, i);
new_reg.name = strdup(name);
new_reg.spr_num = GROUP2 + 640 + i + (way * 256);
new_reg.feature = "org.gnu.gdb.or1k.group2";
new_reg.group = "immu";
or1k_add_reg(target, &new_reg);
}
}
return ERROR_OK;
}
static int or1k_jtag_read_regs(struct or1k_common *or1k, uint32_t *regs)
{
struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag);
LOG_DEBUG("-");
return du_core->or1k_jtag_read_cpu(&or1k->jtag,
or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1,
regs + OR1K_REG_R0);
}
static int or1k_jtag_write_regs(struct or1k_common *or1k, uint32_t *regs)
{
struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag);
LOG_DEBUG("-");
return du_core->or1k_jtag_write_cpu(&or1k->jtag,
or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1,
&regs[OR1K_REG_R0]);
}
static int or1k_save_context(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
int regs_read = 0;
int retval;
LOG_DEBUG("-");
for (int i = 0; i < OR1KNUMCOREREGS; i++) {
if (!or1k->core_cache->reg_list[i].valid) {
if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) {
retval = du_core->or1k_jtag_read_cpu(&or1k->jtag,
or1k->arch_info[i].spr_num, 1,
&or1k->core_regs[i]);
if (retval != ERROR_OK)
return retval;
} else if (!regs_read) {
/* read gpr registers at once (but only one time in this loop) */
retval = or1k_jtag_read_regs(or1k, or1k->core_regs);
if (retval != ERROR_OK)
return retval;
/* prevent next reads in this loop */
regs_read = 1;
}
/* We've just updated the core_reg[i], now update
the core cache */
or1k_read_core_reg(target, i);
}
}
return ERROR_OK;
}
static int or1k_restore_context(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
int reg_write = 0;
int retval;
LOG_DEBUG("-");
for (int i = 0; i < OR1KNUMCOREREGS; i++) {
if (or1k->core_cache->reg_list[i].dirty) {
or1k_write_core_reg(target, i);
if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) {
retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
or1k->arch_info[i].spr_num, 1,
&or1k->core_regs[i]);
if (retval != ERROR_OK) {
LOG_ERROR("Error while restoring context");
return retval;
}
} else
reg_write = 1;
}
}
if (reg_write) {
/* read gpr registers at once (but only one time in this loop) */
retval = or1k_jtag_write_regs(or1k, or1k->core_regs);
if (retval != ERROR_OK) {
LOG_ERROR("Error while restoring context");
return retval;
}
}
return ERROR_OK;
}
static int or1k_read_core_reg(struct target *target, int num)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
uint32_t reg_value;
LOG_DEBUG("-");
if ((num < 0) || (num >= or1k->nb_regs))
return ERROR_COMMAND_SYNTAX_ERROR;
if ((num >= 0) && (num < OR1KNUMCOREREGS)) {
reg_value = or1k->core_regs[num];
buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value);
LOG_DEBUG("Read core reg %i value 0x%08" PRIx32, num, reg_value);
or1k->core_cache->reg_list[num].valid = true;
or1k->core_cache->reg_list[num].dirty = false;
} else {
/* This is an spr, always read value from HW */
int retval = du_core->or1k_jtag_read_cpu(&or1k->jtag,
or1k->arch_info[num].spr_num, 1, &reg_value);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading spr 0x%08" PRIx32, or1k->arch_info[num].spr_num);
return retval;
}
buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value);
LOG_DEBUG("Read spr reg %i value 0x%08" PRIx32, num, reg_value);
}
return ERROR_OK;
}
static int or1k_write_core_reg(struct target *target, int num)
{
struct or1k_common *or1k = target_to_or1k(target);
LOG_DEBUG("-");
if ((num < 0) || (num >= OR1KNUMCOREREGS))
return ERROR_COMMAND_SYNTAX_ERROR;
uint32_t reg_value = buf_get_u32(or1k->core_cache->reg_list[num].value, 0, 32);
or1k->core_regs[num] = reg_value;
LOG_DEBUG("Write core reg %i value 0x%08" PRIx32, num, reg_value);
or1k->core_cache->reg_list[num].valid = true;
or1k->core_cache->reg_list[num].dirty = false;
return ERROR_OK;
}
static int or1k_get_core_reg(struct reg *reg)
{
struct or1k_core_reg *or1k_reg = reg->arch_info;
struct target *target = or1k_reg->target;
LOG_DEBUG("-");
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
return or1k_read_core_reg(target, or1k_reg->list_num);
}
static int or1k_set_core_reg(struct reg *reg, uint8_t *buf)
{
struct or1k_core_reg *or1k_reg = reg->arch_info;
struct target *target = or1k_reg->target;
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
uint32_t value = buf_get_u32(buf, 0, 32);
LOG_DEBUG("-");
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
if (or1k_reg->list_num < OR1KNUMCOREREGS) {
buf_set_u32(reg->value, 0, 32, value);
reg->dirty = true;
reg->valid = true;
} else {
/* This is an spr, write it to the HW */
int retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
or1k_reg->spr_num, 1, &value);
if (retval != ERROR_OK) {
LOG_ERROR("Error while writing spr 0x%08" PRIx32, or1k_reg->spr_num);
return retval;
}
}
return ERROR_OK;
}
static const struct reg_arch_type or1k_reg_type = {
.get = or1k_get_core_reg,
.set = or1k_set_core_reg,
};
static struct reg_cache *or1k_build_reg_cache(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = calloc(or1k->nb_regs, sizeof(struct reg));
struct or1k_core_reg *arch_info =
malloc((or1k->nb_regs) * sizeof(struct or1k_core_reg));
struct reg_feature *feature;
LOG_DEBUG("-");
/* Build the process context cache */
cache->name = "OpenRISC 1000 registers";
cache->next = NULL;
cache->reg_list = reg_list;
cache->num_regs = or1k->nb_regs;
(*cache_p) = cache;
or1k->core_cache = cache;
or1k->arch_info = arch_info;
for (int i = 0; i < or1k->nb_regs; i++) {
arch_info[i] = or1k_core_reg_list_arch_info[i];
arch_info[i].target = target;
arch_info[i].or1k_common = or1k;
reg_list[i].name = or1k_core_reg_list_arch_info[i].name;
feature = malloc(sizeof(struct reg_feature));
feature->name = or1k_core_reg_list_arch_info[i].feature;
reg_list[i].feature = feature;
reg_list[i].group = or1k_core_reg_list_arch_info[i].group;
reg_list[i].size = 32;
reg_list[i].value = calloc(1, 4);
reg_list[i].dirty = false;
reg_list[i].valid = false;
reg_list[i].type = &or1k_reg_type;
reg_list[i].arch_info = &arch_info[i];
reg_list[i].number = i;
reg_list[i].exist = true;
}
return cache;
}
static int or1k_debug_entry(struct target *target)
{
LOG_DEBUG("-");
int retval = or1k_save_context(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_save_context");
return retval;
}
struct or1k_common *or1k = target_to_or1k(target);
uint32_t addr = or1k->core_regs[OR1K_REG_NPC];
if (breakpoint_find(target, addr))
/* Halted on a breakpoint, step back to permit executing the instruction there */
retval = or1k_set_core_reg(&or1k->core_cache->reg_list[OR1K_REG_NPC],
(uint8_t *)&addr);
return retval;
}
static int or1k_halt(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("target->state: %s",
target_state_name(target));
if (target->state == TARGET_HALTED) {
LOG_DEBUG("Target was already halted");
return ERROR_OK;
}
if (target->state == TARGET_UNKNOWN)
LOG_WARNING("Target was in unknown state when halt was requested");
if (target->state == TARGET_RESET) {
if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) &&
jtag_get_srst()) {
LOG_ERROR("Can't request a halt while in reset if nSRST pulls nTRST");
return ERROR_TARGET_FAILURE;
} else {
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
}
int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL);
if (retval != ERROR_OK) {
LOG_ERROR("Impossible to stall the CPU");
return retval;
}
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
static int or1k_is_cpu_running(struct target *target, int *running)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
int retval;
int tries = 0;
const int RETRIES_MAX = 5;
/* Have a retry loop to determine of the CPU is running.
If target has been hard reset for any reason, it might take a couple
of goes before it's ready again.
*/
while (tries < RETRIES_MAX) {
tries++;
retval = du_core->or1k_is_cpu_running(&or1k->jtag, running);
if (retval != ERROR_OK) {
LOG_WARNING("Debug IF CPU control reg read failure.");
/* Try once to restart the JTAG infrastructure -
quite possibly the board has just been reset. */
LOG_WARNING("Resetting JTAG TAP state and reconnecting to debug IF.");
du_core->or1k_jtag_init(&or1k->jtag);
LOG_WARNING("...attempt %d of %d", tries, RETRIES_MAX);
alive_sleep(2);
continue;
} else
return ERROR_OK;
}
LOG_ERROR("Could not re-establish communication with target");
return retval;
}
static int or1k_poll(struct target *target)
{
int retval;
int running;
retval = or1k_is_cpu_running(target, &running);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_is_cpu_running");
return retval;
}
/* check for processor halted */
if (!running) {
/* It's actually stalled, so update our software's state */
if ((target->state == TARGET_RUNNING) ||
(target->state == TARGET_RESET)) {
target->state = TARGET_HALTED;
retval = or1k_debug_entry(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_debug_entry");
return retval;
}
target_call_event_callbacks(target,
TARGET_EVENT_HALTED);
} else if (target->state == TARGET_DEBUG_RUNNING) {
target->state = TARGET_HALTED;
retval = or1k_debug_entry(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_debug_entry");
return retval;
}
target_call_event_callbacks(target,
TARGET_EVENT_DEBUG_HALTED);
}
} else { /* ... target is running */
/* If target was supposed to be stalled, stall it again */
if (target->state == TARGET_HALTED) {
target->state = TARGET_RUNNING;
retval = or1k_halt(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_halt");
return retval;
}
retval = or1k_debug_entry(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_debug_entry");
return retval;
}
target_call_event_callbacks(target,
TARGET_EVENT_DEBUG_HALTED);
}
target->state = TARGET_RUNNING;
}
return ERROR_OK;
}
static int or1k_assert_reset(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("-");
int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_RESET);
if (retval != ERROR_OK) {
LOG_ERROR("Error while asserting RESET");
return retval;
}
return ERROR_OK;
}
static int or1k_deassert_reset(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("-");
int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_NOT_RESET);
if (retval != ERROR_OK) {
LOG_ERROR("Error while deasserting RESET");
return retval;
}
return ERROR_OK;
}
static int or1k_soft_reset_halt(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("-");
int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL);
if (retval != ERROR_OK) {
LOG_ERROR("Error while stalling the CPU");
return retval;
}
retval = or1k_assert_reset(target);
if (retval != ERROR_OK)
return retval;
retval = or1k_deassert_reset(target);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static bool is_any_soft_breakpoint(struct target *target)
{
struct breakpoint *breakpoint = target->breakpoints;
LOG_DEBUG("-");
while (breakpoint)
if (breakpoint->type == BKPT_SOFT)
return true;
return false;
}
static int or1k_resume_or_step(struct target *target, int current,
uint32_t address, int handle_breakpoints,
int debug_execution, int step)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
struct breakpoint *breakpoint = NULL;
uint32_t resume_pc;
uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM];
LOG_DEBUG("Addr: 0x%" PRIx32 ", stepping: %s, handle breakpoints %s\n",
address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no");
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!debug_execution)
target_free_all_working_areas(target);
/* current ? continue on current pc : continue at <address> */
if (!current)
buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0,
32, address);
int retval = or1k_restore_context(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_restore_context");
return retval;
}
/* read debug registers (starting from DMR1 register) */
retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
OR1K_DEBUG_REG_NUM, debug_reg_list);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading debug registers");
return retval;
}
/* Clear Debug Reason Register (DRR) */
debug_reg_list[OR1K_DEBUG_REG_DRR] = 0;
/* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */
debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB;
if (step)
/* Set the single step trigger in Debug Mode Register 1 (DMR1) */
debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT;
else
/* Clear the single step trigger in Debug Mode Register 1 (DMR1) */
debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT);
/* Set traps to be handled by the debug unit in the Debug Stop
Register (DSR). Check if we have any software breakpoints in
place before setting this value - the kernel, for instance,
relies on l.trap instructions not stalling the processor ! */
if (is_any_soft_breakpoint(target) == true)
debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE;
/* Write debug registers (starting from DMR1 register) */
retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD,
OR1K_DEBUG_REG_NUM, debug_reg_list);
if (retval != ERROR_OK) {
LOG_ERROR("Error while writing back debug registers");
return retval;
}
resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value,
0, 32);
/* The front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
/* Single step past breakpoint at current address */
breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
LOG_DEBUG("Unset breakpoint at 0x%08" TARGET_PRIxADDR, breakpoint->address);
retval = or1k_remove_breakpoint(target, breakpoint);
if (retval != ERROR_OK)
return retval;
}
}
/* Unstall time */
retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_UNSTALL);
if (retval != ERROR_OK) {
LOG_ERROR("Error while unstalling the CPU");
return retval;
}
if (step)
target->debug_reason = DBG_REASON_SINGLESTEP;
else
target->debug_reason = DBG_REASON_NOTHALTED;
/* Registers are now invalid */
register_cache_invalidate(or1k->core_cache);
if (!debug_execution) {
target->state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
LOG_DEBUG("Target resumed at 0x%08" PRIx32, resume_pc);
} else {
target->state = TARGET_DEBUG_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
LOG_DEBUG("Target debug resumed at 0x%08" PRIx32, resume_pc);
}
return ERROR_OK;
}
static int or1k_resume(struct target *target, int current,
target_addr_t address, int handle_breakpoints,
int debug_execution)
{
return or1k_resume_or_step(target, current, address,
handle_breakpoints,
debug_execution,
NO_SINGLE_STEP);
}
static int or1k_step(struct target *target, int current,
target_addr_t address, int handle_breakpoints)
{
return or1k_resume_or_step(target, current, address,
handle_breakpoints,
0,
SINGLE_STEP);
}
static int or1k_add_breakpoint(struct target *target,
struct breakpoint *breakpoint)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
uint8_t data;
LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32,
breakpoint->address, breakpoint->length, breakpoint->type,
breakpoint->unique_id);
/* Only support SW breakpoints for now. */
if (breakpoint->type == BKPT_HARD)
LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint.");
/* Read and save the instruction */
int retval = du_core->or1k_jtag_read_memory(&or1k->jtag,
breakpoint->address,
4,
1,
&data);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading the instruction at 0x%08" TARGET_PRIxADDR,
breakpoint->address);
return retval;
}
free(breakpoint->orig_instr);
breakpoint->orig_instr = malloc(breakpoint->length);
memcpy(breakpoint->orig_instr, &data, breakpoint->length);
/* Sub in the OR1K trap instruction */
uint8_t or1k_trap_insn[4];
target_buffer_set_u32(target, or1k_trap_insn, OR1K_TRAP_INSTR);
retval = du_core->or1k_jtag_write_memory(&or1k->jtag,
breakpoint->address,
4,
1,
or1k_trap_insn);
if (retval != ERROR_OK) {
LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08" TARGET_PRIxADDR,
breakpoint->address);
return retval;
}
/* invalidate instruction cache */
uint32_t addr = breakpoint->address;
retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
OR1K_ICBIR_CPU_REG_ADD, 1, &addr);
if (retval != ERROR_OK) {
LOG_ERROR("Error while invalidating the ICACHE");
return retval;
}
return ERROR_OK;
}
static int or1k_remove_breakpoint(struct target *target,
struct breakpoint *breakpoint)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32,
breakpoint->address, breakpoint->length, breakpoint->type,
breakpoint->unique_id);
/* Only support SW breakpoints for now. */
if (breakpoint->type == BKPT_HARD)
LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint.");
/* Replace the removed instruction */
int retval = du_core->or1k_jtag_write_memory(&or1k->jtag,
breakpoint->address,
4,
1,
breakpoint->orig_instr);
if (retval != ERROR_OK) {
LOG_ERROR("Error while writing back the instruction at 0x%08" TARGET_PRIxADDR,
breakpoint->address);
return retval;
}
/* invalidate instruction cache */
uint32_t addr = breakpoint->address;
retval = du_core->or1k_jtag_write_cpu(&or1k->jtag,
OR1K_ICBIR_CPU_REG_ADD, 1, &addr);
if (retval != ERROR_OK) {
LOG_ERROR("Error while invalidating the ICACHE");
return retval;
}
return ERROR_OK;
}
static int or1k_add_watchpoint(struct target *target,
struct watchpoint *watchpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int or1k_remove_watchpoint(struct target *target,
struct watchpoint *watchpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int or1k_read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) {
LOG_ERROR("Bad arguments");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) {
LOG_ERROR("Can't handle unaligned memory access");
return ERROR_TARGET_UNALIGNED_ACCESS;
}
return du_core->or1k_jtag_read_memory(&or1k->jtag, address, size, count, buffer);
}
static int or1k_write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count);
if (target->state != TARGET_HALTED) {
LOG_WARNING("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) {
LOG_ERROR("Bad arguments");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) {
LOG_ERROR("Can't handle unaligned memory access");
return ERROR_TARGET_UNALIGNED_ACCESS;
}
return du_core->or1k_jtag_write_memory(&or1k->jtag, address, size, count, buffer);
}
static int or1k_init_target(struct command_context *cmd_ctx,
struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
struct or1k_jtag *jtag = &or1k->jtag;
if (!du_core) {
LOG_ERROR("No debug unit selected");
return ERROR_FAIL;
}
if (!jtag->tap_ip) {
LOG_ERROR("No tap selected");
return ERROR_FAIL;
}
or1k->jtag.tap = target->tap;
or1k->jtag.or1k_jtag_inited = 0;
or1k->jtag.or1k_jtag_module_selected = -1;
or1k->jtag.target = target;
or1k_build_reg_cache(target);
return ERROR_OK;
}
static int or1k_target_create(struct target *target, Jim_Interp *interp)
{
if (!target->tap)
return ERROR_FAIL;
struct or1k_common *or1k = calloc(1, sizeof(struct or1k_common));
target->arch_info = or1k;
or1k_create_reg_list(target);
or1k_tap_vjtag_register();
or1k_tap_xilinx_bscan_register();
or1k_tap_mohor_register();
or1k_du_adv_register();
return ERROR_OK;
}
static int or1k_examine(struct target *target)
{
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
if (!target_was_examined(target)) {
target_set_examined(target);
int running;
int retval = du_core->or1k_is_cpu_running(&or1k->jtag, &running);
if (retval != ERROR_OK) {
LOG_ERROR("Couldn't read the CPU state");
return retval;
} else {
if (running)
target->state = TARGET_RUNNING;
else {
LOG_DEBUG("Target is halted");
/* This is the first time we examine the target,
* it is stalled and we don't know why. Let's
* assume this is because of a debug reason.
*/
if (target->state == TARGET_UNKNOWN)
target->debug_reason = DBG_REASON_DBGRQ;
target->state = TARGET_HALTED;
}
}
}
return ERROR_OK;
}
static int or1k_arch_state(struct target *target)
{
return ERROR_OK;
}
static int or1k_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
int *reg_list_size, enum target_register_class reg_class)
{
struct or1k_common *or1k = target_to_or1k(target);
if (reg_class == REG_CLASS_GENERAL) {
/* We will have this called whenever GDB connects. */
int retval = or1k_save_context(target);
if (retval != ERROR_OK) {
LOG_ERROR("Error while calling or1k_save_context");
return retval;
}
*reg_list_size = OR1KNUMCOREREGS;
/* this is free()'d back in gdb_server.c's gdb_get_register_packet() */
*reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
for (int i = 0; i < OR1KNUMCOREREGS; i++)
(*reg_list)[i] = &or1k->core_cache->reg_list[i];
} else {
*reg_list_size = or1k->nb_regs;
*reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
for (int i = 0; i < or1k->nb_regs; i++)
(*reg_list)[i] = &or1k->core_cache->reg_list[i];
}
return ERROR_OK;
}
static int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
{
return ERROR_FAIL;
}
static int or1k_checksum_memory(struct target *target, target_addr_t address,
uint32_t count, uint32_t *checksum)
{
return ERROR_FAIL;
}
static int or1k_profiling(struct target *target, uint32_t *samples,
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
{
struct timeval timeout, now;
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_du *du_core = or1k_to_du(or1k);
int retval = ERROR_OK;
gettimeofday(&timeout, NULL);
timeval_add_time(&timeout, seconds, 0);
LOG_INFO("Starting or1k profiling. Sampling npc as fast as we can...");
/* Make sure the target is running */
target_poll(target);
if (target->state == TARGET_HALTED)
retval = target_resume(target, 1, 0, 0, 0);
if (retval != ERROR_OK) {
LOG_ERROR("Error while resuming target");
return retval;
}
uint32_t sample_count = 0;
for (;;) {
uint32_t reg_value;
retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, GROUP0 + 16 /* NPC */, 1, &reg_value);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading NPC");
return retval;
}
samples[sample_count++] = reg_value;
gettimeofday(&now, NULL);
if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) > 0) {
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
break;
}
}
*num_samples = sample_count;
return retval;
}
COMMAND_HANDLER(or1k_tap_select_command_handler)
{
struct target *target = get_current_target(CMD_CTX);
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_jtag *jtag = &or1k->jtag;
struct or1k_tap_ip *or1k_tap;
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
list_for_each_entry(or1k_tap, &tap_list, list) {
if (or1k_tap->name) {
if (!strcmp(CMD_ARGV[0], or1k_tap->name)) {
jtag->tap_ip = or1k_tap;
LOG_INFO("%s tap selected", or1k_tap->name);
return ERROR_OK;
}
}
}
LOG_ERROR("%s unknown, no tap selected", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_HANDLER(or1k_tap_list_command_handler)
{
struct or1k_tap_ip *or1k_tap;
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
list_for_each_entry(or1k_tap, &tap_list, list) {
if (or1k_tap->name)
command_print(CMD, "%s", or1k_tap->name);
}
return ERROR_OK;
}
COMMAND_HANDLER(or1k_du_select_command_handler)
{
struct target *target = get_current_target(CMD_CTX);
struct or1k_common *or1k = target_to_or1k(target);
struct or1k_jtag *jtag = &or1k->jtag;
struct or1k_du *or1k_du;
if (CMD_ARGC > 2)
return ERROR_COMMAND_SYNTAX_ERROR;
list_for_each_entry(or1k_du, &du_list, list) {
if (or1k_du->name) {
if (!strcmp(CMD_ARGV[0], or1k_du->name)) {
jtag->du_core = or1k_du;
LOG_INFO("%s debug unit selected", or1k_du->name);
if (CMD_ARGC == 2) {
int options;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], options);
or1k_du->options = options;
LOG_INFO("Option %x is passed to %s debug unit"
, options, or1k_du->name);
}
return ERROR_OK;
}
}
}
LOG_ERROR("%s unknown, no debug unit selected", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_HANDLER(or1k_du_list_command_handler)
{
struct or1k_du *or1k_du;
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
list_for_each_entry(or1k_du, &du_list, list) {
if (or1k_du->name)
command_print(CMD, "%s", or1k_du->name);
}
return ERROR_OK;
}
COMMAND_HANDLER(or1k_addreg_command_handler)
{
struct target *target = get_current_target(CMD_CTX);
struct or1k_core_reg new_reg;
if (CMD_ARGC != 4)
return ERROR_COMMAND_SYNTAX_ERROR;
new_reg.target = NULL;
new_reg.or1k_common = NULL;
uint32_t addr;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr);
new_reg.name = strdup(CMD_ARGV[0]);
new_reg.spr_num = addr;
new_reg.feature = strdup(CMD_ARGV[2]);
new_reg.group = strdup(CMD_ARGV[3]);
or1k_add_reg(target, &new_reg);
LOG_DEBUG("Add reg \"%s\" @ 0x%08" PRIx32 ", group \"%s\", feature \"%s\"",
new_reg.name, addr, new_reg.group, new_reg.feature);
return ERROR_OK;
}
static const struct command_registration or1k_hw_ip_command_handlers[] = {
{
.name = "tap_select",
.handler = or1k_tap_select_command_handler,
.mode = COMMAND_ANY,
.usage = "name",
.help = "Select the TAP core to use",
},
{
.name = "tap_list",
.handler = or1k_tap_list_command_handler,
.mode = COMMAND_ANY,
.usage = "",
.help = "Display available TAP core",
},
{
.name = "du_select",
.handler = or1k_du_select_command_handler,
.mode = COMMAND_ANY,
.usage = "name",
.help = "Select the Debug Unit core to use",
},
{
.name = "du_list",
.handler = or1k_du_list_command_handler,
.mode = COMMAND_ANY,
.usage = "select_tap name",
.help = "Display available Debug Unit core",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration or1k_reg_command_handlers[] = {
{
.name = "addreg",
.handler = or1k_addreg_command_handler,
.mode = COMMAND_ANY,
.usage = "name addr feature group",
.help = "Add a register to the register list",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration or1k_command_handlers[] = {
{
.chain = or1k_reg_command_handlers,
},
{
.chain = or1k_hw_ip_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct target_type or1k_target = {
.name = "or1k",
.poll = or1k_poll,
.arch_state = or1k_arch_state,
.target_request_data = NULL,
.halt = or1k_halt,
.resume = or1k_resume,
.step = or1k_step,
.assert_reset = or1k_assert_reset,
.deassert_reset = or1k_deassert_reset,
.soft_reset_halt = or1k_soft_reset_halt,
.get_gdb_reg_list = or1k_get_gdb_reg_list,
.read_memory = or1k_read_memory,
.write_memory = or1k_write_memory,
.checksum_memory = or1k_checksum_memory,
.commands = or1k_command_handlers,
.add_breakpoint = or1k_add_breakpoint,
.remove_breakpoint = or1k_remove_breakpoint,
.add_watchpoint = or1k_add_watchpoint,
.remove_watchpoint = or1k_remove_watchpoint,
.target_create = or1k_target_create,
.init_target = or1k_init_target,
.examine = or1k_examine,
.get_gdb_fileio_info = or1k_get_gdb_fileio_info,
.profiling = or1k_profiling,
};