Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
spu-adsr.c
Go to the documentation of this file.
1// ==========================================================================
2// Validate ADSR envelope via currentVolume changes
3// ==========================================================================
4
5#define ATTACK(step, shift, exp) (\
6 (((step) & 3) << 8) | \
7 (((shift) & 31) << 10) | \
8 (!!(exp) << 15))
9#define DECAY(shift) (\
10 (((shift) & 15) << 4))
11#define SUSTAIN(step, shift, level, direction, exp) (\
12 (((step) & 3) << 22) | \
13 (((shift) & 31) << 24) | \
14 (((level) & 15) << 0) | \
15 (!!(direction) << 30) | \
16 (!!(exp) << 31))
17#define RELEASE(shift, exp) (\
18 (((shift) & 31) << 16) | \
19 (!!(exp) << 21))
20
22// How long each bounded wait below is allowed to take before it gives up and
23// says so. Both numbers come from measuring ENVX on silicon rather than from
24// taste (src/mips/tests/spu-envx): a drain with the release rate forced to the
25// fastest setting completes in one bit-11 tick, and the envelope leaves zero
26// after key-on inside a single sub-tick sample. The caps are an order of
27// magnitude clear of both.
28#define ADSR_DRAIN_MAX_TICKS 16
29#define ADSR_ONSET_MAX_SPINS 2000000
30
31// Given the envelope settings, spit out a currentVolume trace.
32// To avoid jitter and interference, the captured output starts only when
33// the volume changes from 0. The sample rate of the ENVX is a sample every
34// spu_wait_status_bit11_flip call to try separating CPU clock from the
35// SPU clock and increase chances of reproducibility.
36static void spu_adsr_capture(
37 uint32_t adsr, // packed ADSR envelope (see ATTACK/DECAY/SUSTAIN/RELEASE macros)
38 uint16_t* envx_out, // output buffer; must be of length n_samples
39 unsigned n_samples // sample count to capture per SPU status bit11 flip
40) {
41 // Drain the volume left by the previous key-on. The release rate that
42 // actually applies here is whatever the previous case left in the voice,
43 // and the capture helper leaves adsrHi=0x80ff - release shift 31,
44 // exponential - under which ENVX does not decrement at all within three
45 // seconds on silicon. Waiting on that is what hung the suite on hardware.
46 // A release rate can be overridden while it is already in progress, so
47 // force the fastest one before keying off and the drain is a tick.
49 SPU_CTRL = 0x8000 | 0x4000;
51 SPU_VOICES[1].adsrHi = (uint16_t)(RELEASE(0, 0) >> 16);
52 SPU_KEY_OFF_LOW = 0xffff; SPU_KEY_OFF_HIGH = 0xffff;
53 spu_wait_status_bit11_flip();
54 unsigned drain = 0;
55 while (SPU_VOICES[1].currentVolume != 0) {
56 if (++drain > ADSR_DRAIN_MAX_TICKS) {
57 ramsyscall_printf("spu_adsr_capture: drain stalled at envx=%04x after %u ticks\n",
58 SPU_VOICES[1].currentVolume & 0xffff, drain);
59 break;
60 }
61 spu_wait_status_bit11_flip();
62 }
63
64 // prepare envelope, wait for bit11 flip, then fire voice!
65 SPU_VOICES[1].sampleRate = 0x1000;
66 SPU_VOICES[1].sampleStartAddr = SPU_UPLOAD_ADDR >> 3;
67 SPU_VOICES[1].sampleRepeatAddr = SPU_UPLOAD_ADDR >> 3;
68 SPU_VOICES[1].volumeLeft = 0;
69 SPU_VOICES[1].volumeRight = 0;
70 spu_wait_status_bit11_flip();
71 SPU_VOICES[1].adsrLo = (uint16_t)(adsr & 0xFFFF);
72 SPU_VOICES[1].adsrHi = (uint16_t)(adsr >> 16);
74 SPU_KEY_ON_LOW = 1u << 1;
75
76 // Synchronize the SPU by waiting for currentVolume to leave zero. Bounded:
77 // an envelope that never rises would otherwise spin here forever, and the
78 // one-shot end flag can zero ENVX before this ever observes a peak.
79 unsigned onset = 0;
80 while (SPU_VOICES[1].currentVolume == 0) {
81 if (++onset > ADSR_ONSET_MAX_SPINS) {
82 ramsyscall_printf("spu_adsr_capture: envelope never left zero for adsr=%08x\n", adsr);
83 break;
84 }
85 }
86
87 // now capture one sample every bit11 flip
88 envx_out[0] = SPU_VOICES[1].currentVolume;
89 for (unsigned i = 1; i < n_samples; i++) {
90 spu_wait_status_bit11_flip();
91 envx_out[i] = SPU_VOICES[1].currentVolume;
92 }
93
94 // key off, we finished here
95 SPU_KEY_OFF_LOW = 0xffff; SPU_KEY_OFF_HIGH = 0xffff;
96 muteSpu();
97}
98
99static void spu_adsr_capture_with_keyoff(
100 uint32_t adsr,
101 uint16_t* envx_out,
102 unsigned n_samples,
103 unsigned keyoff_at
104) {
105 spu_adsr_capture(adsr, envx_out, keyoff_at + 1);
106 for (unsigned i = keyoff_at + 1; i < n_samples; i++) {
107 spu_wait_status_bit11_flip();
108 envx_out[i] = SPU_VOICES[1].currentVolume;
109 }
110}
111)
112
113// testing an envelope with the current capturing technique in spu_adsr_capture
114// does not lead to exact reproducible samples due to some minor timing
115// differences between the CPU polling and the produced SPU results.
116// The value step is a delta used as margin of error.
117//
118// That margin has a hard floor. ENVX does not move continuously: a linear
119// envelope advances in one discrete increment (sized below) applied once every
120// 1 << max(0, shift - 11) samples. So the whole captured trace is a step
121// function of where key-on landed, and a one-event alignment slip moves every
122// sample in it by a full increment. A window narrower than one increment is not
123// a tolerance at all - it demands an exact alignment the harness cannot deliver,
124// and passes or fails on luck.
125//
126// The increment is not symmetric: a rising envelope steps by (7 - step_field),
127// a falling one by (8 - step_field), so the floor is the larger of the two.
128//
129// RISING IS CONFIRMED ON SILICON. adsr_sustain_up_linear had failed both prior
130// hardware runs at shifts 14 and 16 and passes under this floor, twice.
131//
132// FALLING IS NOT. adsr_sustain_down_linear and adsr_decay_shift still fail at
133// margin 8, so a one-event alignment slip is NOT the whole story for decreasing
134// envelopes and the 64-events-per-index reading below is at best incomplete. Do
135// not widen the floor further to chase them - that was tried at 7 -> 8 and the
136// two tests did not move, which means the mechanism is something else. Note also
137// that decay on this hardware is exponential, not linear, so a fixed increment
138// is the wrong model for adsr_decay_shift regardless.
139//
140// Derived against the checked-in goldens. Rising, at sustain shifts 10/12/14/16:
141// slopes 7168, 1792, 448, 112 ENVX per 512-sample trace index, reproducing
142// exactly under increment 7 at the event rate above. Falling, in
143// adsr_sustain_down_linear and adsr_decay_shift: slope 512 per index, which is
144// 73.1 events under increment 7 and exactly 64 under increment 8. Every block
145// had been toleranced below its own increment; the ones that passed had simply
146// landed well. Floored, the alignment slip is absorbed without giving up any
147// real strictness - 8 on a nominal of 0x4068 is 0.05%.
148//
149// LIMITATION, stated rather than hidden: the floor cannot see the shift, so it
150// applies the shift >= 11 increment. Below that the increment doubles per shift
151// (14 at shift 10), and those call sites are still under-toleranced. The only
152// sustain block in that range currently passes; if it starts flaking, that is
153// this line, not a regression.
154#define ENVX_INCREMENT 8 // max(rising 7, falling 8)
155#define ENVX_MARGIN(step) ((step) < ENVX_INCREMENT ? ENVX_INCREMENT : (step))
156#define ASSERT_ENVX_NEAR(nominal, step, got) \
157 cester_assert_true((got) >= (uint16_t)((nominal) - ENVX_MARGIN(step)) && \
158 (got) <= (uint16_t)((nominal) + ENVX_MARGIN(step)))
159
160CESTER_TEST(adsr_attack_linear_step, spu_tests,
161 int i;
162 uint16_t envx[0x40];
163
164 const uint32_t base = DECAY(0) | SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(0, 0);
165
166 spu_adsr_capture(ATTACK(2, 12, 0) | base, envx, 4);
167 cester_assert_uint_eq(0x0005, envx[0]);
168 ASSERT_ENVX_NEAR(0x04f1, 5, envx[1]);
169 ASSERT_ENVX_NEAR(0x09f1, 5, envx[2]);
170 ASSERT_ENVX_NEAR(0x0ef1, 5, envx[3]);
171
172 spu_adsr_capture(ATTACK(3, 12, 0) | base, envx, 4);
173 cester_assert_uint_eq(0x0004, envx[0]);
174 ASSERT_ENVX_NEAR(0x03f4, 4, envx[1]);
175 ASSERT_ENVX_NEAR(0x07f4, 4, envx[2]);
176 ASSERT_ENVX_NEAR(0x0bf4, 4, envx[3]);
177
178 spu_adsr_capture(ATTACK(2, 24, 0) | base, envx, 48);
179 for (i = 0; i < 17; i++)
180 cester_assert_uint_eq(0x0005, envx[i]);
181 for (i = 17; i < 33; i++)
182 cester_assert_uint_eq(0x000a, envx[i]);
183 for (i = 33; i < 48; i++)
184 cester_assert_uint_eq(0x000f, envx[i]);
185
186 spu_adsr_capture(ATTACK(3, 24, 0) | base, envx, 48);
187 for (i = 0; i < 17; i++)
188 cester_assert_uint_eq(0x0004, envx[i]);
189 for (i = 17; i < 33; i++)
190 cester_assert_uint_eq(0x0008, envx[i]);
191 for (i = 33; i < 48; i++)
192 cester_assert_uint_eq(0x000c, envx[i]);
193)
194
195CESTER_TEST(adsr_attack_linear_shift, spu_tests,
196 int i;
197 uint16_t envx[0x40];
198
199 const uint32_t base = DECAY(0) | SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(0, 0);
200
201 spu_adsr_capture(ATTACK(0, 0, 0) | base, envx, 1);
202 cester_assert_uint_eq(0x3800, envx[0]);
203
204 spu_adsr_capture(ATTACK(1, 0, 0) | base, envx, 1);
205 cester_assert_uint_eq(0x3000, envx[0]);
206
207 spu_adsr_capture(ATTACK(0, 11, 0) | base, envx, 4);
208 cester_assert_uint_eq(0x0007, envx[0]);
209 ASSERT_ENVX_NEAR(0x0dcf, 7, envx[1]);
210 ASSERT_ENVX_NEAR(0x1bcf, 7, envx[2]);
211 ASSERT_ENVX_NEAR(0x29cf, 7, envx[3]);
212
213 spu_adsr_capture(ATTACK(1, 11, 0) | base, envx, 4);
214 cester_assert_uint_eq(0x0006, envx[0]);
215 ASSERT_ENVX_NEAR(0x0bdc, 7, envx[1]);
216 ASSERT_ENVX_NEAR(0x17d6, 7, envx[2]);
217 ASSERT_ENVX_NEAR(0x23d6, 7, envx[3]);
218
219 spu_adsr_capture(ATTACK(0, 12, 0) | base, envx, 32);
220 cester_assert_uint_eq(0x0007, envx[0]);
221 ASSERT_ENVX_NEAR(0x06e4, 7, envx[1]);
222 ASSERT_ENVX_NEAR(0x0de4, 7, envx[2]);
223 ASSERT_ENVX_NEAR(0x14e4, 7, envx[3]);
224 ASSERT_ENVX_NEAR(0x1be4, 7, envx[4]);
225 ASSERT_ENVX_NEAR(0x22e4, 7, envx[5]);
226 ASSERT_ENVX_NEAR(0x29e4, 7, envx[6]);
227 ASSERT_ENVX_NEAR(0x30e4, 7, envx[7]);
228 ASSERT_ENVX_NEAR(0x37e4, 7, envx[8]);
229 ASSERT_ENVX_NEAR(0x3ee4, 7, envx[9]);
230 ASSERT_ENVX_NEAR(0x45e4, 7, envx[10]);
231 ASSERT_ENVX_NEAR(0x4ce4, 7, envx[11]);
232 ASSERT_ENVX_NEAR(0x53e4, 7, envx[12]);
233 ASSERT_ENVX_NEAR(0x5ae4, 7, envx[13]);
234 ASSERT_ENVX_NEAR(0x61e4, 7, envx[14]);
235 ASSERT_ENVX_NEAR(0x68e4, 7, envx[15]);
236 ASSERT_ENVX_NEAR(0x6fe4, 7, envx[16]);
237 ASSERT_ENVX_NEAR(0x76e4, 7, envx[17]);
238 ASSERT_ENVX_NEAR(0x7de4, 7, envx[18]);
239
240 spu_adsr_capture(ATTACK(1, 12, 0) | base, envx, 4);
241 cester_assert_uint_eq(0x0006, envx[0]);
242 ASSERT_ENVX_NEAR(0x05ee, 6, envx[1]);
243 ASSERT_ENVX_NEAR(0x0bee, 6, envx[2]);
244 ASSERT_ENVX_NEAR(0x11ee, 6, envx[3]);
245
246 spu_adsr_capture(ATTACK(0, 23, 0) | base, envx, 48);
247 for (i = 0; i < 9; i++)
248 cester_assert_uint_eq(0x0007, envx[i]);
249 for (i = 9; i < 17; i++)
250 cester_assert_uint_eq(0x000e, envx[i]);
251 for (i = 17; i < 25; i++)
252 cester_assert_uint_eq(0x0015, envx[i]);
253 for (i = 25; i < 33; i++)
254 cester_assert_uint_eq(0x001c, envx[i]);
255 for (i = 33; i < 41; i++)
256 cester_assert_uint_eq(0x0023, envx[i]);
257 for (i = 41; i < 48; i++)
258 cester_assert_uint_eq(0x002a, envx[i]);
259
260 spu_adsr_capture(ATTACK(1, 23, 0) | base, envx, 48);
261 for (i = 0; i < 9; i++)
262 cester_assert_uint_eq(0x0006, envx[i]);
263 for (i = 9; i < 17; i++)
264 cester_assert_uint_eq(0x000c, envx[i]);
265 for (i = 17; i < 25; i++)
266 cester_assert_uint_eq(0x0012, envx[i]);
267 for (i = 25; i < 33; i++)
268 cester_assert_uint_eq(0x0018, envx[i]);
269 for (i = 33; i < 41; i++)
270 cester_assert_uint_eq(0x001e, envx[i]);
271 for (i = 41; i < 48; i++)
272 cester_assert_uint_eq(0x0024, envx[i]);
273
274 spu_adsr_capture(ATTACK(0, 24, 0) | base, envx, 48);
275 for (i = 0; i < 17; i++)
276 cester_assert_uint_eq(0x0007, envx[i]);
277 for (i = 17; i < 33; i++)
278 cester_assert_uint_eq(0x000e, envx[i]);
279 for (i = 33; i < 48; i++)
280 cester_assert_uint_eq(0x0015, envx[i]);
281
282 spu_adsr_capture(ATTACK(1, 24, 0) | base, envx, 48);
283 for (i = 0; i < 17; i++)
284 cester_assert_uint_eq(0x0006, envx[i]);
285 for (i = 17; i < 33; i++)
286 cester_assert_uint_eq(0x000c, envx[i]);
287 for (i = 33; i < 48; i++)
288 cester_assert_uint_eq(0x0012, envx[i]);
289)
290
291// Above ENVX 0x6000, exponential attack right-shifts AddStep by 2 (delta /= 4),
292// stretching the tail. Below 0x6000 it is bit-identical to linear.
293CESTER_TEST(adsr_attack_exponential, spu_tests,
294 uint16_t envx[0x40];
295
296 const uint32_t base = DECAY(0) | SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(0, 0);
297
298 spu_adsr_capture(ATTACK(0, 12, 1) | base, envx, 32);
299 cester_assert_uint_eq(0x0007, envx[0]);
300 ASSERT_ENVX_NEAR(0x06e4, 7, envx[1]);
301 ASSERT_ENVX_NEAR(0x0de4, 7, envx[2]);
302 ASSERT_ENVX_NEAR(0x14e4, 7, envx[3]);
303 ASSERT_ENVX_NEAR(0x1be4, 7, envx[4]);
304 ASSERT_ENVX_NEAR(0x22e4, 7, envx[5]);
305 ASSERT_ENVX_NEAR(0x29e4, 7, envx[6]);
306 ASSERT_ENVX_NEAR(0x30e4, 7, envx[7]);
307 ASSERT_ENVX_NEAR(0x37e4, 7, envx[8]);
308 ASSERT_ENVX_NEAR(0x3ee4, 7, envx[9]);
309 ASSERT_ENVX_NEAR(0x45e4, 7, envx[10]);
310 ASSERT_ENVX_NEAR(0x4ce4, 7, envx[11]);
311 ASSERT_ENVX_NEAR(0x53e4, 7, envx[12]);
312 ASSERT_ENVX_NEAR(0x5ae4, 7, envx[13]);
313 ASSERT_ENVX_NEAR(0x607f, 7, envx[14]);
314 ASSERT_ENVX_NEAR(0x623f, 7, envx[15]);
315 ASSERT_ENVX_NEAR(0x63ff, 7, envx[16]);
316 ASSERT_ENVX_NEAR(0x65bf, 7, envx[17]);
317 ASSERT_ENVX_NEAR(0x677f, 7, envx[18]);
318 ASSERT_ENVX_NEAR(0x693f, 7, envx[19]);
319 ASSERT_ENVX_NEAR(0x6aff, 7, envx[20]);
320 ASSERT_ENVX_NEAR(0x6cbf, 7, envx[21]);
321 ASSERT_ENVX_NEAR(0x6e7f, 7, envx[22]);
322 ASSERT_ENVX_NEAR(0x703f, 7, envx[23]);
323 ASSERT_ENVX_NEAR(0x71ff, 7, envx[24]);
324 ASSERT_ENVX_NEAR(0x73bf, 7, envx[25]);
325 ASSERT_ENVX_NEAR(0x757f, 7, envx[26]);
326 ASSERT_ENVX_NEAR(0x773f, 7, envx[27]);
327 ASSERT_ENVX_NEAR(0x78ff, 7, envx[28]);
328 ASSERT_ENVX_NEAR(0x7abf, 7, envx[29]);
329 ASSERT_ENVX_NEAR(0x7c7f, 7, envx[30]);
330 ASSERT_ENVX_NEAR(0x7e3f, 7, envx[31]);
331)
332
333// test decay rate after attack peaks; higher value means slower decay
334CESTER_MAYBE_TEST(adsr_decay_shift, spu_tests,
335 uint16_t envx[0x40];
336
337 spu_adsr_capture(
338 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(0, 0, 0, 1, 0) | RELEASE(0, 1),
339 envx, 16);
340 cester_assert_uint_eq(0x1c00, envx[0]);
341 ASSERT_ENVX_NEAR(0x6370, 0x07, envx[1]);
342 ASSERT_ENVX_NEAR(0x4c95, 0x05, envx[2]);
343 ASSERT_ENVX_NEAR(0x3ac6, 0x04, envx[3]);
344 ASSERT_ENVX_NEAR(0x2cef, 0x03, envx[4]);
345 ASSERT_ENVX_NEAR(0x221c, 0x03, envx[5]);
346 ASSERT_ENVX_NEAR(0x19b0, 0x02, envx[6]);
347 ASSERT_ENVX_NEAR(0x1343, 0x02, envx[7]);
348 ASSERT_ENVX_NEAR(0x0e2d, 0x01, envx[8]);
349 ASSERT_ENVX_NEAR(0x0a2d, 0x01, envx[9]);
350 for (unsigned i = 10; i < 16; i++)
351 cester_assert_uint_eq(0x0000, envx[i]);
352
353 spu_adsr_capture(
354 ATTACK(0, 1, 0) | DECAY(12) | SUSTAIN(0, 0, 0, 1, 0) | RELEASE(0, 1),
355 envx, 32);
356 cester_assert_uint_eq(0x1c00, envx[0]);
357 ASSERT_ENVX_NEAR(0x782b, 0x04, envx[1]);
358 ASSERT_ENVX_NEAR(0x702b, 0x04, envx[2]);
359 ASSERT_ENVX_NEAR(0x6925, 0x04, envx[3]);
360 ASSERT_ENVX_NEAR(0x6225, 0x04, envx[4]);
361 ASSERT_ENVX_NEAR(0x5bd7, 0x03, envx[5]);
362 ASSERT_ENVX_NEAR(0x55d7, 0x03, envx[6]);
363 ASSERT_ENVX_NEAR(0x4fdd, 0x03, envx[7]);
364 ASSERT_ENVX_NEAR(0x4add, 0x03, envx[8]);
365 ASSERT_ENVX_NEAR(0x45dd, 0x03, envx[9]);
366 ASSERT_ENVX_NEAR(0x40dd, 0x03, envx[10]);
367 ASSERT_ENVX_NEAR(0x3cb1, 0x02, envx[11]);
368 ASSERT_ENVX_NEAR(0x38b1, 0x02, envx[12]);
369 ASSERT_ENVX_NEAR(0x34b1, 0x02, envx[13]);
370 ASSERT_ENVX_NEAR(0x30b1, 0x02, envx[14]);
371 ASSERT_ENVX_NEAR(0x2d84, 0x02, envx[15]);
372 ASSERT_ENVX_NEAR(0x2a84, 0x02, envx[16]);
373 ASSERT_ENVX_NEAR(0x2784, 0x02, envx[17]);
374 ASSERT_ENVX_NEAR(0x2484, 0x02, envx[18]);
375 ASSERT_ENVX_NEAR(0x2184, 0x02, envx[19]);
376 ASSERT_ENVX_NEAR(0x1f03, 0x01, envx[20]);
377 ASSERT_ENVX_NEAR(0x1d03, 0x01, envx[21]);
378 ASSERT_ENVX_NEAR(0x1b03, 0x01, envx[22]);
379 ASSERT_ENVX_NEAR(0x1903, 0x02, envx[23]);
380 ASSERT_ENVX_NEAR(0x1703, 0x01, envx[24]);
381 ASSERT_ENVX_NEAR(0x1503, 0x01, envx[25]);
382 ASSERT_ENVX_NEAR(0x1303, 0x01, envx[26]);
383 ASSERT_ENVX_NEAR(0x1103, 0x01, envx[27]);
384 ASSERT_ENVX_NEAR(0x0f81, 0x01, envx[28]);
385 ASSERT_ENVX_NEAR(0x0e81, 0x01, envx[29]);
386 ASSERT_ENVX_NEAR(0x0d81, 0x01, envx[30]);
387 ASSERT_ENVX_NEAR(0x0c81, 0x01, envx[31]);
388
389 spu_adsr_capture(
390 ATTACK(0, 1, 0) | DECAY(14) | SUSTAIN(0, 0, 0, 1, 0) | RELEASE(0, 1),
391 envx, 32);
392 cester_assert_uint_eq(0x1c00, envx[0]);
393 ASSERT_ENVX_NEAR(0x7e05, 0x02, envx[1]);
394 ASSERT_ENVX_NEAR(0x7c05, 0x02, envx[2]);
395 ASSERT_ENVX_NEAR(0x7805, 0x02, envx[4]);
396 ASSERT_ENVX_NEAR(0x7405, 0x02, envx[6]);
397 ASSERT_ENVX_NEAR(0x7005, 0x02, envx[8]);
398 ASSERT_ENVX_NEAR(0x6906, 0x02, envx[12]);
399 ASSERT_ENVX_NEAR(0x6206, 0x02, envx[16]);
400 ASSERT_ENVX_NEAR(0x5bba, 0x02, envx[20]);
401 ASSERT_ENVX_NEAR(0x55ba, 0x02, envx[24]);
402 ASSERT_ENVX_NEAR(0x4fc7, 0x02, envx[28]);
403 ASSERT_ENVX_NEAR(0x4c05, 0x02, envx[31]);
404)
405
406// test to which volume level the voice sits on key on sustain
407CESTER_TEST(adsr_sustain_level, spu_tests,
408 uint16_t envx[16];
409
410 spu_adsr_capture(
411 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(3, 0x1f, 0, 1, 0) | RELEASE(0, 1),
412 envx, 16);
413 for (unsigned i = 10; i < 16; i++)
414 cester_assert_uint_eq(0x07ff, envx[i]);
415
416 spu_adsr_capture(
417 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(3, 0x1f, 7, 1, 0) | RELEASE(0, 1),
418 envx, 16);
419 for (unsigned i = 3; i < 16; i++)
420 cester_assert_uint_eq(0x3ffa, envx[i]);
421
422 spu_adsr_capture(
423 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(3, 0x1f, 11, 1, 0) | RELEASE(0, 1),
424 envx, 16);
425 for (unsigned i = 2; i < 16; i++)
426 cester_assert_uint_eq(0x5ff6, envx[i]);
427
428 spu_adsr_capture(
429 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(3, 0x1f, 14, 1, 0) | RELEASE(0, 1),
430 envx, 16);
431 for (unsigned i = 1; i < 16; i++)
432 cester_assert_uint_eq(0x77ff, envx[i]);
433
434 spu_adsr_capture(
435 ATTACK(0, 1, 0) | DECAY(10) | SUSTAIN(3, 0x1f, 15, 1, 0) | RELEASE(0, 1),
436 envx, 16);
437 for (unsigned i = 1; i < 16; i++)
438 cester_assert_uint_eq(0x7fef, envx[i]);
439)
440
441// sustain at various levels while direction scale positive linearly
442CESTER_TEST(adsr_sustain_up_linear, spu_tests,
443 uint16_t envx[0x20];
444
445 spu_adsr_capture(
446 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 10, 15, 0, 0) | RELEASE(0, 1),
447 envx, 8);
448 cester_assert_uint_eq(0x1c00, envx[0]);
449 ASSERT_ENVX_NEAR(0x5b50, 0x07, envx[1]);
450 ASSERT_ENVX_NEAR(0x7750, 0x07, envx[2]);
451 for (unsigned i = 3; i < 8; i++)
452 cester_assert_uint_eq(0x7fff, envx[i]);
453
454 spu_adsr_capture(
455 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(3, 10, 15, 0, 0) | RELEASE(0, 1),
456 envx, 8);
457 cester_assert_uint_eq(0x1c00, envx[0]);
458 ASSERT_ENVX_NEAR(0x4f9b, 0x04, envx[1]);
459 ASSERT_ENVX_NEAR(0x5f9b, 0x04, envx[2]);
460 ASSERT_ENVX_NEAR(0x6f9b, 0x04, envx[3]);
461 ASSERT_ENVX_NEAR(0x7f9b, 0x04, envx[4]);
462 for (unsigned i = 5; i < 8; i++)
463 cester_assert_uint_eq(0x7fff, envx[i]);
464
465 spu_adsr_capture(
466 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 12, 15, 0, 0) | RELEASE(0, 1),
467 envx, 16);
468 cester_assert_uint_eq(0x1c00, envx[0]);
469 ASSERT_ENVX_NEAR(0x46d1, 0x04, envx[1]);
470 ASSERT_ENVX_NEAR(0x4dd1, 0x04, envx[2]);
471 ASSERT_ENVX_NEAR(0x54d1, 0x04, envx[3]);
472 ASSERT_ENVX_NEAR(0x5bd1, 0x04, envx[4]);
473 ASSERT_ENVX_NEAR(0x62d1, 0x04, envx[5]);
474 ASSERT_ENVX_NEAR(0x69d1, 0x04, envx[6]);
475 ASSERT_ENVX_NEAR(0x70d1, 0x04, envx[7]);
476 ASSERT_ENVX_NEAR(0x77d1, 0x04, envx[8]);
477 ASSERT_ENVX_NEAR(0x7ed1, 0x04, envx[9]);
478 for (unsigned i = 10; i < 16; i++)
479 cester_assert_uint_eq(0x7fff, envx[i]);
480
481 spu_adsr_capture(
482 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 14, 15, 0, 0) | RELEASE(0, 1),
483 envx, 32);
484 cester_assert_uint_eq(0x1c00, envx[0]);
485 ASSERT_ENVX_NEAR(0x41b8, 0x02, envx[1]);
486 ASSERT_ENVX_NEAR(0x4378, 0x02, envx[2]);
487 ASSERT_ENVX_NEAR(0x46f8, 0x02, envx[4]);
488 ASSERT_ENVX_NEAR(0x4df8, 0x02, envx[8]);
489 ASSERT_ENVX_NEAR(0x54f8, 0x02, envx[12]);
490 ASSERT_ENVX_NEAR(0x5bf8, 0x02, envx[16]);
491 ASSERT_ENVX_NEAR(0x62f8, 0x02, envx[20]);
492 ASSERT_ENVX_NEAR(0x69f8, 0x02, envx[24]);
493 ASSERT_ENVX_NEAR(0x70f8, 0x02, envx[28]);
494 ASSERT_ENVX_NEAR(0x7638, 0x02, envx[31]);
495
496 spu_adsr_capture(
497 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 16, 15, 0, 0) | RELEASE(0, 1),
498 envx, 32);
499 cester_assert_uint_eq(0x1c00, envx[0]);
500 ASSERT_ENVX_NEAR(0x4068, 0x02, envx[1]);
501 ASSERT_ENVX_NEAR(0x4228, 0x02, envx[5]);
502 ASSERT_ENVX_NEAR(0x4458, 0x02, envx[10]);
503 ASSERT_ENVX_NEAR(0x4688, 0x02, envx[15]);
504 ASSERT_ENVX_NEAR(0x48b8, 0x02, envx[20]);
505 ASSERT_ENVX_NEAR(0x4ae8, 0x02, envx[25]);
506 ASSERT_ENVX_NEAR(0x4d88, 0x02, envx[31]);
507)
508
509// sustain at various levels while direction scale negative linearly
510CESTER_MAYBE_TEST(adsr_sustain_down_linear, spu_tests,
511 uint16_t envx[0x20];
512
513 spu_adsr_capture(
514 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(3, 10, 15, 1, 0) | RELEASE(0, 1),
515 envx, 8);
516 cester_assert_uint_eq(0x1c00, envx[0]);
517 ASSERT_ENVX_NEAR(0x2c7c, 0x05, envx[1]);
518 ASSERT_ENVX_NEAR(0x187c, 0x05, envx[2]);
519 ASSERT_ENVX_NEAR(0x047c, 0x05, envx[3]);
520 for (unsigned i = 4; i < 8; i++)
521 cester_assert_uint_eq(0x0000, envx[i]);
522
523 spu_adsr_capture(
524 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 12, 15, 1, 0) | RELEASE(0, 1),
525 envx, 16);
526 cester_assert_uint_eq(0x1c00, envx[0]);
527 ASSERT_ENVX_NEAR(0x3833, 0x04, envx[1]);
528 ASSERT_ENVX_NEAR(0x3033, 0x04, envx[2]);
529 ASSERT_ENVX_NEAR(0x2833, 0x04, envx[3]);
530 ASSERT_ENVX_NEAR(0x2033, 0x04, envx[4]);
531 ASSERT_ENVX_NEAR(0x1833, 0x04, envx[5]);
532 ASSERT_ENVX_NEAR(0x1033, 0x04, envx[6]);
533 ASSERT_ENVX_NEAR(0x0833, 0x04, envx[7]);
534 ASSERT_ENVX_NEAR(0x0033, 0x04, envx[8]);
535 for (unsigned i = 9; i < 16; i++)
536 cester_assert_uint_eq(0x0000, envx[i]);
537
538 spu_adsr_capture(
539 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 14, 15, 1, 0) | RELEASE(0, 1),
540 envx, 32);
541 cester_assert_uint_eq(0x1c00, envx[0]);
542 ASSERT_ENVX_NEAR(0x3e05, 0x02, envx[1]);
543 ASSERT_ENVX_NEAR(0x3c05, 0x02, envx[2]);
544 ASSERT_ENVX_NEAR(0x3805, 0x02, envx[4]);
545 ASSERT_ENVX_NEAR(0x3005, 0x02, envx[8]);
546 ASSERT_ENVX_NEAR(0x2805, 0x02, envx[12]);
547 ASSERT_ENVX_NEAR(0x2005, 0x02, envx[16]);
548 ASSERT_ENVX_NEAR(0x1805, 0x02, envx[20]);
549 ASSERT_ENVX_NEAR(0x1005, 0x02, envx[24]);
550 ASSERT_ENVX_NEAR(0x0805, 0x02, envx[28]);
551 ASSERT_ENVX_NEAR(0x0205, 0x02, envx[31]);
552
553 spu_adsr_capture(
554 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 16, 15, 1, 0) | RELEASE(0, 1),
555 envx, 32);
556 cester_assert_uint_eq(0x1c00, envx[0]);
557 ASSERT_ENVX_NEAR(0x3f85, 0x02, envx[1]);
558 ASSERT_ENVX_NEAR(0x3e85, 0x02, envx[3]);
559 ASSERT_ENVX_NEAR(0x3d05, 0x02, envx[6]);
560 ASSERT_ENVX_NEAR(0x3b85, 0x02, envx[9]);
561 ASSERT_ENVX_NEAR(0x3a05, 0x02, envx[12]);
562 ASSERT_ENVX_NEAR(0x3885, 0x02, envx[15]);
563 ASSERT_ENVX_NEAR(0x3705, 0x02, envx[18]);
564 ASSERT_ENVX_NEAR(0x3585, 0x02, envx[21]);
565 ASSERT_ENVX_NEAR(0x3405, 0x02, envx[24]);
566 ASSERT_ENVX_NEAR(0x3285, 0x02, envx[27]);
567 ASSERT_ENVX_NEAR(0x3105, 0x02, envx[30]);
568)
569
570// sustain at various levels while direction scale positive exponentially
571CESTER_TEST(adsr_sustain_up_exponential, spu_tests,
572 uint16_t envx[0x20];
573
574 spu_adsr_capture(
575 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 12, 15, 0, 1) | RELEASE(0, 1),
576 envx, 24);
577 cester_assert_uint_eq(0x1c00, envx[0]);
578 ASSERT_ENVX_NEAR(0x46d1, 0x04, envx[1]);
579 ASSERT_ENVX_NEAR(0x4dd1, 0x04, envx[2]);
580 ASSERT_ENVX_NEAR(0x54d1, 0x04, envx[3]);
581 ASSERT_ENVX_NEAR(0x5bd1, 0x04, envx[4]);
582 ASSERT_ENVX_NEAR(0x60ba, 0x02, envx[5]);
583 ASSERT_ENVX_NEAR(0x627a, 0x02, envx[6]);
584 ASSERT_ENVX_NEAR(0x643a, 0x02, envx[7]);
585 ASSERT_ENVX_NEAR(0x65fa, 0x02, envx[8]);
586 ASSERT_ENVX_NEAR(0x67ba, 0x02, envx[9]);
587 ASSERT_ENVX_NEAR(0x6cfa, 0x02, envx[12]);
588 ASSERT_ENVX_NEAR(0x73fa, 0x02, envx[16]);
589 ASSERT_ENVX_NEAR(0x7afa, 0x02, envx[20]);
590 cester_assert_uint_eq(0x7fff, envx[23]);
591
592 spu_adsr_capture(
593 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 14, 15, 0, 1) | RELEASE(0, 1),
594 envx, 32);
595 cester_assert_uint_eq(0x1c00, envx[0]);
596 ASSERT_ENVX_NEAR(0x41b8, 0x02, envx[1]);
597 ASSERT_ENVX_NEAR(0x4df8, 0x02, envx[8]);
598 ASSERT_ENVX_NEAR(0x5bf8, 0x02, envx[16]);
599 ASSERT_ENVX_NEAR(0x6051, 0x02, envx[19]);
600 ASSERT_ENVX_NEAR(0x60c1, 0x02, envx[20]);
601 ASSERT_ENVX_NEAR(0x6211, 0x02, envx[23]);
602 ASSERT_ENVX_NEAR(0x6361, 0x02, envx[26]);
603 ASSERT_ENVX_NEAR(0x6591, 0x02, envx[31]);
604)
605
606// sustain at various levels while direction scale negative exponentially
607CESTER_TEST(adsr_sustain_down_exponential, spu_tests,
608 uint16_t envx[0x20];
609
610 spu_adsr_capture(
611 ATTACK(0, 1, 0) | DECAY(0) | SUSTAIN(0, 12, 15, 1, 1) | RELEASE(0, 1),
612 envx, 32);
613 cester_assert_uint_eq(0x1c00, envx[0]);
614 // Multiplicative decrease — deltas shrink as EnvVol drops.
615 ASSERT_ENVX_NEAR(0x3c19, 0x02, envx[1]);
616 ASSERT_ENVX_NEAR(0x3819, 0x02, envx[2]);
617 ASSERT_ENVX_NEAR(0x3419, 0x02, envx[3]);
618 ASSERT_ENVX_NEAR(0x3019, 0x02, envx[4]);
619 ASSERT_ENVX_NEAR(0x2d12, 0x02, envx[5]);
620 ASSERT_ENVX_NEAR(0x2a12, 0x02, envx[6]);
621 ASSERT_ENVX_NEAR(0x2712, 0x02, envx[7]);
622 ASSERT_ENVX_NEAR(0x2412, 0x02, envx[8]);
623 ASSERT_ENVX_NEAR(0x2112, 0x02, envx[9]);
624 ASSERT_ENVX_NEAR(0x1eb7, 0x01, envx[10]);
625 ASSERT_ENVX_NEAR(0x1ab7, 0x01, envx[12]);
626 ASSERT_ENVX_NEAR(0x16b7, 0x01, envx[14]);
627 ASSERT_ENVX_NEAR(0x12b7, 0x01, envx[16]);
628 ASSERT_ENVX_NEAR(0x0f5b, 0x01, envx[18]);
629 ASSERT_ENVX_NEAR(0x0c5b, 0x01, envx[21]);
630 ASSERT_ENVX_NEAR(0x095b, 0x01, envx[24]);
631 ASSERT_ENVX_NEAR(0x065b, 0x01, envx[27]);
632 ASSERT_ENVX_NEAR(0x035b, 0x01, envx[30]);
633)
634
635// release linear, capture samples as soon as key goes off
636CESTER_MAYBE_TEST(adsr_release_linear, spu_tests,
637 uint16_t envx[0x20];
638
639 spu_adsr_capture_with_keyoff(
640 ATTACK(0, 1, 0) | DECAY(15) |
641 SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(12, 0),
642 envx, 24, 3);
643 cester_assert_uint_eq(0x1c00, envx[0]);
644 cester_assert_uint_eq(0x7ff7, envx[1]);
645 cester_assert_uint_eq(0x7ff7, envx[2]);
646 cester_assert_uint_eq(0x7ff7, envx[3]);
647 ASSERT_ENVX_NEAR(0x77fb, 0x04, envx[4]);
648 ASSERT_ENVX_NEAR(0x6ffb, 0x04, envx[5]);
649 ASSERT_ENVX_NEAR(0x67fb, 0x04, envx[6]);
650 ASSERT_ENVX_NEAR(0x5ffb, 0x04, envx[7]);
651 ASSERT_ENVX_NEAR(0x57fb, 0x04, envx[8]);
652 ASSERT_ENVX_NEAR(0x4ffb, 0x04, envx[9]);
653 ASSERT_ENVX_NEAR(0x47fb, 0x04, envx[10]);
654 ASSERT_ENVX_NEAR(0x3ffb, 0x04, envx[11]);
655 ASSERT_ENVX_NEAR(0x37fb, 0x04, envx[12]);
656 ASSERT_ENVX_NEAR(0x2ffb, 0x04, envx[13]);
657 ASSERT_ENVX_NEAR(0x27fb, 0x04, envx[14]);
658 ASSERT_ENVX_NEAR(0x1ffb, 0x04, envx[15]);
659 ASSERT_ENVX_NEAR(0x17fb, 0x04, envx[16]);
660 ASSERT_ENVX_NEAR(0x0ffb, 0x04, envx[17]);
661 ASSERT_ENVX_NEAR(0x07fb, 0x04, envx[18]);
662 for (unsigned i = 19; i < 24; i++)
663 cester_assert_uint_eq(0x0000, envx[i]);
664
665 spu_adsr_capture_with_keyoff(
666 ATTACK(0, 1, 0) | DECAY(15) |
667 SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(14, 0),
668 envx, 32, 3);
669 cester_assert_uint_eq(0x1c00, envx[0]);
670 ASSERT_ENVX_NEAR(0x7ffb, 0x04, envx[3]);
671 ASSERT_ENVX_NEAR(0x7dfb, 0x04, envx[4]);
672 ASSERT_ENVX_NEAR(0x7bfb, 0x04, envx[5]);
673 ASSERT_ENVX_NEAR(0x77fb, 0x04, envx[7]);
674 ASSERT_ENVX_NEAR(0x6ffb, 0x04, envx[11]);
675 ASSERT_ENVX_NEAR(0x67fb, 0x04, envx[15]);
676 ASSERT_ENVX_NEAR(0x5ffb, 0x04, envx[19]);
677 ASSERT_ENVX_NEAR(0x57fb, 0x04, envx[23]);
678 ASSERT_ENVX_NEAR(0x4ffb, 0x04, envx[27]);
679 ASSERT_ENVX_NEAR(0x47fb, 0x04, envx[31]);
680
681 spu_adsr_capture_with_keyoff(
682 ATTACK(0, 1, 0) | DECAY(15) |
683 SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(16, 0),
684 envx, 16, 3);
685 cester_assert_uint_eq(0x1c00, envx[0]);
686 ASSERT_ENVX_NEAR(0x7ffb, 0x04, envx[3]);
687 ASSERT_ENVX_NEAR(0x7f7b, 0x04, envx[4]);
688 ASSERT_ENVX_NEAR(0x7efb, 0x04, envx[5]);
689 ASSERT_ENVX_NEAR(0x7dfb, 0x04, envx[7]);
690 ASSERT_ENVX_NEAR(0x7bfb, 0x04, envx[11]);
691 ASSERT_ENVX_NEAR(0x79fb, 0x04, envx[15]);
692)
693
694// release exponential, capture samples as soon as key goes off
695CESTER_MAYBE_TEST(adsr_release_exponential, spu_tests,
696 uint16_t envx[0x20];
697
698 spu_adsr_capture_with_keyoff(
699 ATTACK(0, 1, 0) | DECAY(15) |
700 SUSTAIN(3, 0x1f, 15, 0, 0) | RELEASE(12, 1),
701 envx, 24, 2);
702 cester_assert_uint_eq(0x1c00, envx[0]);
703 cester_assert_uint_eq(0x7ff7, envx[1]);
704 cester_assert_uint_eq(0x7ff7, envx[2]);
705 ASSERT_ENVX_NEAR(0x77fb, 0x04, envx[3]);
706 ASSERT_ENVX_NEAR(0x6ffb, 0x04, envx[4]);
707 ASSERT_ENVX_NEAR(0x68fb, 0x04, envx[5]);
708 ASSERT_ENVX_NEAR(0x61fb, 0x04, envx[6]);
709 ASSERT_ENVX_NEAR(0x5bb3, 0x03, envx[7]);
710 ASSERT_ENVX_NEAR(0x55b3, 0x03, envx[8]);
711 ASSERT_ENVX_NEAR(0x4fbf, 0x03, envx[9]);
712 ASSERT_ENVX_NEAR(0x4abf, 0x03, envx[10]);
713 ASSERT_ENVX_NEAR(0x45bf, 0x03, envx[11]);
714 ASSERT_ENVX_NEAR(0x40bf, 0x03, envx[12]);
715 ASSERT_ENVX_NEAR(0x3c99, 0x02, envx[13]);
716 ASSERT_ENVX_NEAR(0x3899, 0x02, envx[14]);
717 ASSERT_ENVX_NEAR(0x3499, 0x02, envx[15]);
718 ASSERT_ENVX_NEAR(0x3099, 0x02, envx[16]);
719 ASSERT_ENVX_NEAR(0x2d72, 0x02, envx[17]);
720 ASSERT_ENVX_NEAR(0x2a72, 0x02, envx[18]);
721 ASSERT_ENVX_NEAR(0x2772, 0x02, envx[19]);
722 ASSERT_ENVX_NEAR(0x2472, 0x02, envx[20]);
723 ASSERT_ENVX_NEAR(0x2172, 0x02, envx[21]);
724 ASSERT_ENVX_NEAR(0x1ef7, 0x01, envx[22]);
725 ASSERT_ENVX_NEAR(0x1cf7, 0x01, envx[23]);
726)
CESTER_TEST(cdlGetLocL, test_instances, int resetDone=resetCDRom();if(!resetDone) { cester_assert_true(resetDone);return;} initializeTime();CDROM_REG0=0;CDROM_REG1=CDL_GETLOCL;uint32_t ackTime=waitCDRomIRQ();uint8_t cause1=ackCDRomCause();uint8_t ctrl1=CDROM_REG0 &~3;uint8_t response[16];uint8_t responseSize=readResponse(response);uint8_t ctrl2=CDROM_REG0 &~3;CDROM_REG0=1;uint8_t cause1b=CDROM_REG3_UC;cester_assert_uint_eq(3, cause1);cester_assert_uint_eq(0xe0, cause1b);cester_assert_uint_eq(0x38, ctrl1);cester_assert_uint_eq(0x18, ctrl2);cester_assert_uint_eq(8, responseSize);cester_assert_uint_ge(ackTime, 500);cester_assert_uint_lt(ackTime, 7000);ramsyscall_printf("Basic getlocL, ack in %ius\n", ackTime);) CESTER_TEST(cdlGetLocLafterSeekP
cester_assert_uint_eq(5, cause1)
CESTER_BODY(static void hexdump(const void *data_, unsigned size) { const uint8_t *data=(const uint8_t *) data_;char ascii[17];ascii[16]=0;for(unsigned i=0;i< size;i++) { if(i % 16==0) ramsyscall_printf("%08x |", i);ramsyscall_printf("%02X ", data[i]);ascii[i % 16]=data[i] >=' ' &&data[i]<='~' ? data[i] :'.';unsigned j=i+1;if((j % 8==0)||(j==size)) { ramsyscall_printf(" ");if(j % 16==0) { ramsyscall_printf("| %s \n", ascii);} else if(j==size) { ascii[j % 16]=0;if(j % 16<=8) ramsyscall_printf(" ");for(j %=16;j< 16;j++) ramsyscall_printf(" ");ramsyscall_printf("| %s \n", ascii);} } } } static int s_interruptsWereEnabled=0;static uint16_t s_oldMode=0;static uint32_t s_lastHSyncCounter=0;static uint32_t s_currentTime=0;static uint32_t s_oldIMASK=0;static const unsigned US_PER_HBLANK=64;struct LocPResult { uint8_t track, index, m, s, f, am, as, af;uint8_t padding[8];};static uint8_t btoi(uint8_t b) { return(b > > 4) *10+(b &0xf);} static uint8_t itob(uint8_t i) { return(i/10) *16+(i % 10);} static int isValidBCD(uint8_t b) { return(b &0xf)< 10 &&(b > > 4)< 10;} static uint32_t MSF2LBA(uint8_t m, uint8_t s, uint8_t f) { return(m *60+s) *75+f;} static uint8_t readResponse(uint8_t response[16]) { uint8_t responseSize=0;while((CDROM_REG0 &0x20) &&(responseSize< 16)) { response[responseSize++]=CDROM_REG1;} return responseSize;} static uint8_t discardResponse() { uint8_t response[16];return readResponse(response);} static inline void initializeTime() { while(1) { uint32_t init=COUNTERS[1].value;uint32_t counter;while((counter=COUNTERS[1].value)==init);if(counter !=COUNTERS[1].value) continue;s_lastHSyncCounter=counter;break;} s_currentTime=0;} static inline uint32_t updateTime() { uint32_t lastHSyncCounter=s_lastHSyncCounter;uint32_t hsyncCounter;while(1) { hsyncCounter=COUNTERS[1].value;if(hsyncCounter !=COUNTERS[1].value) continue;break;} if(hsyncCounter< lastHSyncCounter) { hsyncCounter+=0x10000;} uint32_t currentTime=s_currentTime=s_currentTime+(hsyncCounter - lastHSyncCounter) *US_PER_HBLANK;s_lastHSyncCounter=hsyncCounter;return currentTime;} static inline uint32_t waitCDRomIRQ() { uint32_t time;do { time=updateTime();} while((IREG &IRQ_CDROM)==0);IREG &=~IRQ_CDROM;return time;} static inline int waitCDRomIRQWithTimeout(uint32_t *timeoutp) { uint32_t time=updateTime();uint32_t timeout= *timeoutp+time;do { time=updateTime();} while(((IREG &IRQ_CDROM)==0) &&(time<=timeout));int ret=(IREG &IRQ_CDROM) !=0; *timeoutp=time;IREG &=~IRQ_CDROM;return ret;} static inline uint8_t ackCDRomCause() { CDROM_REG0=1;uint8_t cause=CDROM_REG3_UC;if(cause &7) { CDROM_REG0=1;CDROM_REG3=7;} if(cause &0x18) { CDROM_REG0=1;CDROM_REG3=cause &0x18;} return cause &7;} int setMode(uint8_t mode) { uint8_t cause;CDROM_REG0=0;CDROM_REG2=mode;CDROM_REG1=CDL_SETMODE;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;return 1;} static inline int resetCDRom() { uint8_t cause;CDROM_REG0=1;CDROM_REG3=0x1f;CDROM_REG0=1;CDROM_REG2=0x1f;CDROM_REG0=0;CDROM_REG1=CDL_INIT;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=2) return 0;initializeTime();while(updateTime()< 10000);return setMode(0);} static int setLoc(uint8_t minute, uint8_t second, uint8_t frame) { uint8_t cause;CDROM_REG0=0;CDROM_REG2=minute;CDROM_REG2=second;CDROM_REG2=frame;CDROM_REG1=CDL_SETLOC;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;return 1;} static int seekPTo(uint8_t minute, uint8_t second, uint8_t frame) { uint8_t cause;CDROM_REG0=0;CDROM_REG2=minute;CDROM_REG2=second;CDROM_REG2=frame;CDROM_REG1=CDL_SETLOC;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;CDROM_REG0=0;CDROM_REG1=CDL_SEEKP;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=2) return 0;return 1;} static int seekLTo(uint8_t minute, uint8_t second, uint8_t frame) { uint8_t cause;CDROM_REG0=0;CDROM_REG2=minute;CDROM_REG2=second;CDROM_REG2=frame;CDROM_REG1=CDL_SETLOC;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;CDROM_REG0=0;CDROM_REG1=CDL_SEEKL;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=3) return 0;waitCDRomIRQ();cause=ackCDRomCause();CDROM_REG1;if(cause !=2) return 0;return 1;} uint8_t getCtrl() { uint8_t cause;CDROM_REG0=0;CDROM_REG1=CDL_NOP;waitCDRomIRQ();ackCDRomCause();uint8_t ctrl=CDROM_REG1;return ctrl;}) CESTER_BEFORE_ALL(cpu_tests
#define SPU_VOICES
Definition spu.h:42
#define SPU_KEY_ON_LOW
Definition spu.h:88
#define SPU_VOL_MAIN_LEFT
Definition spu.h:84
#define SPU_KEY_OFF_LOW
Definition spu.h:90
#define SPU_KEY_OFF_HIGH
Definition spu.h:91
#define SPU_CTRL
Definition spu.h:104
#define SPU_VOL_MAIN_RIGHT
Definition spu.h:85
#define CESTER_MAYBE_TEST
Definition cop0.c:34
ramsyscall_printf("=== e01_kseg1_reads_no_fill ===\n")
int i
Definition gte-regio.c:297
int base
Definition gentable.py:114
cester_assert_true(seekDone)
spu_tests
Definition spu-adpcm-edge.c:189
#define ASSERT_ENVX_NEAR(nominal, step, got)
#define DECAY(shift)
Definition spu-adsr.c:9
#define RELEASE(shift, exp)
Definition spu-adsr.c:17
#define ENVX_MARGIN(step)
#define ADSR_DRAIN_MAX_TICKS
#define SUSTAIN(step, shift, level, direction, exp)
Definition spu-adsr.c:11
#define ATTACK(step, shift, exp)
Definition spu-adsr.c:5
#define ADSR_ONSET_MAX_SPINS
#define ENVX_INCREMENT
#define SPU_UPLOAD_ADDR
Definition spu-capamp.c:31
muteSpu()
spu_reset_quiet()
void int(code1, code2)
void uint32_t(classId, spec)