target/arc: introduce basic smp support

With this commit we introduce basic SMP support for ARC targets.
Only running smp application in telnet is supported, GDB is
not supported yet.

SMP support starts with running "smp target1 target2..." command
during target initialization. This command creates linked list
of targets and sets for each ->smp=1. Next running poll()
function if one core is halted, it is necessary to poll
other cores in list. And finally resuming execution it is necessary
to restore context on each target and run each core.

Major changes in this commit:
 * Add "arc_smp on/of" handlers.
 * Modify resume, poll functions to process slave cores.
 * Introduced  arc_dbg_set_pc() and arc_ocd_poll_smp() functions
 * Introduced target/board snps_hsdk_smp.cfg files.

Usage via telnet:
 > load /path/to/bin
 > resume <start_address>

Signed-off-by: Evgeniy Didin <didin@synopsys.com>
This commit is contained in:
Evgeniy Didin 2020-03-30 22:08:54 +03:00 committed by Kumar Gala
parent a0e8edc4e7
commit 580d06d9dd
7 changed files with 287 additions and 27 deletions

View File

@ -389,7 +389,7 @@ int arc32_start_core(struct target *target)
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc32->jtag_info, AUX_STATUS32_REG, &value));
value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc32->jtag_info, AUX_STATUS32_REG, value));
LOG_DEBUG("Core started to run");
LOG_DEBUG("Core %s started to run", target_name(target));
#ifdef DEBUG
CHECK_RETVAL(arc32_print_core_state(target));

View File

@ -32,6 +32,7 @@
#include "target.h"
#include "target_request.h"
#include "target_type.h"
#include "smp.h"
#include "arc_dbg.h"
#include "arc_jtag.h"

View File

@ -555,13 +555,72 @@ int arc_dbg_halt(struct target *target)
return ERROR_OK;
}
static int arc_dbg_set_pc(struct target *target, int current, target_addr_t address)
{
int retval = ERROR_OK;
uint32_t resume_pc = 0;
struct arc32_common *arc32 = target_to_arc32(target);
struct reg *pc = &arc32->core_cache->reg_list[arc32->pc_index_in_cache];
/* current = 1: continue on current PC, otherwise continue at <address> */
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
pc->dirty = 1;
pc->valid = 1;
LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address);
}
if (!current)
resume_pc = address;
else
resume_pc = buf_get_u32(pc->value, 0, 32);
LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i",
resume_pc, pc->dirty, pc->valid);
/* check if GDB tells to set our PC where to continue from */
if ((pc->valid == 1) && (resume_pc == buf_get_u32(pc->value, 0, 32))) {
uint32_t value;
value = buf_get_u32(pc->value, 0, 32);
LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value);
retval = arc_jtag_write_aux_reg_one(&arc32->jtag_info, AUX_PC_REG, value);
}
return retval;
}
static int arc_dbg_restore_smp(struct target *target, int current, target_addr_t address, int debug_execution)
{
int retval = 0;
struct target_list *head;
struct target *curr;
head = target->head;
LOG_DEBUG("Restoring smp");
while (head != (struct target_list *)NULL) {
curr = head->target;
if ((curr != target) && (curr->state != TARGET_RUNNING)
&& target_was_examined(curr)) {
retval += arc32_restore_context(curr);
retval = arc_dbg_set_pc(curr, current, address);
arc32_enable_interrupts(curr, !debug_execution);
retval += arc32_start_core(curr);
}
head = head->next;
}
return retval;
}
int arc_dbg_resume(struct target *target, int current, target_addr_t address,
int handle_breakpoints, int debug_execution)
{
struct arc32_common *arc32 = target_to_arc32(target);
struct breakpoint *breakpoint = NULL;
uint32_t resume_pc = 0;
struct reg *pc = &arc32->core_cache->reg_list[arc32->pc_index_in_cache];
LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i, debug_execution:%i",
current, address, handle_breakpoints, debug_execution);
@ -579,36 +638,20 @@ int arc_dbg_resume(struct target *target, int current, target_addr_t address,
arc_dbg_enable_watchpoints(target);
}
/* current = 1: continue on current PC, otherwise continue at <address> */
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
pc->dirty = 1;
pc->valid = 1;
LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address);
}
if (!current)
resume_pc = address;
else
resume_pc = buf_get_u32(pc->value,
0, 32);
/* We need to reset ARC cache variables so caches
* would be invalidated and actual data
* would be fetched from memory. */
arc32_reset_caches_states(target);
arc32_restore_context(target);
LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i",
resume_pc, pc->dirty, pc->valid);
/* check if GDB tells to set our PC where to continue from */
if ((pc->valid == 1) && (resume_pc == buf_get_u32(pc->value, 0, 32))) {
uint32_t value;
value = buf_get_u32(pc->value, 0, 32);
LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value);
arc_jtag_write_aux_reg_one(&arc32->jtag_info, AUX_PC_REG, value);
int retval;
if (target->smp) {
target->gdb_service->core[0] = -1;
retval = arc_dbg_restore_smp(target, current, address, debug_execution);
if (retval != ERROR_OK)
return retval;
}
arc32_restore_context(target);
arc_dbg_set_pc(target, current, address);
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {

View File

@ -1046,6 +1046,44 @@ static int jim_handle_actionpoints_num(Jim_Interp *interp, int argc,
return JIM_OK;
}
COMMAND_HANDLER(arc_handle_smp_off_command)
{
struct target *target = get_current_target(CMD_CTX);
/* check target is an smp target */
struct target_list *head;
struct target *curr;
head = target->head;
target->smp = 0;
if (head != (struct target_list *)NULL) {
while (head != (struct target_list *)NULL) {
curr = head->target;
curr->smp = 0;
head = head->next;
}
/* fixes the target display to the debugger */
target->gdb_service->target = target;
}
return ERROR_OK;
}
COMMAND_HANDLER(arc_handle_smp_on_command)
{
struct target *target = get_current_target(CMD_CTX);
struct target_list *head;
struct target *curr;
head = target->head;
if (head != (struct target_list *)NULL) {
target->smp = 1;
while (head != (struct target_list *)NULL) {
curr = head->target;
curr->smp = 1;
head = head->next;
}
}
return ERROR_OK;
}
static const struct command_registration arc_jtag_command_group[] = {
{
.name = "always-check-status-rd",
@ -1201,6 +1239,20 @@ static const struct command_registration arc_core_command_handlers[] = {
.usage = "[<unsigned integer>]",
.help = "Prints or sets amount of actionpoints in the processor.",
},
{
.name = "smp_off",
.handler = arc_handle_smp_off_command,
.mode = COMMAND_EXEC,
.usage = "arc smp_off",
.help = "Stop smp handling",
},
{
.name = "smp_on",
.handler = arc_handle_smp_on_command,
.mode = COMMAND_EXEC,
.usage = "arc smp_on",
.help = "Restart smp handling",
},
COMMAND_REGISTRATION_DONE
};

View File

@ -44,6 +44,33 @@ static int arc_ocd_init_arch_info(struct target *target,
return ERROR_OK;
}
static int arc_ocd_poll_smp(struct target *target)
{
struct target_list *head;
struct target *curr;
int retval = 0;
foreach_smp_target(head, target->head) {
curr = head->target;
/* skip calling context */
if (curr == target)
continue;
if (!target_was_examined(curr))
continue;
/* skip targets that were already halted */
if (curr->state == TARGET_HALTED)
continue;
/* avoid recursion in arc_ocd_poll() */
curr->smp = 0;
arc_ocd_poll(curr);
curr->smp = 1;
}
return retval;
}
/* ----- Exported functions ------------------------------------------------ */
int arc_ocd_poll(struct target *target)
@ -53,7 +80,6 @@ int arc_ocd_poll(struct target *target)
/* gdb calls continuously through this arc_poll() function */
CHECK_RETVAL(arc_jtag_status(&arc32->jtag_info, &status));
/* check for processor halted */
if (status & ARC_JTAG_STAT_RU) {
if (target->state != TARGET_RUNNING){
@ -68,6 +94,13 @@ int arc_ocd_poll(struct target *target)
LOG_DEBUG("ARC core is halted or in reset.");
CHECK_RETVAL(arc_dbg_debug_entry(target));
int retval = 0;
if (target->smp) {
retval = arc_ocd_poll_smp(target);
if (retval != ERROR_OK)
return retval;
}
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
} else if (target->state == TARGET_DEBUG_RUNNING) {

View File

@ -0,0 +1,36 @@
# Copyright (C) 2019 Synopsys, Inc.
#
# 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, write to the
# Free Software Foundation, Inc.,
#
# Synopsys DesignWare ARC AXS103 Software Development Platform (HS38 cores)
#
# Configure JTAG cable
# SDP has built-in FT2232 chip, which is similiar to Digilent HS-1, except that
# it uses channgel B for JTAG, instead of channel A.
source [find interface/ftdi/snps_sdp.cfg]
adapter_khz 10000
# ARCs supports only JTAG.
transport select jtag
# Configure SoC
source [find target/snps_hsdk_smp.cfg]
# Initialize
init
reset halt

View File

@ -0,0 +1,95 @@
# Copyright (C) 2019 Synopsys, Inc.
#
# 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, write to the
# Free Software Foundation, Inc.,
#
# HS Development Kit SoC.
#
# Contains quad-core ARC HS38.
#
source [find cpu/arc/hs.tcl]
set _coreid 0
set _dbgbase [expr 0x00000000 | ($_coreid << 13)]
# CHIPNAME will be used to choose core family (600, 700 or EM). As far as
# OpenOCD is concerned EM and HS are identical.
set _CHIPNAME arc-em
# OpenOCD discovers JTAG TAPs in reverse order.
# ARC HS38 core 4
set _TARGETNAME $_CHIPNAME.cpu4
jtag newtap $_CHIPNAME cpu4 -irlen 4 -ircapture 0x1 -expected-id 0x200c24b1
target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME
$_TARGETNAME configure -coreid $_coreid
$_TARGETNAME configure -dbgbase $_dbgbase
# Flush L2$.
$_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME"
set _coreid [expr $_coreid + 1]
set _dbgbase [expr 0x00000000 | ($_coreid << 13)]
arc_hs_init_regs
# Enable L2 cache support for core 4.
$_TARGETNAME arc has-l2cache true
# ARC HS38 core 3
set _TARGETNAME1 $_CHIPNAME.cpu3
jtag newtap $_CHIPNAME cpu3 -irlen 4 -ircapture 0x1 -expected-id 0x200824b1
target create $_TARGETNAME1 arcv2 -chain-position $_TARGETNAME1
$_TARGETNAME1 configure -coreid $_coreid
$_TARGETNAME1 configure -dbgbase $_dbgbase
$_TARGETNAME1 configure -event reset-assert "arc_common_reset $_TARGETNAME1"
set _coreid [expr $_coreid + 1]
set _dbgbase [expr 0x00000000 | ($_coreid << 13)]
arc_hs_init_regs
# Enable L2 cache support for core 3.
$_TARGETNAME1 arc has-l2cache true
# ARC HS38 core 2
set _TARGETNAME2 $_CHIPNAME.cpu2
jtag newtap $_CHIPNAME cpu2 -irlen 4 -ircapture 0x1 -expected-id 0x200424b1
target create $_TARGETNAME2 arcv2 -chain-position $_TARGETNAME2
$_TARGETNAME2 configure -coreid $_coreid
$_TARGETNAME2 configure -dbgbase $_dbgbase
$_TARGETNAME2 configure -event reset-assert "arc_common_reset $_TARGETNAME2"
set _coreid [expr $_coreid + 1]
set _dbgbase [expr 0x00000000 | ($_coreid << 13)]
arc_hs_init_regs
# Enable L2 cache support for core 2.
$_TARGETNAME2 arc has-l2cache true
# ARC HS38 core 1
set _TARGETNAME3 $_CHIPNAME.cpu1
jtag newtap $_CHIPNAME cpu1 -irlen 4 -ircapture 0x1 -expected-id 0x200024b1
target create $_TARGETNAME3 arcv2 -chain-position $_TARGETNAME3
$_TARGETNAME3 configure -coreid $_coreid
$_TARGETNAME3 configure -dbgbase $_dbgbase
$_TARGETNAME3 configure -event reset-assert "arc_common_reset $_TARGETNAME3"
set _coreid [expr $_coreid + 1]
set _dbgbase [expr 0x00000000 | ($_coreid << 13)]
arc_hs_init_regs
# Enable L2 cache support for core 1.
$_TARGETNAME3 arc has-l2cache true
target smp $_CHIPNAME.cpu4 $_CHIPNAME.cpu3 $_CHIPNAME.cpu2 $_CHIPNAME.cpu1