summaryrefslogtreecommitdiffstats
path: root/firmware/fixpt.h
blob: c6c0b7307c2215435c17bca92bbc74ea1bce190c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#ifndef FIXEDPOINT_H_
#define FIXEDPOINT_H_

#include "util.h"


#ifndef FIXPT_SIZE
  /* Q10.5 */
# define FIXPT_SIZE		24
# define FIXPT_SHIFT		6
#endif

#ifndef FIXPTFLOAT_SIZE
# define FIXPTFLOAT_SIZE	32
#endif


#if FIXPT_SIZE == 8
typedef int8_t fixpt_t;
typedef int16_t fixpt_big_t;
#elif FIXPT_SIZE == 16
typedef int16_t fixpt_t;
typedef int24_t fixpt_big_t;
#elif FIXPT_SIZE == 24
typedef int24_t fixpt_t;
typedef int32_t fixpt_big_t;
#elif FIXPT_SIZE == 32
typedef int32_t fixpt_t;
typedef int64_t fixpt_big_t;
#else
# error "Invalid FIXPT_SIZE"
#endif

#define FIXPT_MAX	((fixpt_t)((1ULL << (FIXPT_SIZE - 1U)) - 1U))
#define FIXPT_MIN	((fixpt_t)(-FIXPT_MAX))


#if FIXPTFLOAT_SIZE == 32
typedef float fixptfloat_t;
#elif FIXPTFLOAT_SIZE == 64
typedef double fixptfloat_t;
#else
# error "Invalid FIXPTFLOAT_SIZE"
#endif


static inline fixpt_big_t fixpt_inflate(fixpt_t a)
{
	return (fixpt_big_t)a;
}

fixpt_t fixpt_deflate(fixpt_big_t a);

static inline fixpt_big_t int_to_fixpt_big(int32_t i)
{
	return (fixpt_big_t)(i << FIXPT_SHIFT);
}

static inline fixpt_t int_to_fixpt(int32_t i)
{
	return fixpt_deflate(int_to_fixpt_big(i));
}

int32_t fixpt_big_to_int(fixpt_big_t p);

static inline int32_t fixpt_to_int(fixpt_t p)
{
	return fixpt_big_to_int(fixpt_inflate(p));
}

#define FLOAT_TO_FIXPT_BIG(f)	((fixpt_big_t)(						\
		((f) < 0.0) ?								\
			(fixpt_big_t)(((f) * (fixptfloat_t)(1L << FIXPT_SHIFT)) - 0.5)	\
		:									\
			(fixpt_big_t)(((f) * (fixptfloat_t)(1L << FIXPT_SHIFT)) + 0.5)	\
	))

#define FLOAT_TO_FIXPT(f)	((fixpt_t)FLOAT_TO_FIXPT_BIG(f))

static inline fixpt_big_t float_to_fixpt_big(fixptfloat_t f)
{
	return (fixpt_big_t)FLOAT_TO_FIXPT_BIG(f);
}

static inline fixpt_t float_to_fixpt(fixptfloat_t f)
{
	return fixpt_deflate(float_to_fixpt_big(f));
}

static inline fixptfloat_t fixpt_big_to_float(fixpt_big_t p)
{
	return (fixptfloat_t)p / (fixptfloat_t)(1L << FIXPT_SHIFT);
}

static inline fixptfloat_t fixpt_to_float(fixpt_t p)
{
	return fixpt_big_to_float(fixpt_inflate(p));
}

/* Get the integer part of a fixpt_t.
 */
int32_t fixpt_get_int_part(fixpt_t p);

/* Get the decimal fractional part of a fixpt_t.
 */
uint32_t fixpt_get_dec_fract(fixpt_t p, uint8_t nr_digits);

/* Calculate: a + b
 */
static inline fixpt_big_t fixpt_big_add(fixpt_big_t a, fixpt_big_t b)
{
	fixpt_big_t tmp;

	tmp = a + b;

	return tmp;
}

/* Calculate: a - b
 */
static inline fixpt_big_t fixpt_big_sub(fixpt_big_t a, fixpt_big_t b)
{
	fixpt_big_t tmp;

	tmp = a - b;

	return tmp;
}

/* Calculate: a * b
 */
fixpt_big_t fixpt_big_mul(fixpt_big_t a, fixpt_big_t b);

/* Calculate: a / b
 */
fixpt_big_t fixpt_big_div(fixpt_big_t a, fixpt_big_t b);

/* Calculate: (a * b) / c
 */
fixpt_big_t fixpt_big_mul_div(fixpt_big_t a, fixpt_big_t b, fixpt_big_t c);

/* Calculate: a + b
 */
static inline fixpt_t fixpt_add(fixpt_t a, fixpt_t b)
{
	fixpt_big_t tmp;

	tmp = fixpt_big_add(fixpt_inflate(a), fixpt_inflate(b));

	return fixpt_deflate(tmp);
}

/* Calculate: a - b
 */
static inline fixpt_t fixpt_sub(fixpt_t a, fixpt_t b)
{
	fixpt_big_t tmp;

	tmp = fixpt_big_sub(fixpt_inflate(a), fixpt_inflate(b));

	return fixpt_deflate(tmp);
}

/* Calculate: a * b
 */
static inline fixpt_t fixpt_mul(fixpt_t a, fixpt_t b)
{
	fixpt_big_t tmp;

	tmp = fixpt_big_mul(fixpt_inflate(a), fixpt_inflate(b));

	return fixpt_deflate(tmp);
}

/* Calculate: a / b
 */
static inline fixpt_t fixpt_div(fixpt_t a, fixpt_t b)
{
	fixpt_big_t tmp;

	tmp = fixpt_big_div(fixpt_inflate(a), fixpt_inflate(b));

	return fixpt_deflate(tmp);
}

/* Calculate: (a * b) / c
 */
static inline fixpt_t fixpt_mul_div(fixpt_t a, fixpt_t b, fixpt_t c)
{
	fixpt_big_t tmp;

	tmp = fixpt_big_mul_div(fixpt_inflate(a),
				fixpt_inflate(b),
				fixpt_inflate(c));

	return fixpt_deflate(tmp);
}

/* Calculate: -a
 */
static inline fixpt_t fixpt_neg(fixpt_t a)
{
	if (a <= FIXPT_MIN)
		return FIXPT_MAX;

	return (fixpt_t)-a;
}

/* Calculate: Absolute value of a
 */
fixpt_t fixpt_abs(fixpt_t a);

/* Calculate: a + b, limited to lo_lim, hi_lim
 */
fixpt_t fixpt_add_limited(fixpt_t a, fixpt_t b,
			  fixpt_t lo_lim, fixpt_t hi_lim);

/* Limit a to lo_lim, hi_lim */
fixpt_t fixpt_clamp(fixpt_t a,
		    fixpt_t lo_lim, fixpt_t hi_lim);

#endif /* FIXEDPOINT_H_ */
bues.ch cgit interface