/
tiasnd.c
150 lines (130 loc) · 2.67 KB
/
tiasnd.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
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
// Atari TIA sound generator emulation routines
// Algorithms adapted from the Stella source code (stella.sourceforge.net)
// Matt Sarnoff (www.msarnoff.org)
// October 20, 2010
#import <stdio.h>
#import <stdint.h>
// 4-bit and 5-bit linear feedback shift registers
static uint8_t sr4 = 1;
static uint8_t sr5 = 1;
// Clock the 4-bit register
static inline void shift4()
{
// 4-bit linear feedback shift register, taps at bits 3 and 2
sr4 = ((sr4 << 1) | (!!(sr4 & 0x08) ^ !!(sr4 & 0x04))) & 0x0F;
}
// Clock the 5-bit register
static inline void shift5()
{
// 5-bit linear feedback shift register, taps at bits 4 and 2
sr5 = ((sr5 << 1) | (!!(sr5 & 0x10) ^ !!(sr5 & 0x04))) & 0x1F;
}
// Generates the bit pattern 01010101...
static inline void div4_two()
{
sr4 = ((sr4 << 1) | (!(sr4 & 0x01))) & 0x0F;
}
// Generates the bit pattern 000111000111...
static inline void div4_six()
{
sr4 = (~sr4 << 1) | (!(!(!(sr4 & 0x04) && ((sr4 & 0x07)))));
}
// TIA waveform 1
static void wave_poly4()
{
shift4();
}
// TIA waveform 2
static void wave_div31poly4()
{
shift5();
// 5-bit register clocks 4-bit register
if ((sr5 & 0x0F) == 0x08)
shift4();
}
// TIA waveform 3
static void wave_poly5poly4()
{
shift5();
// 5-bit register clocks 4-bit register
if (sr5 & 0x10)
shift4();
}
// TIA waveforms 4 and 5
static void wave_div2()
{
div4_two();
}
// TIA waveform 6
static void wave_div31div2()
{
shift5();
if ((sr5 & 0x0F) == 0x08)
div4_two();
}
// TIA waveform 7
static void wave_poly5div2()
{
shift5();
if (sr5 & 0x10)
div4_two();
}
// TIA waveform 8
static void wave_poly9()
{
// taps at bits 8 and 4
sr5 = (sr5 << 1) | (!!(sr4 & 0x08) ^ !!(sr5 & 0x10));
sr4 = ((sr4 << 1) | (!!(sr5 & 0x20))) & 0x0F;
sr5 &= 0x1F;
}
// TIA waveform 9
static void wave_poly5()
{
sr5 = (sr5 << 1) | (!!(sr5 & 0x10) ^ !!(sr5 & 0x04));
sr4 = ((sr4 << 1) | (!!(sr5 & 0x20))) & 0x0F;
sr5 &= 0x1F;
}
// TIA waveform A
static void wave_div31()
{
shift5();
if ((sr5 & 0x0F) == 0x08)
sr4 = ((sr4 << 1) | (!!(sr5 & 0x10))) & 0x0F;
}
// TIA waveforms C and D
static void wave_div6()
{
div4_six();
}
// TIA waveform E
static void wave_div31div6()
{
shift5();
if ((sr5 & 0x0F) == 0x08)
div4_six();
}
// TIA waveform F
static void wave_poly5div6()
{
shift5();
if (sr5 & 0x10)
div4_six();
}
typedef void (*wavefnptr)();
static wavefnptr wavefns[8] = {
wave_poly4,
wave_poly5poly4,
wave_div2,
wave_div31div2,
wave_poly5div2,
wave_poly9,
wave_poly5,
wave_poly5div6,
};
// Generate and return one sample of the specified waveform
// Sample value is 0 or 1.
uint8_t tia_out(uint8_t waveformnum)
{
wavefns[waveformnum & 0x07]();
return !!(sr4 & 0x08);
}