Hi Everyone,
I’m tring to add semi-hosting support to my application which i’m building with freedom-e-sdk. As many you already know that semi-hosting is already implemented in “micro-os-plus” but in my case i’m trying to run my application without any OS. To understand and use semi-hosting in my application which i’m building using freedom-e-sdk, i did the following
-
downloaded and built latest openocd 8dd5d which supports riscv semi-hosting
-
Modified led_fade program to send a string “Hello Semi” and print it openocd console.
-
I have copied semi-hosting implementation from “micro-os-plus” RTOS
-
used run_openocd and run_gdb targets to run the application on hifive1 board.
-
Made changes in top level makefile to add -g3 flag and -Og.
CFLAGS=“-Og -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=medany -g3 -I$(abspath $(MEE_BSP_PATH)/install/include/)”
CXXFLAGS=“-Og -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -g3 -mcmodel=medany -I$(abspath $(MEE_BSP_PATH)/install/include/)” \
Below is the code
// See LICENSE for license details.
// This is the program which ships on the HiFive1
// board, executing out of SPI Flash at 0x20400000.
#include <stdint.h>
#include "platform.h"
#define RISCV_SEMIHOSTING_CALL_NUMBER 7 //added
#define OS_INTEGER_TRACE_SEMIHOSTING_BUFF_ARRAY_SIZE (16)
#ifndef _SIFIVE_HIFIVE1_H
#error "'led_fade' is designed to run on HiFive1 and/or E300 Arty Dev Kit."
#endif
enum semihosting_operation_numbers
{
/*
* ARM semihosting operations, in lexicographic order.
*/
SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */
SEMIHOSTING_SYS_CLOSE = 0x02,
SEMIHOSTING_SYS_CLOCK = 0x10,
SEMIHOSTING_SYS_ELAPSED = 0x30,
SEMIHOSTING_SYS_ERRNO = 0x13,
SEMIHOSTING_SYS_EXIT = 0x18,
SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20,
SEMIHOSTING_SYS_FLEN = 0x0C,
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
SEMIHOSTING_SYS_HEAPINFO = 0x16,
SEMIHOSTING_SYS_ISERROR = 0x08,
SEMIHOSTING_SYS_ISTTY = 0x09,
SEMIHOSTING_SYS_OPEN = 0x01,
SEMIHOSTING_SYS_READ = 0x06,
SEMIHOSTING_SYS_READC = 0x07,
SEMIHOSTING_SYS_REMOVE = 0x0E,
SEMIHOSTING_SYS_RENAME = 0x0F,
SEMIHOSTING_SYS_SEEK = 0x0A,
SEMIHOSTING_SYS_SYSTEM = 0x12,
SEMIHOSTING_SYS_TICKFREQ = 0x31,
SEMIHOSTING_SYS_TIME = 0x11,
SEMIHOSTING_SYS_TMPNAM = 0x0D,
SEMIHOSTING_SYS_WRITE = 0x05,
SEMIHOSTING_SYS_WRITEC = 0x03,
SEMIHOSTING_SYS_WRITE0 = 0x04,
};
static const char msg[] = "Hello Semi\r\n";
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;
}
int dwrite (const void* buf, int nbyte) // Debug channel write.
{
char tmp[OS_INTEGER_TRACE_SEMIHOSTING_BUFF_ARRAY_SIZE];
int togo = nbyte;
if (buf == NULL || nbyte == 0)
{
return 0;
}
const char* cbuf = (const char*) buf;
// Since the single character debug channel is quite slow, try to
// optimize and send a null terminated string, if possible.
if (cbuf[nbyte] == '\0')
{
// send string
os_semihosting_call_host(SEMIHOSTING_SYS_WRITE0, (void*) cbuf);
}
else
{
// If not, use a local buffer to speed things up.
// For re-entrance, this bugger must be allocated on the stack,
// so be cautious with the size.
while (togo > 0)
{
int n = ((togo < sizeof(tmp)) ? togo : sizeof(tmp) - 1);
int i = 0;
for (; i < n; ++i, ++cbuf)
{
tmp[i] = *cbuf;
}
tmp[i] = '\0';
os_semihosting_call_host (SEMIHOSTING_SYS_WRITE0, (void*) tmp);
togo -= n;
}
}
// All bytes written.
return (int) nbyte;
}
int main (void){
// Make sure the HFROSC is on before the next line:
PRCI_REG(PRCI_HFROSCCFG) |= ROSC_EN(1);
// Run off 16 MHz Crystal for accuracy. Note that the
// first line is
PRCI_REG(PRCI_PLLCFG) = (PLL_REFSEL(1) | PLL_BYPASS(1));
PRCI_REG(PRCI_PLLCFG) |= (PLL_SEL(1));
// Turn off HFROSC to save power
PRCI_REG(PRCI_HFROSCCFG) &= ~(ROSC_EN(1));
uint16_t r=0xFF;
uint16_t g=0;
uint16_t b=0;
char c = 0;
// Set up RGB PWM
PWM1_REG(PWM_CFG) = 0;
// To balance the power consumption, make one left, one right, and one center aligned.
PWM1_REG(PWM_CFG) = (PWM_CFG_ENALWAYS) | (PWM_CFG_CMP2CENTER);
PWM1_REG(PWM_COUNT) = 0;
// Period is approximately 244 Hz
// the LEDs are intentionally left somewhat dim,
// as the full brightness can be painful to look at.
PWM1_REG(PWM_CMP0) = 0;
GPIO_REG(GPIO_IOF_SEL) |= ( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET) | (1 << RED_LED_OFFSET));
GPIO_REG(GPIO_IOF_EN ) |= ( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET) | (1 << RED_LED_OFFSET));
GPIO_REG(GPIO_OUTPUT_XOR) &= ~( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET));
GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << RED_LED_OFFSET);
dwrite(msg,sizeof(msg)-1); // send a string to print on debug channel
while(1){
volatile uint64_t * now = (volatile uint64_t*)(CLINT_CTRL_ADDR + CLINT_MTIME);
volatile uint64_t then = *now + 100;
while (*now < then) { }
if(r > 0 && b == 0){
r--;
g++;
}
if(g > 0 && r == 0){
g--;
b++;
}
if(b > 0 && g == 0){
r++;
b--;
}
uint32_t G = g;
uint32_t R = r;
uint32_t B = b;
PWM1_REG(PWM_CMP1) = G << 4; // PWM is low on the left, GPIO is low on the left side, LED is ON on the left.
PWM1_REG(PWM_CMP2) = (B << 1) << 4; // PWM is high on the middle, GPIO is low in the middle, LED is ON in the middle.
PWM1_REG(PWM_CMP3) = 0xFFFF - (R << 4); // PWM is low on the left, GPIO is low on the right, LED is on on the right.
}
}
the output on openocd console is:
Info : Found flash device ‘issi is25lp128’ (ID 0x0018609d)
Info : JTAG tap: riscv.cpu tap/device found: 0x10e31913 (mfg: 0x489 (SiFive, Inc.), part: 0x0e31, ver: 0x1)
halted at 0x20401090 due to hardware trigger
halted at 0x20401094 due to step
the output on gdb console when issue run command:
Reading symbols from software/semihost//semihost…
Remote debugging using localhost:3333
0x20401090 in ?? ()
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /media/cdac/OBU/hifive1/freedom-e-sdk/software/semihost/semihost
halted at 0x20401094 due to step
There is no output on either of the (gdb and openocd) consoles.
It is from my understanding that adding semi-hosting syscall (taken from micro-os-plus) in my application would be sufficient to print string on openocd console (since openocd i’m using has already semi-hosting support).
so the code flow would be dwrite->os_semihosting_call_host->trap_entry(entry.S)->handle_trap(init.c) ; from here debugger (openocd) gets notified about semi-hosting request and handles it. please correct me if i’m wrong.
could any help with how to make it work or where did i go wrong?
Thanks in advance.