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:
parent
a0e8edc4e7
commit
580d06d9dd
|
@ -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));
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue