Skip to content

Commit 4dc0e03

Browse files
author
Robert Schöftner
committed
add hal_extend_int function
helper function to deal with wrap around and extension of lower-width counters to 64bit ints.
1 parent fcd8ed1 commit 4dc0e03

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

src/hal/hal.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,24 @@ extern int hal_get_signal_value_by_name(
692692
extern int hal_get_param_value_by_name(
693693
const char *name, hal_type_t *type, hal_data_u **data);
694694

695+
/***********************************************************************
696+
* MISC HELPER FUNCTIONS *
697+
************************************************************************/
698+
699+
/** hal_extend_counter() extends a counter value with nbits to 64 bits.
700+
701+
For some hardware counters it may be desireable to extend their
702+
range beyond their native width.
703+
704+
This function maintains a 64bit counter value and deals with wrap
705+
arounds. Increments between updates need to be less than 2**(nbits-1).
706+
Call with current 64bit counter value to be updated as @param old,
707+
new lower-bit counter value read from hardware as @param newlow
708+
and width of counter as @param nbits.
709+
@returns new counter 64bit counter value.
710+
Code by Jeff Epler. */
711+
extern rtapi_s64 hal_extend_int(rtapi_s64 old, rtapi_s64 newlow, int nbits);
712+
695713
/***********************************************************************
696714
* EXECUTION RELATED FUNCTIONS *
697715
************************************************************************/
@@ -983,6 +1001,41 @@ extern bool hal_stream_writable(hal_stream_t *stream);
9831001
extern void hal_stream_wait_writable(hal_stream_t *stream, sig_atomic_t *stop);
9841002
#endif
9851003

1004+
1005+
/***********************************************************************
1006+
* MISC HELPER FUNCTIONS *
1007+
************************************************************************/
1008+
1009+
static inline rtapi_s64 hal_extend_counter(rtapi_s64 old, rtapi_s64 newlow, int nbits)
1010+
{
1011+
/* Extend low-bit-width counter value to 64bit, counting wrap arounds resp.
1012+
"rotations" in additional bits.
1013+
1014+
see https://github.com/LinuxCNC/linuxcnc/pull/3932#issuecomment-4239206615
1015+
This code avoids branches and undefined behaviour due to signed overflow
1016+
Idea from MicroPython.
1017+
1018+
To avoid messy code to sign extend a lower-width value to 64bits, shift
1019+
the counter value such that the sign bit gets into the MSB.
1020+
Calculate the delta from the stored value in the shifted base.
1021+
Shifting back the delta assures the sign is extended properly.
1022+
Addition as unsigned avoids signed overflow, which would be undefined
1023+
behaviour.
1024+
1025+
Attention has to be paied that the magnitude of increments / decrements
1026+
of the counter stay within 1<<(nshift-1) between calls to this function,
1027+
else the wrap around will be counted in the wrong direction.
1028+
1029+
Code contributed by Jeff Epler.
1030+
*/
1031+
int nshift = 64 - nbits;
1032+
rtapi_u64 oldlow_shifted = ((rtapi_u64)old << nshift);
1033+
rtapi_u64 newlow_shifted = ((rtapi_u64)newlow << nshift);
1034+
rtapi_s64 diff_shifted = newlow_shifted - oldlow_shifted;
1035+
return (rtapi_u64)old + (diff_shifted >> nshift);
1036+
}
1037+
1038+
9861039
RTAPI_END_DECLS
9871040

9881041
#endif /* HAL_H */

0 commit comments

Comments
 (0)