diff --git a/common/Intrinsics.hs b/common/Intrinsics.hs index b049903..281d30f 100644 --- a/common/Intrinsics.hs +++ b/common/Intrinsics.hs @@ -129,6 +129,29 @@ intrinsicProcs :: [(String, [(A.AbbrevMode, A.Type, String)])] intrinsicProcs = [ ("ASSERT", [(A.ValAbbrev, A.Bool, "value")]) , ("RESCHEDULE", []) + ] ++ concat [ + (zip ["INT" ++ suffix ++ "TOSTRING", "HEX" ++ suffix ++ "TOSTRING"] $ repeat + [ (A.Abbrev, A.Int, "len") + , (A.Abbrev, A.Array [A.UnknownDimension] A.Byte, "string") + , (A.ValAbbrev, A.Int, "n") + ]) + ++ (zip ["STRINGTOINT" ++ suffix, "STRINGTOHEX" ++ suffix] $ repeat + [ (A.Abbrev, A.Bool, "error") + , (A.Abbrev, A.Int, "n") + , (A.ValAbbrev, A.Array [A.UnknownDimension] A.Byte, "string") + ]) + | suffix <- ["","16","32","64"] + ] ++ [ + ("BOOLTOSTRING", + [ (A.Abbrev, A.Int, "len") + , (A.Abbrev, A.Array [A.UnknownDimension] A.Byte, "string") + , (A.ValAbbrev, A.Bool, "b") + ]) + , ("STRINGTOBOOL", + [ (A.Abbrev, A.Bool, "error") + , (A.Abbrev, A.Bool, "b") + , (A.ValAbbrev, A.Array [A.UnknownDimension] A.Byte, "string") + ]) ] rainIntrinsicFunctions :: [(String, ([A.Type], [(A.Type, String)]))] diff --git a/support/tock_support.h b/support/tock_support.h index e95e302..623e8f1 100644 --- a/support/tock_support.h +++ b/support/tock_support.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,26 @@ #endif //}}} +//TODO we should really use more Tock-specific names to avoid clashes + +//We use #define so we can #undef afterwards +#if occam_INT_size == 4 + #define INT int32_t + #define UINT uint32_t +#elif occam_INT_size == 8 + #define INT int64_t + #define UINT uint64_t +#else + #error You must define occam_INT_size when using this header +#endif + +#ifdef __cplusplus +#define BOOL bool +#else +#define BOOL _Bool +#endif + + //{{{ runtime check functions static inline int occam_check_slice (int, int, int, const char *) occam_unused; static inline int occam_check_slice (int start, int count, int limit, const char *pos) { @@ -258,8 +279,61 @@ static inline int occam_check_retype (int src, int dest, const char *pos) { return a * b; \ } +#define MAKE_TOSTRING(type, occname, flag) \ + static inline void occam_##occname##TOSTRING(INT*, char*, const type) occam_unused; \ + static inline void occam_##occname##TOSTRING(INT* len, char* string, const type n) { \ + /* Must use buffer to avoid writing trailing zero: */ char buf[32]; \ + int chars_written = snprintf(buf, 32, flag, n); \ + memcpy(string, buf, chars_written * sizeof(char)); \ + *len = chars_written; \ + } -#define MAKE_ALL_SIGNED(type,flag,utype) \ +#define MAKE_STRINGTO(type, occname, flag) \ + static inline void occam_STRINGTO##occname(BOOL*, type*, const char*) occam_unused; \ + static inline void occam_STRINGTO##occname(BOOL* error, type* n, const char* string) { \ + *error = 1 != sscanf(string, flag, n); \ + } + +#define MAKE_STRINGTO_SMALL(type, occname, flag) \ + static inline void occam_STRINGTO##occname(BOOL*, type*, const char*) occam_unused; \ + static inline void occam_STRINGTO##occname(BOOL* error, type* n, const char* string) { \ + int t; \ + *error = 1 != sscanf(string, flag, &t) || (int)(type)t != t; \ + *n = (type)t; \ + } + +//Same arrangement regardless of our processor size: +#define MAKE_STRINGTO_8 MAKE_STRINGTO_SMALL +#define MAKE_STRINGTO_16 MAKE_STRINGTO_SMALL +#define MAKE_STRINGTO_32 MAKE_STRINGTO +#define MAKE_STRINGTO_64 MAKE_STRINGTO + +static inline void occam_BOOLTOSTRING(INT*, char*, const BOOL) occam_unused; +static inline void occam_BOOLTOSTRING(INT* len, char* str, const BOOL b) { + if (b) { + memcpy(str,"TRUE",4*sizeof(char)); + *len = 4; + } else { + memcpy(str,"FALSE",5*sizeof(char)); + *len = 5; + } +} + +static inline void occam_STRINGTOBOOL(BOOL*, BOOL*, const char*) occam_unused; +static inline void occam_STRINGTOBOOL(BOOL* error, BOOL* b, const char* str) { + if (memcmp("TRUE", str, 4*sizeof(char)) == 0) { + *b = true; + *error = false; + } else if (memcmp("FALSE", str, 5*sizeof(char)) == 0) { + *b = false; + *error = false; + } else { + *error = true; + } +} + + +#define MAKE_ALL_SIGNED(type,bits,flag,hflag,utype) \ MAKE_RANGE_CHECK(type,flag) \ MAKE_ADD(type,flag) \ MAKE_SUBTR(type,flag) \ @@ -270,7 +344,11 @@ static inline int occam_check_retype (int src, int dest, const char *pos) { MAKE_SHIFT(utype, type) \ MAKE_PLUS(type) \ MAKE_MINUS(type) \ - MAKE_TIMES(type) + MAKE_TIMES(type) \ + MAKE_TOSTRING(type, INT##bits, flag) \ + MAKE_TOSTRING(type, HEX##bits, hflag) \ + MAKE_STRINGTO_##bits(type, INT##bits, flag) \ + MAKE_STRINGTO_##bits(type, HEX##bits, hflag) //{{{ uint8_t MAKE_RANGE_CHECK(uint8_t, "%d") @@ -295,20 +373,26 @@ static inline uint8_t occam_rem_uint8_t (uint8_t a, uint8_t b, const char *pos) // we don't define negate for unsigned types //}}} + //{{{ int8_t -MAKE_ALL_SIGNED(int8_t, "%d", uint8_t) +MAKE_ALL_SIGNED(int8_t, 8, "%d", "%x", uint8_t) //}}} //{{{ int16_t -MAKE_ALL_SIGNED(int16_t, "%d", uint16_t) +MAKE_ALL_SIGNED(int16_t, 16, "%d", "%x", uint16_t) //}}} //{{{ int -MAKE_ALL_SIGNED(int, "%d", unsigned int) +//MAKE_ALL_SIGNED(int, "%d", unsigned int) +MAKE_TOSTRING(INT, INT, "%d") +MAKE_TOSTRING(INT, HEX, "%x") +MAKE_STRINGTO(INT, INT, "%d") +MAKE_STRINGTO(INT, HEX, "%x") + //}}} //{{{ int32_t -MAKE_ALL_SIGNED(int32_t, "%d", uint32_t) +MAKE_ALL_SIGNED(int32_t, 32, "%d", "%x", uint32_t) //}}} //{{{ int64_t -MAKE_ALL_SIGNED(int64_t, "%lld", uint64_t) +MAKE_ALL_SIGNED(int64_t, 64, "%lld", "%llx", uint64_t) //}}} // FIXME range checks for float and double shouldn't work this way //{{{ float @@ -398,23 +482,6 @@ int64_t occam_convert_double_int64_t_trunc (double v, const char *pos) { //{{{ intrinsics // FIXME These should do range checks. -//We use #define so we can #undef afterwards -#if occam_INT_size == 4 - #define INT int32_t - #define UINT uint32_t -#elif occam_INT_size == 8 - #define INT int64_t - #define UINT uint64_t -#else - #error You must define occam_INT_size when using this header -#endif - -#ifdef __cplusplus -#define BOOL bool -#else -#define BOOL _Bool -#endif - #include "tock_intrinsics_arith.h" #define REAL float #define RINT int32_t