Skip to content

Commit

Permalink
Add CDM client class (osd_cl_cdm)
Browse files Browse the repository at this point in the history
This client class provides a high-level API for the functionality of the
Core Debug Module (CDM).

Limitations:
- Accesses to 128 bit CPU registers are currently not supported.
  • Loading branch information
shivmgg authored and imphil committed Jun 12, 2018
1 parent 7a3bf4f commit 59de556
Show file tree
Hide file tree
Showing 11 changed files with 942 additions and 5 deletions.
1 change: 1 addition & 0 deletions doc/02_developer/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Each class is contained in one C header file.
libosd/cl_scm.rst
libosd/cl_stm.rst
libosd/cl_ctm.rst
libosd/cl_cdm.rst
libosd/log.rst
libosd/packet.rst
libosd/errorhandling.rst
Expand Down
17 changes: 17 additions & 0 deletions doc/02_developer/api/libosd/cl_cdm.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
osd_cl_cdm class
----------------

API to access the functionality of the Core Debug Module (CDM).

Usage
^^^^^

.. code-block:: c
#include <osd/osd.h>
#include <osd/cl_cdm.h>
Public Interface
^^^^^^^^^^^^^^^^

.. doxygenfile:: libosd/include/osd/cl_cdm.h
2 changes: 2 additions & 0 deletions src/libosd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pkginclude_HEADERS =\
include/osd/cl_scm.h \
include/osd/cl_stm.h \
include/osd/cl_ctm.h \
include/osd/cl_cdm.h \
include/osd/memaccess.h \
include/osd/systracelogger.h \
include/osd/coretracelogger.h
Expand All @@ -29,6 +30,7 @@ libosd_la_SOURCES =\
cl_scm.c \
cl_stm.c \
cl_ctm.c \
cl_cdm.c \
memaccess.c \
systracelogger.c \
coretracelogger.c
Expand Down
179 changes: 179 additions & 0 deletions src/libosd/cl_cdm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* Copyright 2018 The Open SoC Debug Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <osd/cl_cdm.h>

#include <assert.h>
#include <osd/osd.h>
#include <osd/packet.h>
#include <osd/reg.h>
#include "osd-private.h"

static struct osd_cdm_event *build_cdm_event(
const struct osd_cdm_desc *cdm_desc, const struct osd_packet *pkg)
{
struct osd_cdm_event *ev = calloc(1, sizeof(struct osd_cdm_event));

size_t exp_payload_len = 1; // stall
assert(osd_packet_sizeconv_payload2data(exp_payload_len) ==
pkg->data_size_words &&
"CDM Protocol violation detected.");

bool stall = pkg->data.payload[0];

ev->stall = stall;
return ev;
}

API_EXPORT
osd_result osd_cl_cdm_handle_event(void *arg, struct osd_packet *pkg)
{
assert(arg &&
"You need to give an event_handler_arg of type "
"struct osd_cdm_event_handler in osd_hostmod_new()");
assert(pkg);

struct osd_cdm_event_handler *handler = arg;

struct osd_cdm_event *ev = build_cdm_event(handler->cdm_desc, pkg);
osd_packet_free(&pkg);

handler->cb_fn(handler->cb_arg, handler->cdm_desc, ev);
free(ev);

return OSD_OK;
}

static bool is_cdm_module(struct osd_hostmod_ctx *hostmod_ctx,
unsigned int cdm_di_addr)
{
osd_result rv;

struct osd_module_desc desc;

rv = osd_hostmod_mod_describe(hostmod_ctx, cdm_di_addr, &desc);
if (OSD_FAILED(rv)) {
return false;
}

if (desc.vendor != OSD_MODULE_VENDOR_OSD ||
desc.type != OSD_MODULE_TYPE_STD_CDM || desc.version != 0) {
return false;
}

return true;
}

API_EXPORT
osd_result osd_cl_cdm_get_desc(struct osd_hostmod_ctx *hostmod_ctx,
unsigned int cdm_di_addr,
struct osd_cdm_desc *cdm_desc)
{
assert(hostmod_ctx);
assert(cdm_desc);

osd_result rv;

cdm_desc->di_addr = cdm_di_addr;

if (!is_cdm_module(hostmod_ctx, cdm_di_addr)) {
return OSD_ERROR_WRONG_MODULE;
}

uint16_t regvalue;
rv = osd_hostmod_reg_read(hostmod_ctx, &regvalue, cdm_di_addr,
OSD_REG_CDM_CORE_CTRL, 16, 0);
if (OSD_FAILED(rv)) return rv;
cdm_desc->core_ctrl = regvalue;

rv = osd_hostmod_reg_read(hostmod_ctx, &regvalue, cdm_di_addr,
OSD_REG_CDM_CORE_REG_UPPER, 16, 0);
if (OSD_FAILED(rv)) return rv;
cdm_desc->core_reg_upper = regvalue;

rv = osd_hostmod_reg_read(hostmod_ctx, &regvalue, cdm_di_addr,
OSD_REG_CDM_CORE_DATA_WIDTH, 16, 0);
if (OSD_FAILED(rv)) return rv;
cdm_desc->core_data_width = regvalue;

return OSD_OK;
}

API_EXPORT
osd_result cl_cdm_cpureg_read(struct osd_hostmod_ctx *hostmod_ctx,
struct osd_cdm_desc *cdm_desc, void *reg_val,
uint16_t reg_addr, int flags)
{
assert(hostmod_ctx);
assert(cdm_desc);

osd_result rv;

uint16_t cdm_di_addr = cdm_desc->di_addr;
uint16_t reg_addr_upper = reg_addr >> 15;
uint16_t core_upper = cdm_desc->core_reg_upper;

if (core_upper != reg_addr_upper) {
rv = osd_hostmod_reg_write(hostmod_ctx, &reg_addr_upper, cdm_di_addr,
OSD_REG_CDM_CORE_REG_UPPER, 16, 0);
if (OSD_FAILED(rv)) return rv;
cdm_desc->core_reg_upper = reg_addr_upper;
}

uint16_t cdm_reg_addr = 0x8000 + (reg_addr & 0x7fff);
uint16_t core_dw = cdm_desc->core_data_width;
assert(core_dw != 128
&& "128 bit wide register accesses are currently not supported.");

rv = osd_hostmod_reg_read(hostmod_ctx, reg_val, cdm_di_addr, cdm_reg_addr,
core_dw, flags);
if (OSD_FAILED(rv)) return rv;

return OSD_OK;
}

API_EXPORT
osd_result cl_cdm_cpureg_write(struct osd_hostmod_ctx *hostmod_ctx,
struct osd_cdm_desc *cdm_desc,
const void *reg_val, uint16_t reg_addr,
int flags)
{
assert(hostmod_ctx);
assert(cdm_desc);

osd_result rv;

uint16_t cdm_di_addr = cdm_desc->di_addr;
uint16_t reg_addr_upper = reg_addr >> 15;
uint16_t core_upper = cdm_desc->core_reg_upper;

if (core_upper != reg_addr_upper) {
rv = osd_hostmod_reg_write(hostmod_ctx, &reg_addr_upper, cdm_di_addr,
OSD_REG_CDM_CORE_REG_UPPER, 16, 0);
if (OSD_FAILED(rv)) return rv;
cdm_desc->core_reg_upper = reg_addr_upper;
}

uint16_t cdm_reg_addr = 0x8000 + (reg_addr & 0x7fff);
uint16_t core_dw = cdm_desc->core_data_width;
assert(core_dw != 128
&& "128 bit wide register accesses are currently not supported.");

rv = osd_hostmod_reg_write(hostmod_ctx, reg_val, cdm_di_addr, cdm_reg_addr,
core_dw, flags);
if (OSD_FAILED(rv)) return rv;

return OSD_OK;
}
128 changes: 128 additions & 0 deletions src/libosd/include/osd/cl_cdm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Copyright 2018 The Open SoC Debug Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef OSD_CL_CDM_H
#define OSD_CL_CDM_H

#include <osd/module.h>
#include <osd/osd.h>
#include <osd/packet.h>
#include <osd/hostmod.h>

#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup libosd-cl_cdm CDM client
* @ingroup libosd
*
* @{
*/

/**
* Information about a Core Debug Module
*/
struct osd_cdm_desc {
unsigned int di_addr; //!< DI address of CDM module
uint16_t core_ctrl; //!< Control signal for CPU core
uint16_t core_reg_upper; //!< Most significant bits of the SPR address
uint16_t core_data_width; //!< CPU data width in bits
};

/**
* A single event generated by the CDM module
*/
struct osd_cdm_event {
bool stall; //!< indicates the debugger that the CPU core is stalled.
};

typedef void (*osd_cl_cdm_handler_fn)(
void * /* arg */, const struct osd_cdm_desc * /* cdm_desc */,
const struct osd_cdm_event * /* event */);

struct osd_cdm_event_handler {
const struct osd_cdm_desc *cdm_desc;
osd_cl_cdm_handler_fn cb_fn;
void *cb_arg;
};

/**
* Populate the CDM descriptor with data from the debug module
*
* @param hostmod_ctx the host module handling the communication
* @param cdm_di_addr DI address of the CDM module to get describe
* @param[out] cdm_desc pre-allocated memory descriptor for the result
* @return OSD_OK on success
* OSD_ERROR_WRONG_MODULE if the module at cdm_di_addr is not a CDM
* any other value indicates an error
*/
osd_result osd_cl_cdm_get_desc(struct osd_hostmod_ctx *hostmod_ctx,
unsigned int cdm_di_addr,
struct osd_cdm_desc *cdm_desc);

/**
* Event handler to process CDM event, to be passed to a hostmod instance
*/
osd_result osd_cl_cdm_handle_event(void *arg, struct osd_packet *pkg);


/**
* Read data from an SPR of the CPU attached to a Core Debug Module (CDM)
*
* @param hostmod_ctx the host module handling the communication
* @param[out] cdm_desc pre-allocated memory descriptor for the result
* @param reg_val the returned read data
* @param reg_addr address to read from
* @param flags flags. Set OSD_HOSTMOD_BLOCKING to block indefinitely until the
* access succeeds.
* @return OSD_OK if the read was successful
* any other value indicates an error
*
* @see osd_cl_cdm_cpureg_write()
*/
osd_result cl_cdm_cpureg_read(struct osd_hostmod_ctx *hostmod_ctx,
struct osd_cdm_desc *cdm_desc,
void *reg_val, uint16_t reg_addr,
int flags);

/**
* Write data to an SPR of the CPU attached to a Core Debug Module (CDM)
*
* @param hostmod_ctx the host module handling the communication
* @param[out] cdm_desc pre-allocated memory descriptor for the result
* @param reg_val the data to be written
* @param reg_addr address to write data to
* @param flags flags. Set OSD_HOSTMOD_BLOCKING to block indefinitely until the
* access succeeds.
* @return OSD_OK if the write was successful
* any other value indicates an error
*
* @see osd_cl_cdm_cpureg_read()
*/
osd_result cl_cdm_cpureg_write(struct osd_hostmod_ctx *hostmod_ctx,
struct osd_cdm_desc *cdm_desc,
const void *reg_val, uint16_t reg_addr,
int flags);

/**@}*/ /* end of doxygen group libosd-cl_cdm */

#ifdef __cplusplus
}
#endif

#endif // OSD_CL_CDM_H
3 changes: 2 additions & 1 deletion src/libosd/include/osd/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
LIST_ENTRY(0x0002, DEM_UART, "Device Emulation Module UART") \
LIST_ENTRY(0x0003, MAM, "Memory Access Module") \
LIST_ENTRY(0x0004, STM, "System Trace Module") \
LIST_ENTRY(0x0005, CTM, "Core Trace Module")
LIST_ENTRY(0x0005, CTM, "Core Trace Module") \
LIST_ENTRY(0x0006, CDM, "Core Debug Module")

/**
* Vendor identifiers
Expand Down
9 changes: 8 additions & 1 deletion src/libosd/include/osd/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@

// CTM register map
#define OSD_REG_CTM_ADDR_WIDTH 0x0200
#define OSD_REG_CTM_DATA_WIDTH 0x0200
#define OSD_REG_CTM_DATA_WIDTH 0x0201

// CDM register map
#define OSD_REG_CDM_CORE_CTRL 0x0200
#define OSD_REG_CDM_CORE_CTRL_STALL_BIT 0
#define OSD_REG_CDM_CORE_REG_UPPER 0x0201
#define OSD_REG_CDM_CORE_DATA_WIDTH 0x0202


/**@}*/ /* end of doxygen group libosd-reg */

Expand Down
5 changes: 5 additions & 0 deletions tests/unit/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ check_PROGRAMS = \
check_cl_scm \
check_cl_stm \
check_cl_ctm \
check_cl_cdm \
check_memaccess \
check_systracelogger \
check_coretracelogger
Expand Down Expand Up @@ -37,6 +38,10 @@ check_cl_ctm_SOURCES = \
check_cl_ctm.c \
mock_hostmod.c

check_cl_cdm_SOURCES = \
check_cl_cdm.c \
mock_hostmod.c

check_memaccess_SOURCES = \
check_memaccess.c \
mock_host_controller.c
Expand Down
Loading

0 comments on commit 59de556

Please sign in to comment.