1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#ifndef __UTIL_H
12#define __UTIL_H
13
14#define MASK(n) (BIT(n)-1ul)
15#define IS_ALIGNED(n, b) (!((n) & MASK(b)))
16#define ROUND_DOWN(n, b) (((n) >> (b)) << (b))
17#define ROUND_UP(n, b) (((((n) - 1ul) >> (b)) + 1ul) << (b))
18#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19#define MIN(a,b) (((a)<(b))?(a):(b))
20#define MAX(a,b) (((a)>(b))?(a):(b))
21#define PASTE(a, b) a ## b
22#define _STRINGIFY(a) #a
23#define STRINGIFY(a) _STRINGIFY(a)
24
25/* time constants */
26#define MS_IN_S     1000llu
27
28#ifndef __ASSEMBLER__
29
30#define NULL ((void *)0)
31#define BIT(n) (1ul << (n))
32#define UL_CONST(x) PASTE(x, ul)
33
34#define PACKED       __attribute__((packed))
35#define NORETURN     __attribute__((__noreturn__))
36#define CONST        __attribute__((__const__))
37#define PURE         __attribute__((__pure__))
38#define ALIGN(n)     __attribute__((__aligned__(n)))
39#define FASTCALL     __attribute__((fastcall))
40#ifdef __clang__
41#define VISIBLE      /* nothing */
42#else
43#define VISIBLE      __attribute__((externally_visible))
44#endif
45#define NO_INLINE    __attribute__((noinline))
46#define FORCE_INLINE __attribute__((always_inline))
47#define SECTION(sec) __attribute__((__section__(sec)))
48#define UNUSED       __attribute__((unused))
49#define USED         __attribute__((used))
50#define FASTCALL     __attribute__((fastcall))
51#define FORCE_O2     __attribute__((optimize("O2")))
52/** MODIFIES: */
53void __builtin_unreachable(void);
54#define UNREACHABLE()  __builtin_unreachable()
55#define MAY_ALIAS    __attribute__((may_alias))
56
57#define OFFSETOF(type, member) \
58    __builtin_offsetof(type, member)
59
60#ifdef __GNUC__
61/* Borrowed from linux/include/linux/compiler.h */
62#define likely(x)   __builtin_expect(!!(x), 1)
63#define unlikely(x) __builtin_expect(!!(x), 0)
64#else
65#define likely(x)   (!!(x))
66#define unlikely(x) (!!(x))
67#endif
68
69/* need that for compiling with c99 instead of gnu99 */
70#define asm __asm__
71
72/* Evaluate a Kconfig-provided configuration setting at compile-time. */
73#define config_set(macro) _is_set_(macro)
74#define _macrotest_1 ,
75#define _is_set_(value) _is_set__(_macrotest_##value)
76#define _is_set__(comma) _is_set___(comma 1, 0)
77#define _is_set___(_, v, ...) v
78
79/* Check the existence of a configuration setting, returning one value if it
80 * exists and a different one if it does not */
81#define config_ternary(macro, true, false) _config_ternary(macro, true, false)
82#define _config_ternary(value, true, false) _config_ternary_(_macrotest_##value, true, false)
83#define _config_ternary_(comma, true, false) _config_ternary__(comma true, false)
84#define _config_ternary__(_, v, ...) v
85
86/** MODIFIES:
87    FNSPEC
88        halt_spec: "\<Gamma> \<turnstile> {} Call halt_'proc {}"
89*/
90void halt(void) NORETURN;
91void memzero(void *s, unsigned long n);
92void *memset(void *s, unsigned long c, unsigned long n) VISIBLE;
93void *memcpy(void* ptr_dst, const void* ptr_src, unsigned long n) VISIBLE;
94int PURE strncmp(const char *s1, const char *s2, int n);
95long CONST char_to_long(char c);
96long PURE str_to_long(const char* str);
97
98
99int __builtin_clzl (unsigned long x);
100int __builtin_ctzl (unsigned long x);
101
102#ifdef CONFIG_ARCH_RISCV
103uint32_t __clzsi2(uint32_t x);
104uint32_t __ctzsi2(uint32_t x);
105uint32_t __clzdi2(uint64_t x);
106uint32_t __ctzdi2(uint64_t x);
107#endif
108/** MODIFIES: */
109/** DONT_TRANSLATE */
110/** FNSPEC clzl_spec:
111  "\<forall>s. \<Gamma> \<turnstile>
112    {\<sigma>. s = \<sigma> \<and> x_' s \<noteq> 0 }
113      \<acute>ret__long :== PROC clzl(\<acute>x)
114    \<lbrace> \<acute>ret__long = of_nat (word_clz (x_' s)) \<rbrace>"
115*/
116static inline long
117CONST clzl(unsigned long x)
118{
119    return __builtin_clzl(x);
120}
121
122/** MODIFIES: */
123/** DONT_TRANSLATE */
124/** FNSPEC ctzl_spec:
125  "\<forall>s. \<Gamma> \<turnstile>
126    {\<sigma>. s = \<sigma> \<and> x_' s \<noteq> 0 }
127      \<acute>ret__long :== PROC ctzl(\<acute>x)
128    \<lbrace> \<acute>ret__long = of_nat (word_ctz (x_' s)) \<rbrace>"
129*/
130static inline long
131CONST ctzl(unsigned long x)
132{
133    return __builtin_ctzl(x);
134}
135
136#define CTZL(x) __builtin_ctzl(x)
137
138int __builtin_popcountl (unsigned long x);
139
140/** DONT_TRANSLATE */
141static inline long
142CONST popcountl(unsigned long mask)
143{
144#ifndef __POPCNT__
145    unsigned int count; // c accumulates the total bits set in v
146    for (count = 0; mask; count++) {
147        mask &= mask - 1; // clear the least significant bit set
148    }
149
150    return count;
151#else
152    return __builtin_popcountl(mask);
153#endif
154}
155
156#define POPCOUNTL(x) popcountl(x)
157
158/* Can be used to insert padding to the next L1 cache line boundary */
159#define PAD_TO_NEXT_CACHE_LN(used) char padding[L1_CACHE_LINE_SIZE - ((used) % L1_CACHE_LINE_SIZE)]
160
161#else /* __ASSEMBLER__ */
162
163/* Some assemblers don't recognise ul (unsigned long) suffix */
164#define BIT(n) (1 << (n))
165#define UL_CONST(x) x
166
167#endif /* !__ASSEMBLER__ */
168#endif /* __UTIL_H */
169