SpinalHDL / openocd_riscv

Spen's Official OpenOCD Mirror
Other
45 stars 33 forks source link

enabled semihosting on vexriscv #7

Closed shufps closed 4 years ago

shufps commented 4 years ago

This change enables ARM-compatible semihosting on VexRiscV.

If the target gets halt in single-step or running-mode it checks for the "magic" instruction sequence of

slli x0, x0, 0x1f 
ebreak
srai x0, x0, 0x7

This sequence is defined in the "Volume I: RISC-V Unprivileged ISA V20190608-Base-Ratified" PDF.

Since DPC and DCSR are not implemented in VexRiscV, it uses the PC to find out if it is a semihosting-call.

If it is one, it calls the ARM-semihosting code ... In theory (not tested) all semihosting calls should be supported.

The GnuARM-plugin can do example-projects for RISC-V microcontrollers from SiFive. Such projects already provide compliant semihosting-calls.

The change was tested with such an example-project and is working fine.

Buuuut ... since the change was done quite fast within a couple of hours, I didn't invest time in much error-handling. Also I don't know what the target-state "TARGET_DEBUG_RUNNING" is.

For me, it's working fine but to be merged in the repository there would probably a little bit of work needed.

Dolu1990 commented 4 years ago

Those CSR aren't implemented because VexRiscv do not implement debuging in the RISC-V specified way to save area.

I will check the PR, thanks :D

Dolu1990 commented 4 years ago

Magic :D Do you have some sample for the C code allowing for instance to send console characters from the target ?

About TARGET_DEBUG_RUNNING, that's still quite not well etablished what it is for me too ... Most of the VexRIscv openocd port is about copypasting code from example XD

Dolu1990 commented 4 years ago

@shufps ping :)

shufps commented 4 years ago

Oh sorry, don't read github very often lol ...

// The hint that differentiates the semihosting call.
#define RISCV_SEMIHOSTING_CALL_NUMBER 7
#define SEMIHOSTING_SYS_WRITEC 0x03
#define SEMIHOSTING_SYS_WRITE0 0x04
// ----------------------------------------------------------------------------

  static inline int
  __attribute__ ((always_inline))
  os_semihosting_call_host (int reason, void* arg)
  {
    register int value asm ("a0") = reason;
    register void* ptr asm ("a1") = arg;

    asm volatile (

        // Workaround for RISC-V lack of multiple EBREAKs.
        " .option push \n"
        " .option norvc \n"
        " slli x0, x0, 0x1f \n"
        " ebreak \n"
        " srai x0, x0, %[swi] \n"
        " .option pop \n"

        : "=r" (value) /* Outputs */
        : "0" (value), "r" (ptr), [swi] "i" (RISCV_SEMIHOSTING_CALL_NUMBER) /* Inputs */
        : "memory" /* Clobbers */
    );

    return value;
  }

  inline int
  __attribute__ ((always_inline))
  call_host (int reason, void* arg)
  {
    return os_semihosting_call_host (reason, arg);
  }

you can call it with call_host(SEMIHOSTING_SYS_WRITE0, "hello world\n")

The crazy thing on semihosting is that when calling the debugger with e.g. WRITE0 it will then get the pointer to the string as parameter and the debugging host will read out the memory of the target via the debugging interface and then print it to console. So, they don't transfer lots of data but only a pointer to data and the command what should be done with it. Genious xD

But first enable semihosting with arm semihosting enable in openocd.

It uses the ARM semihosting code, so probably everything should be supported - like reading and writing files on the Debugging-Host, but I didn't test it :)

GnuARM-Plugin for RISC-V has a nice lib which supports the semihosting calls via e.g. trace_printf - it's compatible, I used it in my project :) The code above is only a minimum-extract from their library :)

shufps commented 4 years ago

pong @Dolu1990 ;-)

Dolu1990 commented 4 years ago

Ahhhhhh forgot about it, sorry XD