Skip to content

Commit

Permalink
libgloss: riscv: Add support of clock() for semihosting
Browse files Browse the repository at this point in the history
It's necessary to implement _times() in libsemihosting to add
support of clock() function. SYS_ELAPSED and SYS_TICKFREQ
semihosting calls are used to get a number of ticks which
could be compatible with clock() interface and CLOCKS_PER_SEC
value.

clock() function from libc must return value which gives us seconds
when it's divided by CLOCKS_PER_SEC. By default, CLOCKS_PER_SEC
is 10**6 for RISC-V. However, semihosting's tick frequency may
differ and usually it's 10**9. Thus, we have to obtain a real value
of the tick frequency for the current semihosting setup and
calculate a multiplier and use it for adjusting semihosting's
number of ticks. E.g., if semihosting's ticks frequency is 10**9
then multiplier is 10**9 / 10**6 = 1000.

Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
  • Loading branch information
kolerov committed May 30, 2024
1 parent b3ed425 commit 27abc6d
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
19 changes: 19 additions & 0 deletions libgloss/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ riscv_libsemihost_a_LIBADD =
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_sbrk.$(OBJEXT) \
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_stat.$(OBJEXT) \
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_stat_common.$(OBJEXT) \
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_times.$(OBJEXT) \
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_unlink.$(OBJEXT) \
@CONFIG_RISCV_TRUE@ riscv/riscv_libsemihost_a-semihost-sys_write.$(OBJEXT)
riscv_libsemihost_a_OBJECTS = $(am_riscv_libsemihost_a_OBJECTS)
Expand Down Expand Up @@ -2829,6 +2830,7 @@ TEXINFO_TEX = ../texinfo/texinfo.tex
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_sbrk.c \
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_stat.c \
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_stat_common.c \
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_times.c \
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_unlink.c \
@CONFIG_RISCV_TRUE@ riscv/semihost-sys_write.c

Expand Down Expand Up @@ -4920,6 +4922,8 @@ riscv/riscv_libsemihost_a-semihost-sys_stat.$(OBJEXT): \
riscv/$(am__dirstamp) riscv/$(DEPDIR)/$(am__dirstamp)
riscv/riscv_libsemihost_a-semihost-sys_stat_common.$(OBJEXT): \
riscv/$(am__dirstamp) riscv/$(DEPDIR)/$(am__dirstamp)
riscv/riscv_libsemihost_a-semihost-sys_times.$(OBJEXT): \
riscv/$(am__dirstamp) riscv/$(DEPDIR)/$(am__dirstamp)
riscv/riscv_libsemihost_a-semihost-sys_unlink.$(OBJEXT): \
riscv/$(am__dirstamp) riscv/$(DEPDIR)/$(am__dirstamp)
riscv/riscv_libsemihost_a-semihost-sys_write.$(OBJEXT): \
Expand Down Expand Up @@ -6209,6 +6213,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_sbrk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_stat.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_stat_common.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_unlink.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_write.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@riscv/$(DEPDIR)/riscv_libsemihost_a-sys_chdir.Po@am__quote@
Expand Down Expand Up @@ -8954,6 +8959,20 @@ riscv/riscv_libsemihost_a-semihost-sys_stat_common.obj: riscv/semihost-sys_stat_
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o riscv/riscv_libsemihost_a-semihost-sys_stat_common.obj `if test -f 'riscv/semihost-sys_stat_common.c'; then $(CYGPATH_W) 'riscv/semihost-sys_stat_common.c'; else $(CYGPATH_W) '$(srcdir)/riscv/semihost-sys_stat_common.c'; fi`

riscv/riscv_libsemihost_a-semihost-sys_times.o: riscv/semihost-sys_times.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT riscv/riscv_libsemihost_a-semihost-sys_times.o -MD -MP -MF riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Tpo -c -o riscv/riscv_libsemihost_a-semihost-sys_times.o `test -f 'riscv/semihost-sys_times.c' || echo '$(srcdir)/'`riscv/semihost-sys_times.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Tpo riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='riscv/semihost-sys_times.c' object='riscv/riscv_libsemihost_a-semihost-sys_times.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o riscv/riscv_libsemihost_a-semihost-sys_times.o `test -f 'riscv/semihost-sys_times.c' || echo '$(srcdir)/'`riscv/semihost-sys_times.c

riscv/riscv_libsemihost_a-semihost-sys_times.obj: riscv/semihost-sys_times.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT riscv/riscv_libsemihost_a-semihost-sys_times.obj -MD -MP -MF riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Tpo -c -o riscv/riscv_libsemihost_a-semihost-sys_times.obj `if test -f 'riscv/semihost-sys_times.c'; then $(CYGPATH_W) 'riscv/semihost-sys_times.c'; else $(CYGPATH_W) '$(srcdir)/riscv/semihost-sys_times.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Tpo riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_times.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='riscv/semihost-sys_times.c' object='riscv/riscv_libsemihost_a-semihost-sys_times.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o riscv/riscv_libsemihost_a-semihost-sys_times.obj `if test -f 'riscv/semihost-sys_times.c'; then $(CYGPATH_W) 'riscv/semihost-sys_times.c'; else $(CYGPATH_W) '$(srcdir)/riscv/semihost-sys_times.c'; fi`

riscv/riscv_libsemihost_a-semihost-sys_unlink.o: riscv/semihost-sys_unlink.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(riscv_libsemihost_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT riscv/riscv_libsemihost_a-semihost-sys_unlink.o -MD -MP -MF riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_unlink.Tpo -c -o riscv/riscv_libsemihost_a-semihost-sys_unlink.o `test -f 'riscv/semihost-sys_unlink.c' || echo '$(srcdir)/'`riscv/semihost-sys_unlink.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_unlink.Tpo riscv/$(DEPDIR)/riscv_libsemihost_a-semihost-sys_unlink.Po
Expand Down
1 change: 1 addition & 0 deletions libgloss/riscv/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ multilibtool_LIBRARIES += %D%/libsemihost.a
%D%/semihost-sys_sbrk.c \
%D%/semihost-sys_stat.c \
%D%/semihost-sys_stat_common.c \
%D%/semihost-sys_times.c \
%D%/semihost-sys_unlink.c \
%D%/semihost-sys_write.c

Expand Down
73 changes: 73 additions & 0 deletions libgloss/riscv/semihost-sys_times.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <sys/types.h>
#include <sys/times.h>
#include <machine/syscall.h>
#include "semihost_syscall.h"

clock_t
_times(struct tms *buf)
{
static bool initialized = false;
static clock_t semihosting_tick_freq = 0;
static bool semihosting_tick_freq_bigger = false;
static clock_t semihosting_tick_freq_multiplier = 0;
clock_t elapsed;

/* SYS_ELAPSED semihosting call returns a single 64-bit value for 64-bit
targets and two 32-bit values for 32-bit targets. */
#if __riscv_xlen == 32
uint32_t data_block[2];
#else
uint64_t data_block[1];
#endif

if (!initialized)
{
/* clock() function from libc must return value which gives us seconds
when it's divided by CLOCKS_PER_SEC. By default, CLOCKS_PER_SEC
is 10**6 for RISC-V. However, semihosting's tick frequency may
differ and usually it's 10**9. Thus, we have to obtain a real value
of the tick frequency for the current semihosting setup and
calculate a multiplier and use it for adjusting semihosting's
number of ticks. E.g., if semihosting's ticks frequency is 10**9 then
the multiplier is 10**9 / 10**6 = 1000. */
semihosting_tick_freq = syscall_errno (SEMIHOST_tickfreq, NULL);

if (semihosting_tick_freq > CLOCKS_PER_SEC)
{
semihosting_tick_freq_multiplier = semihosting_tick_freq / CLOCKS_PER_SEC;
semihosting_tick_freq_bigger = true;
}
else
semihosting_tick_freq_multiplier = CLOCKS_PER_SEC / semihosting_tick_freq;

initialized = true;
}

/* SYS_ELAPSED semihosting call returns a number of ticks. */
syscall_errno (SEMIHOST_elapsed, data_block);

#if __riscv_xlen == 32
elapsed = (((uint64_t) data_block[1]) << 32) | ((uint32_t) data_block[0]);
#else
elapsed = data_block[0];
#endif

/* Adjust the number of ticks to make it compatible with CLOCKS_PER_SEC. */
if (semihosting_tick_freq_bigger)
elapsed /= semihosting_tick_freq_multiplier;
else
elapsed *= semihosting_tick_freq_multiplier;

if (buf)
{
buf->tms_utime = elapsed;
buf->tms_stime = 0;
buf->tms_cutime = 0;
buf->tms_cstime = 0;
}

return elapsed;
}

0 comments on commit 27abc6d

Please sign in to comment.