[Open SoC Debug] CDM-OR1K implementation

SHIVAM AGGARWAL shivam16195 at iiitd.ac.in
Thu May 24 20:50:08 CEST 2018


Hi,

On Thu, May 24, 2018 at 10:07 PM, Philipp Wagner <philipp.wagner at tum.de>
wrote:

> Hi,
>
> this thread got rather long and the introduction of OpenOCD into the
> picture confuses me. So I'm taking the chance to summarize the my current
> understanding.
>
> To make it easier to follow, I created a modified figure here:
> http://pasteall.org/pic/show.php?id=91948fcf0633eef6e4aa0b0d9c0a58d3
> (it's not pretty, but hopefully illustrative).
>

Thanks for such a nice picture.

>
> What important components do we have in the system?
>
> 1) The Core Debug Module (CDM). This module connects to a single CPU and
> has two tasks:
>   a) Forward the accesses to SPRs from GDB to the core. The data can be
> forwarded unchanged, but the address needs to be translated.
>   b) Inform GDB about a status change to the CPU. The only status change
> we're interested in is a change between stalled and unstalled.
>
> 2) The MAM. This (already existing) module can read and write arbitrary
> memory addresses.
>
> 3) The OSD-GDB Server Bridge. This software module speaks the gdbserver
> protocol and forwards the GDB requests to the MAM and CDM modules.
>
> Notably absent in this picture are adv_dbg_system and OpenOCD. I don't see
> how these two pieces fit into the picture (expect for taking inspiration
> from their implementation).
>
>
>
>
> Now let's have a closer look at the CDM module.
>
> - Every OSD module has registers which can be accessed from the host. I'm
> calling them "OSD registers" for now.
>
> - OSD Register addresses are 16 bit wide, values can (according to the
> spec) be 16, 32, 64 or 128 bit wide. (http://opensocdebug.readthedo
> cs.io/en/latest/02_spec/03_dataformats.html#register-access-type-reg)
>
> - OSD register addresses between 0x0000 and 0x01FF are always used by OSD
> itself and have fixed meaning. All other register addresses can be used for
> any purpose by the debug module, i.e. by the CDM module in this case.
>
> - To enable GDB to access any SPR of the core, we want to use this
> functionality to "forward" register accesses from GDB through the OSD
> system to the core.
>
> - Side note: GPRs can be also be accesses through a SPR address, so
> there's no need have dedicated support for GPRs.
>
> - or1k SPR addresses in or1k are 16 bit wide.
>
> - As we don't have 16 bit available for a OSD register address, given the
> fixed registers between 0..0x200, we need to perform a address mapping. The
> address mapping I'm proposing is outlined below.
>
- Register accesses require polling from the host. To notify the host about
> something interesting OSD provides a concept of "event packets". These
> packets can be sent by the CDM like an interrupt at any time and the host
> can then react on it. We can use this functionality to inform the host
> about a change in processor state: the core is stalled, or not stalled any
> more.
>
>
> SPR to CDM register address mapping
>
> - Map SPRs to CDM address 0x8000 to 0xFFFF (msb set). This gives 15 bit of
> address space.
>
> - Have a separate register called CORE_REG_UPPER which contains the msb of
> the address.
>
> - The SPR register address is then calculated as
>   spr_reg_addr = CORE_REG_UPPER << 15 | cdm_reg_addr - 0x8000
>
> - As long as the msb of a SPR register address (spr_reg_addr[15]) does not
> change the CORE_REG_UPPER register does not need to be modified, nicely
> generating one (1) OSD operation for a one (1) SPR register access.
>

This is a very neat way of mapping.

1. The final mapping will be something like this: https://docs.google.com/
document/d/1qlmbhIvUt8XnSjvwAyiwyRDp6zeeJtN1Lz6WafBWn2o/edit?usp=sharing

2. Since, we are mapping each SPR into exactly one OSD register, we need to
change the width of the OSD register from 16 bits to 32 bits, right?

3. We need to map only first 10 groups in the module. This implies that MSB
for each group will always be 0. So, we can even omit the CORE_REG_UPPER
part.


>
> Finally, let's look at the OSD-GDB Server bridge.
>
> - In OSD-speak, this component is a "host module". It connects to the
> "host controller" over (most of the time) TCP and has functionality to read
> and write OSD registers from any other module, and to receive and send OSD
> event packets, just like a debug module on the chip. An example for such a
> host module can be found here: https://github.com/opensocdebu
> g/osd-sw/blob/master/src/libosd/systracelogger.c
> In our case, the OSD-GDB server bridge will need to communicate with the
> CDM and the MAM modules.
>
> - The OSD-GDB Server bridge also needs to be able to talk to a GDB
> instance. For this purpose it implements the gdbserver protocol. GDB
> instances can then connect to this gdbserver over TCP and communicate with
> the target.
>
> - Most "intelligence" is within gdb itself. gdb knows which SPRs to read
> and write at what time, it knows how to to translate a "set breakpoint"
> request from the user into a memory write inserting a l.trap, etc.
>
> - Looking at the OpenOCD implementation I'm not fully sure what additional
> functionality, beyond transferring register and memory accesses between GDB
> and the core/memory we need to perform within the OSD-GDB Server bridge.
>
>
> Stafford and Shivam, is this matching your understanding as well? If there
> are significant differences in understanding maybe we should schedule a
> video call to get this sorted out quickly.
>

I think the only significant difference lies in the approach of
implementing CDM module. Stafford mentioned that we can include the
information for OR1K register map on the software side.

"GDB Only really needs information about the GPRs:
       See:
    https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=
blob;f=gdb/features/or1k-core.xml;h=6fe9765150575464bf11a975
2e3c3276ff4ab8fa;hb=HEAD

    This is the base register map that GCC needs.

    For openOCD there are more provided which we can see here:
    http://repo.or.cz/openocd.git/blob/HEAD:/src/target/openrisc/or1k.c#l53

    The register maps are transferred from the debug server to GDB via an
XML file."

This will help in making CDM core independent. But, I think there are a
couple of issues with this implementation.

First, we need to have specialized read/write registers in the CDM module
instead of the register map. It will be inefficient as there will be
multiple transactions for a single read/write access.
Secondly, I am not sure if we can include OR1K register details in the
software side as mentioned above in the OSD framework.

So, I believe it is best to map OR1K registers in the module.

- *Shivam Aggarwal*

Best,
>
> Philipp
>
>
>
>
>
>
>
> On 05/24/2018 10:24 AM, SHIVAM AGGARWAL wrote:
>
>
>>
>> On Thu, 24 May 2018, 02:41 Stafford Horne, <shorne at gmail.com <mailto:
>> shorne at gmail.com>> wrote:
>>
>>     On Wed, May 23, 2018 at 02:06:57PM +0530, SHIVAM AGGARWAL wrote:
>>      > Hi all,
>>      >
>>      > I spend last two days reading about GDB and its architecture.
>>      >
>>      > As a program that works directly with the instructions of the
>>     target CPU,
>>      > GDB needs in-depth knowledge about the details of the CPU core.
>>     GDB needs
>>      > information of all registers (SPRs and GPRs) within the target
>>     system CPU;
>>
>>     GDB Only really needs information about the GPRs:
>>        See:
>>     https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=b
>> lob;f=gdb/features/or1k-core.xml;h=6fe9765150575464bf11a9752
>> e3c3276ff4ab8fa;hb=HEAD
>>
>>     This is the base register map that GCC needs.
>>
>>     For openOCD there are more provided which we can see here:
>>     http://repo.or.cz/openocd.git/blob/HEAD:/src/target/openrisc
>> /or1k.c#l53
>>
>>     The register maps are transferred from the debug server to GDB via
>>     an xml file.
>>
>>      > this allows it to read or write CPU registers by address. It also
>>     needs to
>>      > know about all the the sizes of the different kinds of data, the
>>     size and
>>      > shape of the address space, how the calling convention works, what
>>      > instruction will cause a trap exception, and so on.
>>
>>     Yes, GDB has that all defined within it.  It doesnt need to be
>>     provided by OSD.
>>
>>
>> So, we can include this information on the software side.
>>
>>
>>      > To sum up, CDM-OR1K must provides access to each register in the
>>     CPU core
>>      > as a OSD specific register.
>>      >
>>      > All SPRs in mor1kx are listed in this verilog code:
>>      >
>>     https://github.com/openrisc/mor1kx/blob/master/rtl/verilog/m
>> or1kx-sprs.v
>>      >
>>      >
>>      >    1.
>>      >
>>      >    *Register map for SPRs and GPRs in CDM-OR1K*:
>>      >
>>      > We can easily map 32-bit wide 32 GPRs as two 16-bit OSD specific
>>     registers
>>      > in the module. We already have access to the debug unit for setting
>>      > watchpoints/breakpoints.
>>
>>     *We already have access to the debug unit for reading/setting all
>>     registers.
>>
>>      > In GDB, there are commands like ‘info spr’ used to show the value
>>     of a SPR
>>      > or group of SPRs and ‘spr’ to set the value of an individual SPR.
>>     There are
>>      > about 12 groups (permitted upto 32) with some groups (1, 2 and 3)
>>     having
>>      > 1000+ SPRs.
>>
>>     That list is provided by OpenOCD, or the features XML of the target
>>     server not
>>     by the debug hardware. See my links above.
>>
>>     *Option 1*
>>      > We can assign address spaces 0x0200-0xffff (about 65023 registers)
>> as
>>      > module specific registers in CDM-OR1K. The space is enough to map
>>     each or1k
>>      > register into OSD address space.
>>
>>     Any mapping makes it specific to a processor this is not needed.
>>
>>     *Option 2*
>>      > *Alternate solution*: Can we have certain dedicated read/write
>>     registers in
>>      > the module?
>>      >
>>      > i.e instead of mapping each and every register, each time GDB
>>     asks for a
>>      > specific SPR read/write, we can store its address in one of OSD
>>     register
>>      > and data in two other registers. This information can be
>>     translated over
>>      > system interface signals to the CPU core. But, for commands like
>>     ‘info
>>      > spr’, we might need to store such information for all the SPRs.
>>
>>     This sounds better.  Have you seen how it is done in Adv_debug_if?
>>
>>        - OpenOCD driver:
>>     http://repo.or.cz/openocd.git/blob/HEAD:/src/target/openrisc
>> /or1k_du_adv.c#l498
>>          Burst read/write for registers is always 4 bytes.
>>
>>        - Adv Debug IF:
>>     https://github.com/freecores/adv_debug_sys/blob/master/Hardw
>> are/adv_dbg_if/doc/AdvancedDebugInterface.pdf
>>          RTL:
>>     https://github.com/freecores/adv_debug_sys/blob/master/Hardw
>> are/adv_dbg_if/rtl/verilog/adbg_or1k_module.v
>>          (I think I asked you to look at this before)
>>
>>
>> Yes. JTAG is used in adv_dbg_sys. But we don't need any specific protocol.
>>
>>
>>          Commands
>>            0x0 - NOP
>>            0x3 - cpu register burst setup write
>>            0x7 - cpu register burst setup read
>>            0x9 - module internal register write
>>            0xd - module internal register select
>>
>>          cpu register burst read/write
>>            [ 0 |  Opcode (0x3/0x7) | Address  | Count ]
>>
>>            Here Address is the CPU Register Address
>>
>>          Read/Write are then not send with opcodes, just data
>>            Burst write
>>            [ match | crc | status | Data | Start ]
>>
>>            Burst read
>>            [ CRC  |  Data | Status ]
>>
>>           Here Data is the register data
>>
>>          Status register Select (There is only a single 2-bit internal
>>     register)
>>            [ 0    |  Opcode (0xd) | Index 0 ]
>>
>>            Status Register Read
>>            (Send nop command)
>>
>>            Status Register Write
>>            [ 0 | Opcode (0x9) | Index (0x0) | Data (2-bits) ]
>>
>>            Status Register contents 2 bits.
>>            [ Reset | Stall ]
>>
>>     So in summary, there are 2 parts here
>>        - Reading/Writing registers looks exactly like memory.  All
>>     registers are all
>>          in the same address space. (Actually in OpenRISC the GPRS can
>>     also be
>>          accessed via SPR space, that is what is done here)
>>        - Reading/Writing the status bit to Stall or Reset the processor
>>     or just get
>>          the stall status.
>>
>>     Note adv_debug_if support burst mode to get around having to send an
>>     address and
>>     data command for each read/write.  We could think about a burst
>>     interface, but
>>     currently the software side (OpenOCD) does not use that.
>>
>>     Also Note, the interface has nothing OpenRISC specific.  It doesnt
>>     really even
>>     mention OpenRISC in the spec. It says:
>>
>>        "
>>        The CPU interface is designed to connect to an OR1200 processor,
>>     or any
>>        other CPU which uses the same debug ports.
>>
>>        "
>>
>>
>> As per the above information and my understanding, following changes
>> should be made to Core Debug Module:
>>
>> 1. No need for the register map. We can include this information on the
>> software side.
>>
>> 2. CDM should focus on:
>> a. reading/writing of registers. We can use an interface similar to MAM:
>>
>> https://opensocdebug.readthedocs.io/en/latest/02_spec/07_mod
>> ules/mam/datainterface.html
>>
>> It supports both single word and burst read/write access.
>>
>> b. stall packet
>>
>> 3. As Stafford mentioned above, this implementation will ensure that CDM
>> is core independent.
>>
>
> Sounds reasonable.
>
>
>
>>
>>
>>     Next Steps
>>       - Read OpenOCD code
>>       - Read openrisc target code for GDB (optional)
>>       - Adapt the ideas in the adv debug interface to the OSD CDM spec.
>>
>>
>> I will surely go through these resources to get a better insight.
>>
>>
>>     -Stafford
>>
>>
>> - Shivam Aggarwal
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.librecores.org/pipermail/opensocdebug/attachments/20180525/0ead80be/attachment-0001.html>


More information about the OpenSoCDebug mailing list