forked from mmitch/gbsplay
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gblfsr.c
92 lines (80 loc) · 2.12 KB
/
gblfsr.c
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
/*
* gbsplay is a Gameboy sound player
*
* 2003-2024 (C) by Tobias Diedrich <ranma+gbsplay@tdiedrich.de>
* Christian Garbs <mitch@cgarbs.de>
*
* Licensed under GNU GPL v1 or, at your option, any later version.
*/
#include "gblfsr.h"
#include "test.h"
#define FB_6 (1 << 6)
#define MASK_FULL ((1 << 15) - 1)
#define MASK_NARROW ((1 << 7) - 1)
void gblfsr_reset(struct gblfsr* gblfsr) {
gblfsr->lfsr = MASK_FULL;
gblfsr->narrow = false;
}
void gblfsr_trigger(struct gblfsr* gblfsr) {
gblfsr->lfsr = MASK_FULL;
}
void gblfsr_set_narrow(struct gblfsr* gblfsr, bool narrow) {
gblfsr->narrow = narrow;
}
int gblfsr_next_value(struct gblfsr* gblfsr) {
uint32_t val = gblfsr->lfsr;
uint32_t shifted = val >> 1;
uint32_t xor_out = (val ^ shifted) & 1; /* TAP_0 ^ TAP_1 */
uint32_t wide = shifted | (xor_out << 14); /* FB_14 */
uint32_t narrow = (wide & ~FB_6) | (xor_out * FB_6);
uint32_t new = gblfsr->narrow ? narrow : wide;
gblfsr->lfsr = new;
return new & 1;
}
test void test_lsfr()
{
struct gblfsr state;
uint32_t x = 0;
int n;
/* Full period should be 32767 */
gblfsr_reset(&state);
n = 0;
do {
gblfsr_next_value(&state);
n++;
} while ((state.lfsr & MASK_FULL) != MASK_FULL && n < 99999);
ASSERT_EQUAL("%d", n, 32767);
/* Narrow period should be 127 */
gblfsr_reset(&state);
gblfsr_set_narrow(&state, true);
n = 0;
do {
gblfsr_next_value(&state);
n++;
} while ((state.lfsr & MASK_NARROW) != MASK_NARROW && n < 999);
ASSERT_EQUAL("%d", n, 127);
/* Test first 32 full output bits from reset */
gblfsr_reset(&state);
for (n = 0; n < 32; n++) {
x <<= 1;
x |= gblfsr_next_value(&state);
}
ASSERT_EQUAL("%08x", x, 0xfffc0008);
/* Test first 32 narrow output bits from reset */
gblfsr_reset(&state);
gblfsr_set_narrow(&state, true);
for (n = 0; n < 32; n++) {
x <<= 1;
x |= gblfsr_next_value(&state);
}
ASSERT_EQUAL("%08x", x, 0xfc0830a3);
/* Test output bits after switching from narrow to long without reset */
gblfsr_set_narrow(&state, false);
for (n = 0; n < 32; n++) {
x <<= 1;
x |= gblfsr_next_value(&state);
}
ASSERT_EQUAL("%08x", x, 0xcbc8b8b3);
}
TEST(test_lsfr);
TEST_EOF;