summaryrefslogtreecommitdiff
path: root/n/avr
diff options
context:
space:
mode:
Diffstat (limited to 'n/avr')
-rw-r--r--n/avr/modules/math/fixed/fixed.h4
-rw-r--r--n/avr/modules/math/fixed/fixed.txt50
-rw-r--r--n/avr/modules/math/fixed/test/Makefile17
-rw-r--r--n/avr/modules/math/fixed/test/test_fixed.c105
4 files changed, 165 insertions, 11 deletions
diff --git a/n/avr/modules/math/fixed/fixed.h b/n/avr/modules/math/fixed/fixed.h
index 2337b1c..4f9f77f 100644
--- a/n/avr/modules/math/fixed/fixed.h
+++ b/n/avr/modules/math/fixed/fixed.h
@@ -54,11 +54,11 @@ fixed_div_f824 (int32_t a, int32_t b);
#else /* HOST */
/** Multiply f8.24 by f8.24, return f8.24. */
-#define fixed_mul_f824(a, b) (((uint64_t) (a) * (uint64_t) (b) \
+#define fixed_mul_f824(a, b) (((int64_t) (a) * (int64_t) (b) \
+ 0x800000LL) >> 24)
/** Divide f8.24 by f8.24, return f8.24. */
-#define fixed_div_f824(a, b) (((uint64_t) (a) << 24) / (uint64_t) (b))
+#define fixed_div_f824(a, b) (((int64_t) (a) << 24) / (int64_t) (b))
#endif
diff --git a/n/avr/modules/math/fixed/fixed.txt b/n/avr/modules/math/fixed/fixed.txt
new file mode 100644
index 0000000..4c0ddc3
--- /dev/null
+++ b/n/avr/modules/math/fixed/fixed.txt
@@ -0,0 +1,50 @@
+*Title: Module AVR math à virgule fixe
+*Author: Ni
+
+* La virgule fixe
+
+Le format à virgule fixe, à opposer à la virgule flottante, divise un mot
+binaire en deux parties, la partie entière et la partie fractionnaire.
+
+L'inconvénient par rapport à la virgule flottante, c'est de pouvoir
+représenter une plage plus petite de nombres. Il faut aussi faire très
+attention de ne pas déborder lors des calculs intermédiaires.
+
+L'avantage, c'est la vitesse d'exécution, ça tombe bien, on est pressé !
+
+Je vous laisse consulter internet pour plus d'informations.
+
+* Notation des nombres
+
+Pour décoder le nom des fonctions :
+
+ [u]{i|f}x[.y]
+
+ [u] non signé ;
+ [i] entier ;
+ [f] virgule fixe ;
+ [x] taille de la partie entière en bits ;
+ [y] taille de la partie fractionnaire en bits.
+
+Par exemple :
+
+ [i16] mot signé 16 bits ;
+ [uf24.8] nombre en virgule fixe non signé, avec 24 bits pour la partie
+ entière et 8 bits pour la partie fractionnaire.
+
+* Format des angles
+
+Les angles utilisés sont dans l'intervalle [0 ; 1[. La valeur 1 correspond à 2
+pi radians, soit un tour complet. Le sens des angles orientés est le sens
+trigonométrique bien sur.
+
+* Routines de tests
+
+Pour tester les algorithmes, on compile test_fixed pour hôte et pour AVR. On
+lance les deux et l'on compare les résultats, ils doivent être identiques.
+
+La version hôte vérifie les calculs avec la bibliothèque mathématique du C.
+
+* Doc
+
+*File: uart.exd
diff --git a/n/avr/modules/math/fixed/test/Makefile b/n/avr/modules/math/fixed/test/Makefile
index 38517e5..c690212 100644
--- a/n/avr/modules/math/fixed/test/Makefile
+++ b/n/avr/modules/math/fixed/test/Makefile
@@ -12,6 +12,21 @@ AVR_MCU = atmega128
OPTIMIZE = -O2
DEFS =
-LIBS =
+HOST_LIBS = -lm
include $(BASE)/make/Makefile.gen
+
+EXTRA_CLEAN_FILES += test_fixed.mul test_fixed.div test_fixed.cos \
+ test_fixed.sqrt
+
+test_fixed.mul: test_fixed.host
+ echo '!m' | ./$< > $@
+
+test_fixed.div: test_fixed.host
+ echo '!d' | ./$< > $@
+
+test_fixed.cos: test_fixed.host
+ echo '!c' | ./$< > $@
+
+test_fixed.sqrt: test_fixed.host
+ echo '!s' | ./$< > $@
diff --git a/n/avr/modules/math/fixed/test/test_fixed.c b/n/avr/modules/math/fixed/test/test_fixed.c
index 35ea573..ff826d4 100644
--- a/n/avr/modules/math/fixed/test/test_fixed.c
+++ b/n/avr/modules/math/fixed/test/test_fixed.c
@@ -30,6 +30,72 @@
#include "modules/utils/utils.h"
#include "io.h"
+#ifdef HOST
+
+#include <math.h>
+#include <fenv.h>
+#include <stdio.h>
+
+static void
+check_mul (int32_t a, int32_t b, int32_t r)
+{
+ feclearexcept (FE_ALL_EXCEPT);
+ double af = (double) a / (1 << 24);
+ double bf = (double) b / (1 << 24);
+ int32_t ri = rint (af * bf * (1 << 24));
+ if (r != ri && !fetestexcept (FE_INVALID))
+ printf ("error: %08x * %08x != %08x (%08x)\n", a, b, r, ri);
+}
+
+static void
+check_div (int32_t a, int32_t b, int32_t r)
+{
+ feclearexcept (FE_ALL_EXCEPT);
+ double af = (double) a / (1 << 24);
+ double bf = (double) b / (1 << 24);
+ int32_t ri = af / bf * (1 << 24);
+ if (r != ri && !fetestexcept (FE_INVALID))
+ printf ("error: %08x / %08x != %08x (%08x)\n", a, b, r, ri);
+}
+
+static void
+check_cos (int32_t a, int32_t rc, int32_t rs)
+{
+ double af = (double) a / (1 << 24) * 2 * M_PI;
+ int32_t rci = cos (af) * (1 << 24);
+ if (rc != rci)
+ printf ("error: cos (%08x) != %08x (%08x%+d)\n",
+ a, rc, rci, rc - rci);
+ int32_t rsi = sin (af) * (1 << 24);
+ if (rs != rsi)
+ printf ("error: sin (%08x) != %08x (%08x%+d)\n",
+ a, rs, rsi, rs - rsi);
+}
+
+static void
+check_sqrt (uint32_t a, uint32_t rf, uint16_t ri)
+{
+ double aff = (double) a / (1 << 8);
+ uint32_t rfi = sqrt (aff) * (1 << 8);
+ if (rf != rfi)
+ printf ("error: sqrt_f (%08x) != %08x (%08x%+d)\n",
+ a, rf, rfi, rf - rfi);
+ double aif = (double) a;
+ uint16_t rii = sqrt (aif);
+ if (ri != rii)
+ printf ("error: sqrt_i (%08x) != %04x (%04x%+d)\n",
+ a, ri, rii, ri - rii);
+}
+
+#else
+
+# define check_mul(a, b, r)
+# define check_div(a, b, r)
+# define check_cos(a, rc, rs)
+# define check_sqrt(a, rf, ri)
+
+#endif
+
void
proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
{
@@ -54,9 +120,13 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
bl = patl[bp] >> bs;
proto_send2d ('a', al, bl);
rl[0] = fixed_mul_f824 (al, bl);
+ check_mul (al, bl, rl[0]);
rl[1] = fixed_mul_f824 (-al, bl);
+ check_mul (-al, bl, rl[1]);
rl[2] = fixed_mul_f824 (al, -bl);
+ check_mul (al, -bl, rl[2]);
rl[3] = fixed_mul_f824 (-al, -bl);
+ check_mul (-al, -bl, rl[3]);
proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]);
}
for (i = 0; i < 64000; i++)
@@ -65,9 +135,13 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
bl = random_u32 ();
proto_send2d ('a', al, bl);
rl[0] = fixed_mul_f824 (al, bl);
+ check_mul (al, bl, rl[0]);
rl[1] = fixed_mul_f824 (-al, bl);
+ check_mul (-al, bl, rl[1]);
rl[2] = fixed_mul_f824 (al, -bl);
+ check_mul (al, -bl, rl[2]);
rl[3] = fixed_mul_f824 (-al, -bl);
+ check_mul (-al, -bl, rl[3]);
proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]);
}
break;
@@ -75,35 +149,47 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
for (ap = 0; ap < patn; ap++)
for (bp = 0; bp < patn; bp++)
for (as = 0; as < 32; as++)
- for (bs = 0; bs < 32; bs++)
+ for (bs = 0; bs < 31; bs++)
{
al = patl[ap] >> as;
bl = patl[bp] >> bs;
proto_send2d ('a', al, bl);
rl[0] = fixed_div_f824 (al, bl);
+ check_div (al, bl, rl[0]);
rl[1] = fixed_div_f824 (-al, bl);
+ check_div (-al, bl, rl[1]);
rl[2] = fixed_div_f824 (al, -bl);
+ check_div (al, -bl, rl[2]);
rl[3] = fixed_div_f824 (-al, -bl);
+ check_div (-al, -bl, rl[3]);
proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]);
}
for (i = 0; i < 64000; i++)
{
al = random_u32 ();
bl = random_u32 ();
- proto_send2d ('a', al, bl);
- rl[0] = fixed_div_f824 (al, bl);
- rl[1] = fixed_div_f824 (-al, bl);
- rl[2] = fixed_div_f824 (al, -bl);
- rl[3] = fixed_div_f824 (-al, -bl);
- proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]);
+ if (bl != 0)
+ {
+ proto_send2d ('a', al, bl);
+ rl[0] = fixed_div_f824 (al, bl);
+ check_div (al, bl, rl[0]);
+ rl[1] = fixed_div_f824 (-al, bl);
+ check_div (-al, bl, rl[1]);
+ rl[2] = fixed_div_f824 (al, -bl);
+ check_div (al, -bl, rl[2]);
+ rl[3] = fixed_div_f824 (-al, -bl);
+ check_div (-al, -bl, rl[3]);
+ proto_send4d ('r', rl[0], rl[1], rl[2], rl[3]);
+ }
}
break;
case c ('c', 0):
- for (al = 0; al < (1L << 24); al += 1 << 8)
+ for (al = 0; al < (1L << 24); al += 257)
{
proto_send1d ('a', al);
rl[0] = fixed_cos_f824 (al);
rl[1] = fixed_sin_f824 (al);
+ check_cos (al, rl[0], rl[1]);
proto_send2d ('r', rl[0], rl[1]);
}
for (i = 0; i < 64000; i++)
@@ -112,6 +198,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
proto_send1d ('a', al);
rl[0] = fixed_cos_f824 (al);
rl[1] = fixed_sin_f824 (al);
+ check_cos (al, rl[0], rl[1]);
proto_send2d ('r', rl[0], rl[1]);
}
break;
@@ -123,6 +210,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
proto_send1d ('a', al);
rl[0] = fixed_sqrt_uf248 (al);
rl[1] = fixed_sqrt_ui32 (al);
+ check_sqrt (al, rl[0], rl[1]);
proto_send2d ('r', rl[0], rl[1]);
}
for (i = 0; i < 64000; i++)
@@ -131,6 +219,7 @@ proto_callback (uint8_t cmd, uint8_t size, uint8_t *args)
proto_send1d ('a', al);
rl[0] = fixed_sqrt_uf248 (al);
rl[1] = fixed_sqrt_ui32 (al);
+ check_sqrt (al, rl[0], rl[1]);
proto_send2d ('r', rl[0], rl[1]);
}
break;