Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
sid.c
Go to the documentation of this file.
1 /*
2  * This source is a modifed version of sidengine.c from here: https://github.com/wothke/websid
3  * Modification is mainly about killing the not-SID related parts, and making emulation modular,
4  * ie introducing a way to allow to emulate more SIDs through the SidEmulation structure pointer.
5  * Otherwise it should be the same. Sorry, I am just lame with sound things, the modularization
6  * can be done in a better way, ie some things should not be per SID stuff, etc.
7  * Modifications done by: Gabor Lenart (aka LGB) lgblgblgb@gmail.com http://lgb.hu/
8  * Mainly for having *some* sound for my primitive Commodore 65 emulator :)
9  * https://github.com/lgblgblgb/xclcd
10  *
11  * ---- NOW THE ORIGINAL COMMENT HEADER FOLLOWS ----
12  *
13  * This file is largely the original file from the "TinySid for Linux" distribution.
14  *
15  * <p>TinySid (c) 1999-2012 T. Hinrichs, R. Sinsch
16  *
17  * <p>It was updated by merging in the latest "Rockbox" version (This noticably fixed playback problems with
18  * "Yie Ar Kung Fu"..) and by applying fixes contributed by Markus Gritsch. Unfortunately a revision history of the old
19  * TinySid codebase does not seem to exist.. so we'll probably never know what was used for the TinySid Windows executable and
20  * why it is the only version that correctly plays Electric_Girls.sid..)
21  * <p>In this file I deliberately kept the "naming conventions" used in the original TinySID code - to ease future merging
22  * of potential TinySid fixes (consequently there is a mismatch with the conventions that I am using in my own code..)
23  *
24  * <p>My additions here are:
25  * <ol>
26  * <li>fixed PSID digi playback volume (was originally too low)
27  * <li>correct cycle-time calculation for ALL 6510 op codes (also illegal ones)
28  * <li>added impls for illegal 6510 op codes, fixed errors in V-flag calculation, added handling for 6510 addressing "bugs"
29  * <li>poor man's VIC and CIA handling
30  * <li>"cycle limit" feature used to interrupt emulation runs (e.g. main prog can now be suspended/continued)
31  * <li>Poor man's "combined pulse/triangle waveform" impl to allow playback of songs like Kentilla.sid.
32  * <li>added RSID digi playback support (D418 based as well as "pulse width modulation" based): it is a "special feature" of
33  * this implementation that regular SID emulation is performed somewhat independently from the handling of digi samples, i.e. playback
34  * of digi samples is tracked separately (for main, IRQ and NMI) and the respective digi samples are then merged with the regular SID
35  * output as some kind of postprocessing step
36  * <li> replaced original "envelope generator" impl with a more realistic one (incl. "ADSR-bug" handling)
37  * </ol>
38  *
39  * FIXME: refactor CPU and SID emulation into separate files..
40  *
41  * known limitation: basic-ROM specific handling not implemented...
42  *
43  * <p>Notice: if you have questions regarding the details of the below SID emulation, then you should better get in touch with R.Sinsch :-)
44  *
45  * <p>Tiny'R'Sid add-ons (c) 2015 J.Wothke
46  *
47  * Terms of Use: This software is licensed under a CC BY-NC-SA
48  * (http://creativecommons.org/licenses/by-nc-sa/4.0/).
49  */
50 
51 
52  // useful links:
53  // http://www.waitingforfriday.com/index.php/Commodore_SID_6581_Datasheet
54  // http://www.sidmusic.org/sid/sidtech2.html
55  // http://www.oxyron.de/html/opcodes02.html
56 
57 #include <string.h>
58 #include <stdio.h>
59 #include <math.h>
60 #include <stdlib.h>
61 
62 #include "xemu/sid.h"
63 
64 static unsigned char exponential_delays[256];
65 
66 
67 #define getFrameCount() (sidemu->sFrameCount)
68 
69 
70 /*static unsigned long getCyclesPerSec() {
71  return 982800;
72 }*/
73 
74 
75 
76 
77 // hacks
78 //static unsigned char sFake_d012_count=0;
79 //static unsigned char sFake_d012_loop=0;
80 
81 //static unsigned int sCiaNmiVectorHack= 0;
82 
83 //static void setCiaNmiVectorHack(){
84 // sCiaNmiVectorHack= 1;
85 //}
86 
87 /* Routines for quick & dirty float calculation */
88 static inline int pfloat_ConvertFromInt(int i) { return (i<<16); }
89 static inline int pfloat_ConvertFromFloat(float f) { return (int)(f*(1<<16)); }
90 static inline int pfloat_Multiply(int a, int b) { return (a>>8)*(b>>8); }
91 static inline int pfloat_ConvertToInt(int i) { return (i>>16); }
92 
93 
94 // note: decay/release times are 3x longer (implemented via exponential_counter)
95 static const int attackTimes[16] = {
96  2, 8, 16, 24, 38, 56, 68, 80, 100, 240, 500, 800, 1000, 3000, 5000, 8000
97 };
98 
99 
100 //static unsigned long getSampleFrequency() {
101 // return mixing_frequency;
102 //}
103 
104 //static void setMute(unsigned char voice) {
105 // sMuteVoice[voice] = 1;
106 //}
107 
108 /* Get the bit from an unsigned long at a specified position */
109 static inline unsigned char get_bit(unsigned long val, unsigned char b)
110 {
111  return (unsigned char) ((val >> b) & 1);
112 }
113 
114 
115 
116 
117 // poor man's lookup table for combined pulse/triangle waveform (this table does not
118 // lead to correct results but it is better that nothing for songs like Kentilla.sid)
119 // feel free to come up with a better impl!
120 // FIXME: this table was created by sampling kentilla output.. i.e. it already reflects the envelope
121 // used there and may actually be far from the correct waveform
122 static const signed char pulseTriangleWavetable[] =
123 {
124  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00,
125  0x00, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x10,
126  0x10, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x20,
127  0x10, 0x00, 0x06, 0x06, 0x06, 0x06, 0x0b, 0x15, 0x0b, 0x0b, 0x0b, 0x15, 0x25, 0x2f, 0x2f, 0x69,
128  0x20, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0b, 0x15, 0x15,
129  0x1b, 0x06, 0x0b, 0x10, 0x0b, 0x0b, 0x15, 0x25, 0x15, 0x0b, 0x0b, 0x63, 0x49, 0x69, 0x88, 0x3a,
130  0x3a, 0x06, 0x0b, 0x06, 0x10, 0x10, 0x15, 0x3f, 0x10, 0x25, 0x59, 0x59, 0x3f, 0x9d, 0xa7, 0x59,
131  0x00, 0x00, 0x5e, 0x59, 0x88, 0xb7, 0xb7, 0xac, 0x83, 0xac, 0xd1, 0xc6, 0xc1, 0xdb, 0xdb, 0xeb,
132  /* rather symetrical: let's just mirror the above part */
133 };
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 // util related to envelope generator LFSR counter
146 static int clocksToSamples(int clocks) {
147 #ifdef SID_USES_SAMPLE_ENV_COUNTER
148  return round(((float)clocks)/cyclesPerSample)+1;
149 #else
150  return clocks;
151 #endif
152 }
153 
154 
155 
156 
157 /*
158 * check if LFSR threshold was reached
159 */
160 static unsigned char triggerLFSR_Threshold(unsigned int threshold, signed int *end) {
161  if (threshold == (*end)) {
162  (*end)= 0; // reset counter
163  return 1;
164  }
165  return 0;
166 }
167 
168 
169 
170 
171 static unsigned char handleExponentialDelay ( struct SidEmulation *sidemu, unsigned char voice ) {
172  sidemu->osc[voice].exponential_counter+= 1;
173  unsigned char result= (sidemu->osc[voice].exponential_counter >= exponential_delays[sidemu->osc[voice].envelopeOutput]);
174  if (result) {
175  sidemu->osc[voice].exponential_counter= 0; // reset to start next round
176  }
177  return result;
178 }
179 
180 
181 
182 
183 static void simOneEnvelopeCycle( struct SidEmulation *sidemu, unsigned char v ) {
184  // now process the volume according to the phase and adsr values
185  // (explicit switching of ADSR phase is handled in sidPoke() so there is no need to handle that here)
186 
187  // advance envelope LFSR counter (originally this would be a 15-bit cycle counter.. but we may be counting samples here)
188 
189  // ADSR bug scenario: normally the maximum thresholds used for the original 15-bit counter would have been around
190  // 0x7a13 (i.e. somewhat below the 7fff range that can be handled by the counter). For certain bug scenarios
191  // it is possible that the threshold is missed and the counter keeps counting until it again reaches the
192  // threshold after a wrap-around.. (see sidPoke() for specific ADSR-bug handling)
193 
194  if (++sidemu->osc[v].currentLFSR == sidemu->limit_LFSR) {
195  sidemu->osc[v].currentLFSR= 0;
196  }
197 
198  unsigned char previousEnvelopeOutput = sidemu->osc[v].envelopeOutput;
199 
200  switch (sidemu->osc[v].envphase) {
201  case Attack: { // Phase 0 : Attack
202  if (triggerLFSR_Threshold(sidemu->osc[v].attack, &sidemu->osc[v].currentLFSR)) { // inc volume when threshold is reached
203  if (!sidemu->osc[v].zero_lock) {
204  if (sidemu->osc[v].envelopeOutput < 0xff) {
205  // see Alien.sid: "full envelopeOutput level" GATE off/on sequences within same
206  // IRQ will cause undesireable overflow.. this might not be a problem in cycle accurate
207  // emulations.. but here it is (we only see a 20ms snapshot)
208 
209  sidemu->osc[v].envelopeOutput= (sidemu->osc[v].envelopeOutput + 1) & 0xff; // increase volume
210  }
211  sidemu->osc[v].exponential_counter = 0;
212  if (sidemu->osc[v].envelopeOutput == 0xff) {
213  sidemu->osc[v].envphase = Decay;
214  }
215  }
216  }
217  break;
218  }
219  case Decay: { // Phase 1 : Decay
220  if (triggerLFSR_Threshold(sidemu->osc[v].decay, &sidemu->osc[v].currentLFSR) && handleExponentialDelay(sidemu, v)) { // dec volume when threshold is reached
221  if (!sidemu->osc[v].zero_lock) {
222  if (sidemu->osc[v].envelopeOutput != sidemu->osc[v].sustain) {
223  sidemu->osc[v].envelopeOutput= (sidemu->osc[v].envelopeOutput - 1) & 0xff; // decrease volume
224  } else {
225  sidemu->osc[v].envphase = Sustain;
226  }
227  }
228  }
229  break;
230  }
231  case Sustain: { // Phase 2 : Sustain
232  if (sidemu->osc[v].envelopeOutput != sidemu->osc[v].sustain) {
233  sidemu->osc[v].envphase = Decay;
234  }
235  break;
236  }
237  case Release: { // Phase 3 : Release
238  // this phase must be explicitly triggered by clearing the GATE bit.
239  if (triggerLFSR_Threshold(sidemu->osc[v].release, &sidemu->osc[v].currentLFSR) && handleExponentialDelay(sidemu, v)) { // dec volume when threshold is reached
240  if (!sidemu->osc[v].zero_lock) {
241  sidemu->osc[v].envelopeOutput= (sidemu->osc[v].envelopeOutput - 1) & 0xff; // decrease volume
242  }
243  }
244  break;
245  }
246  }
247  if ((sidemu->osc[v].envelopeOutput == 0) && (previousEnvelopeOutput > sidemu->osc[v].envelopeOutput)) {
248  sidemu->osc[v].zero_lock = 1; // new "attack" phase must be started to unlock
249  }
250 }
251 
252 
253 
254 
255 // render a buffer of n samples with the actual register contents
256 void sid_render ( struct SidEmulation *sidemu, short *buffer, unsigned long len, int step )
257 {
258  unsigned long bp;
259  // step 1: convert the not easily processable sid registers into some
260  // more convenient and fast values (makes the thing much faster
261  // if you process more than 1 sample value at once)
262  unsigned char v;
263  for (v=0;v<3;v++) {
264  sidemu->osc[v].pulse = (sidemu->sid.v[v].pulse & 0xfff) << 16;
265  sidemu->osc[v].filter = get_bit(sidemu->sid.res_ftv,v);
266  sidemu->osc[v].attack = sidemu->envelope_counter_period[sidemu->sid.v[v].ad >> 4]; // threshhold to be reached before incrementing volume
267  sidemu->osc[v].decay = sidemu->envelope_counter_period[sidemu->sid.v[v].ad & 0xf];
268  unsigned char sustain= sidemu->sid.v[v].sr >> 4;
269  sidemu->osc[v].sustain = sustain<<4 | sustain;
270  sidemu->osc[v].release = sidemu->envelope_counter_period[sidemu->sid.v[v].sr & 0xf];
271  sidemu->osc[v].wave = sidemu->sid.v[v].wave;
272  sidemu->osc[v].freq = ((unsigned long)sidemu->sid.v[v].freq)*sidemu->freqmul;
273  }
274 
275 #ifdef SID_USES_FILTER
276  sidemu->filter.freq = ((sidemu->sid.ffreqhi << 3) + (sidemu->sid.ffreqlo&0x7)) * sidemu->filtmul;
277  sidemu->filter.freq <<= 1;
278 
279  if (sidemu->filter.freq>pfloat_ConvertFromInt(1)) {
280  sidemu->filter.freq=pfloat_ConvertFromInt(1);
281  }
282  // the above line isnt correct at all - the problem is that the filter
283  // works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
284  // for 32KHz and lower - well, but sound quality is bad enough then to
285  // neglect the fact that the filter doesnt come that high ;)
286  sidemu->filter.l_ena = get_bit(sidemu->sid.ftp_vol,4); // lowpass
287  sidemu->filter.b_ena = get_bit(sidemu->sid.ftp_vol,5); // bandpass
288  sidemu->filter.h_ena = get_bit(sidemu->sid.ftp_vol,6); // highpass
289  sidemu->filter.v3ena = !get_bit(sidemu->sid.ftp_vol,7); // chan3 off
290  sidemu->filter.vol = (sidemu->sid.ftp_vol & 0xf);
291  // filter.rez = 1.0-0.04*(float)(sid.res_ftv >> 4);
292 
293  /* We precalculate part of the quick float operation, saves time in loop later */
294  sidemu->filter.rez = (pfloat_ConvertFromFloat(1.2f) -
295  pfloat_ConvertFromFloat(0.04f)*(sidemu->sid.res_ftv >> 4)) >> 8;
296 #endif
297  // now render the buffer
298  for (bp=0;bp<len;bp+=step) {
299  int outo=0;
300  int outf=0;
301 
302  // step 2 : generate the two output signals (for filtered and non-
303  // filtered) from the osc/eg sections
304  for (v=0;v<3;v++) {
305  // update wave counter
306  sidemu->osc[v].counter = (sidemu->osc[v].counter+sidemu->osc[v].freq) & 0xFFFFFFF;
307  // reset counter / noise generator if TEST bit set (blocked at 0 as long as set)
308  if (sidemu->osc[v].wave & 0x08) {
309  // note: test bit has no influence on the envelope generator whatsoever
310  sidemu->osc[v].counter = 0;
311  sidemu->osc[v].noisepos = 0;
312  sidemu->osc[v].noiseval = 0xffffff;
313  }
314  unsigned char refosc = v?v-1:2; // reference oscillator for sync/ring
315  // sync oscillator to refosc if sync bit set
316  if (sidemu->osc[v].wave & 0x02)
317  if (sidemu->osc[refosc].counter < sidemu->osc[refosc].freq)
318  sidemu->osc[v].counter = sidemu->osc[refosc].counter * sidemu->osc[v].freq / sidemu->osc[refosc].freq;
319  // generate waveforms with really simple algorithms
320  unsigned char tripos = (unsigned char) (sidemu->osc[v].counter>>19);
321  unsigned char triout= tripos;
322  if (sidemu->osc[v].counter>>27) {
323  triout^=0xff;
324  }
325  unsigned char sawout = (unsigned char) (sidemu->osc[v].counter >> 20);
326  unsigned char plsout = (unsigned char) ((sidemu->osc[v].counter > sidemu->osc[v].pulse)-1);
327  if (sidemu->osc[v].wave&0x8) {
328  // TEST (Bit 3): The TEST bit, when set to one, resets and locks oscillator 1 at zero
329  // until the TEST bit is cleared. The noise waveform output of oscillator 1 is also
330  // reset and the pulse waveform output is held at a DC level
331  plsout= sidemu->level_DC;
332  }
333 
334  if ((sidemu->osc[v].wave & 0x40) && (sidemu->osc[v].wave & 0x10)) {
335  // note: correctly "Saw/Triangle should start from 0 and Pulse from FF".
336  // see $50 waveform impl below.. (because the impl is just a hack, this
337  // is an attempt to limit undesireable side effects and keep the original
338  // impl unchanged as far as possible..)
339  plsout ^= 0xff;
340  }
341  // generate noise waveform exactly as the SID does
342  if (sidemu->osc[v].noisepos!=(sidemu->osc[v].counter>>23))
343  {
344  sidemu->osc[v].noisepos = sidemu->osc[v].counter >> 23;
345  sidemu->osc[v].noiseval = (sidemu->osc[v].noiseval << 1) |
346  (get_bit(sidemu->osc[v].noiseval,22) ^ get_bit(sidemu->osc[v].noiseval,17));
347  // impl consistent with: http://www.sidmusic.org/sid/sidtech5.html
348  // doc here is probably wrong: http://www.oxyron.de/html/registers_sid.html
349  sidemu->osc[v].noiseout = (get_bit(sidemu->osc[v].noiseval,22) << 7) |
350  (get_bit(sidemu->osc[v].noiseval,20) << 6) |
351  (get_bit(sidemu->osc[v].noiseval,16) << 5) |
352  (get_bit(sidemu->osc[v].noiseval,13) << 4) |
353  (get_bit(sidemu->osc[v].noiseval,11) << 3) |
354  (get_bit(sidemu->osc[v].noiseval, 7) << 2) |
355  (get_bit(sidemu->osc[v].noiseval, 4) << 1) |
356  (get_bit(sidemu->osc[v].noiseval, 2) << 0);
357  }
358  unsigned char nseout = sidemu->osc[v].noiseout;
359 
360  // modulate triangle wave if ringmod bit set
361  if (sidemu->osc[v].wave & 0x04)
362  if (sidemu->osc[refosc].counter < 0x8000000)
363  triout^=0xff;
364 
365  // now mix the oscillators with an AND operation as stated in
366  // the SID's reference manual - even if this is completely wrong.
367  // well, at least, the $30 and $70 waveform sounds correct and there's
368  // no real solution to do $50 and $60, so who cares.
369 
370  // => wothke: the above statement is nonsense: there are many songs that need $50!
371 
372  unsigned char outv=0xFF;
373 #ifdef SID_DEBUG
374  if ((0x1 << v) & voiceEnableMask) {
375 #endif
376  if ((sidemu->osc[v].wave & 0x40) && (sidemu->osc[v].wave & 0x10)) {
377  // this is a poor man's impl for $50 waveform to improve playback of
378  // songs like Kentilla.sid, Convincing.sid, etc
379 
380  unsigned char idx= tripos > 0x7f ? 0xff-tripos : tripos;
381  outv &= pulseTriangleWavetable[idx];
382  outv &= plsout; // either on or off
383  } else {
384  int updated = 0;
385  if ((sidemu->osc[v].wave & 0x10) && ++updated) outv &= triout;
386  if ((sidemu->osc[v].wave & 0x20) && ++updated) outv &= sawout;
387  if ((sidemu->osc[v].wave & 0x40) && ++updated) outv &= plsout;
388  if ((sidemu->osc[v].wave & 0x80) && ++updated) outv &= nseout;
389  if (!updated) outv &= sidemu->level_DC;
390  }
391 #ifdef SID_DEBUG
392  } else {
393  outv=level_DC;
394  }
395 #endif
396 #ifdef SID_USES_SAMPLE_ENV_COUNTER
397  // using samples
398  simOneEnvelopeCycle(v);
399 #else
400  // using cycles
401  float c= sidemu->cyclesPerSample+sidemu->cycleOverflow;
402  unsigned int cycles= (unsigned int)c;
403  sidemu->cycleOverflow= c-cycles;
404 
405  int i;
406  for (i= 0; i<cycles; i++) {
407  simOneEnvelopeCycle(sidemu, v);
408  }
409 #endif
410  // now route the voice output to either the non-filtered or the
411  // filtered channel and dont forget to blank out osc3 if desired
412 
413 #ifdef SID_USES_FILTER
414  if (((v<2) || sidemu->filter.v3ena) && !sidemu->sMuteVoice[v]) {
415  if (sidemu->osc[v].filter) {
416  outf+=( ((int)(outv-0x80)) * (int)((sidemu->osc[v].envelopeOutput)) ) >>6;
417  } else {
418  outo+=( ((int)(outv-0x80)) * (int)((sidemu->osc[v].envelopeOutput)) ) >>6;
419  }
420  }
421 #else
422  // Don't use filters, just mix all voices together
423  if (!sMuteVoice[v]) outf+= (int)(((signed short)(outv-0x80)) * (sidemu->osc[v].envelopeOutput));
424 #endif
425  }
426 
427 #ifdef SID_USES_FILTER
428  // step 3
429  // so, now theres finally time to apply the multi-mode resonant filter
430  // to the signal. The easiest thing is just modelling a real electronic
431  // filter circuit instead of fiddling around with complex IIRs or even
432  // FIRs ...
433  // it sounds as good as them or maybe better and needs only 3 MULs and
434  // 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
435  // Mage messed the whole thing completely up - as the rest of the
436  // emulator.
437  // This filter sounds a lot like the 8580, as the low-quality, dirty
438  // sound of the 6581 is uuh too hard to achieve :)
439 
440  sidemu->filter.h = pfloat_ConvertFromInt(outf) - (sidemu->filter.b>>8)*sidemu->filter.rez - sidemu->filter.l;
441  sidemu->filter.b += pfloat_Multiply(sidemu->filter.freq, sidemu->filter.h);
442  sidemu->filter.l += pfloat_Multiply(sidemu->filter.freq, sidemu->filter.b);
443 
444  if (sidemu->filter.l_ena || sidemu->filter.b_ena || sidemu->filter.h_ena) {
445  // voice may be routed through filter without actually using any
446  // filters.. e.g. Dancing_in_the_Moonshine.sid
447  outf = 0;
448 
449  if (sidemu->filter.l_ena) outf+=pfloat_ConvertToInt(sidemu->filter.l);
450  if (sidemu->filter.b_ena) outf+=pfloat_ConvertToInt(sidemu->filter.b);
451  if (sidemu->filter.h_ena) outf+=pfloat_ConvertToInt(sidemu->filter.h);
452  }
453 
454  int final_sample = (sidemu->filter.vol*(outo+outf));
455 #else
456  int final_sample = outf>>2;
457 #endif
458 
459  // final_sample= generatePsidDigi(final_sample); // PSID stuff
460 
461  // Clipping
462  const int clipValue = 32767;
463  if ( final_sample < -clipValue ) {
464  final_sample = -clipValue;
465  } else if ( final_sample > clipValue ) {
466  final_sample = clipValue;
467  }
468 
469  short out= final_sample;
470  *(buffer+bp)= out;
471  }
472 }
473 
474 #ifdef SID_DEBUG
475 static char hex1 [16]= {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
476 static char *pokeInfo;
477 
478 static void traceSidPoke(int reg, unsigned char val) {
479  pokeInfo= malloc(sizeof(char)*13);
480 
481  pokeInfo[0]= hex1[(sFrameCount>>12)&0xf];
482  pokeInfo[1]= hex1[(sFrameCount>>8)&0xf];
483  pokeInfo[2]= hex1[(sFrameCount>>4)&0xf];
484  pokeInfo[3]= hex1[(sFrameCount&0xf)];
485  pokeInfo[4]= ' ';
486  pokeInfo[5]= 'D';
487  pokeInfo[6]= '4';
488  pokeInfo[7]= hex1[(reg>>4)];
489  pokeInfo[8]= hex1[(reg&0xf)];
490  pokeInfo[9]= ' ';
491  pokeInfo[10]= hex1[(val>>4)];
492  pokeInfo[11]= hex1[(val&0xf)];
493 
494  fprintf(stderr, "%s\n", pokeInfo);
495  free(pokeInfo);
496 }
497 #endif
498 
499 #if 0
500 static unsigned long getFrameCount() {
501  return sFrameCount;
502 }
503 
504 static void incFrameCount() {
505  sFrameCount++;
506 }
507 #endif
508 
509 
510 //
511 // Poke a value into the sid register
512 //
513 void sid_write_reg ( struct SidEmulation *sidemu, int reg, unsigned char val )
514 {
515  int voice=0;
516 #ifdef SID_DEBUG
517  // if (sTraceon) traceSidPoke(reg, val);
518 #endif
520  sidemu->writtenRegisterValues[reg] = val;
521  if (reg < 7) {}
522  if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
523  if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
524 
525  switch (reg) {
526  case 0: // Set frequency: Low byte
527  sidemu->sid.v[voice].freq = (sidemu->sid.v[voice].freq&0xff00) | val;
528  break;
529  case 1: // Set frequency: High byte
530  sidemu->sid.v[voice].freq = (sidemu->sid.v[voice].freq&0xff) | (val<<8);
531  break;
532  case 2: // Set pulse width: Low byte
533  sidemu->sid.v[voice].pulse = (sidemu->sid.v[voice].pulse&0x0f00) | val;
534  break;
535  case 3: // Set pulse width: High byte
536  sidemu->sid.v[voice].pulse = (sidemu->sid.v[voice].pulse&0xff) | ((val & 0xf)<<8);
537  break;
538  case 4: {
539  unsigned char oldGate= sidemu->sid.v[voice].wave&0x1;
540  unsigned char oldTest= sidemu->sid.v[voice].wave&0x8; // oscillator stop
541  unsigned char newGate= val & 0x01;
542  sidemu->sid.v[voice].wave = val;
543  // poor man's ADSR-bug detection: this is the kind of logic a player would most
544  // likely be using to deliberately trigger the the counter overflow..
545  if (oldTest && (val&0x8) && !oldGate && newGate) {
546  sidemu->sAdsrBugTriggerTime= sidemu->sCycles;
548  }
549  if (!oldGate && newGate) {
550  // If the envelope is then gated again (before the RELEASE cycle has reached
551  // zero amplitude), another ATTACK cycle will begin, starting from whatever amplitude had been reached.
552  sidemu->osc[voice].envphase= Attack;
553  sidemu->osc[voice].zero_lock= 0;
554  } else if (oldGate && !newGate) {
555  // if the gate bit is reset before the envelope has finished the ATTACK cycle,
556  // the RELEASE cycles will immediately begin, starting from whatever amplitude had been reached
557  // see http://www.sidmusic.org/sid/sidtech2.html
558  sidemu->osc[voice].envphase= Release;
559  }
560  }
561  break;
562  case 5:
563  sidemu->sid.v[voice].ad = val;
564  // ADSR-bug: if somebody goes through the above TEST/GATE drill and shortly thereafter
565  // sets up an A/D that is bound to already have run over then we can be pretty sure what he is after..
566  if (sidemu->sAdsrBugFrameCount == getFrameCount()) { // limitation: only works within the same frame
567  int delay= sidemu->envelope_counter_period_clck[val >> 4];
568  if ((sidemu->sCycles-sidemu->sAdsrBugTriggerTime) > delay ) {
569  sidemu->osc[voice].currentLFSR= clocksToSamples(delay); // force ARSR-bug by setting counter higher than the threshold
570  }
571  sidemu->sAdsrBugTriggerTime= 0;
572  }
573  break;
574  case 6: sidemu->sid.v[voice].sr = val; break;
575  case 21: sidemu->sid.ffreqlo = val; break;
576  case 22: sidemu->sid.ffreqhi = val; break;
577  case 23: sidemu->sid.res_ftv = val; break;
578  case 24: sidemu->sid.ftp_vol = val; break;
579  }
580 }
581 
582 
583 
584 #if 0
585 static void simOsc3Polling(unsigned short ad) {
586  // handle busy polling for sid oscillator3 (e.g. Ring_Ring_Ring.sid)
587  if ((ad == 0xd41b) && (memory[pc] == 0xd0) && (memory[pc+1] == 0xfb) /*BEQ above read*/) {
588  unsigned int t=(16777216/sid.v[2].freq)>>8; // cycles per 1 osc step up (if waveform is "sawtooth")
589  unsigned long usedCycles= sidemu->sCycles;
590  if (sLastPolledOsc < usedCycles) {
591  usedCycles-= sLastPolledOsc;
592  }
593  if (usedCycles<t) {
594  sidemu->sCycles+= (t-usedCycles); // sim busywait (just give them evenly spaced signals)
595  }
596  sLastPolledOsc= sidemu->sCycles;
597  io_area[0x041b]+= 1; // this hack should at least avoid endless loops
598  }
599 }
600 #endif
601 
602 static void resetEngine ( struct SidEmulation *sidemu, unsigned long mixfrq, unsigned level_dc )
603 {
604  sidemu->mixing_frequency = mixfrq;
605  sidemu->freqmul = 15872000 / mixfrq;
606  sidemu->filtmul = pfloat_ConvertFromFloat(21.5332031f)/mixfrq;
607  memset((unsigned char*)&sidemu->sid,0,sizeof(struct SidRegisters));
608  memset((unsigned char*)&sidemu->osc[0],0,sizeof(struct SidOsc));
609  memset((unsigned char*)&sidemu->osc[1],0,sizeof(struct SidOsc));
610  memset((unsigned char*)&sidemu->osc[2],0,sizeof(struct SidOsc));
611  memset((unsigned char*)&sidemu->filter,0,sizeof(struct SidFilter));
612  int i;
613  for (i=0;i<3;i++) {
614  // note: by default the rest of sid, osc & filter
615  // above is set to 0
616  sidemu->osc[i].envphase= Release;
617  sidemu->osc[i].zero_lock= 1;
618  sidemu->osc[i].noiseval = 0xffffff;
619  sidemu->sMuteVoice[i]= 0;
620  }
621  sidemu->bval= 0;
622  sidemu->wval= 0;
623  // status
624  sidemu->sFrameCount= 0;
625  sidemu->sCycles= 0;
626  sidemu->sAdsrBugTriggerTime= 0;
627  sidemu->sAdsrBugFrameCount= 0;
628  sidemu->cyclesPerSample=0;
629  sidemu->cycleOverflow=0;
630  // 0x38: supposedly DC level for MOS6581 (whereas it would be 0x80 for the "crappy new chip")
631  sidemu->level_DC = level_dc;
632 #ifdef SID_DEBUG
633  sidemu->voiceEnableMask = 0x7; // for debugging: allows to mute certain voices..
634 #endif
635  sidemu->limit_LFSR = 0;
636  sidemu->sLastFrameCount = 0;
637  // reset hacks
638  //sCiaNmiVectorHack= 0;
639  //sDummyDC04= 0;
640  //sFake_d012_count= 0;
641  //sFake_d012_loop= 0;
642  sidemu->sLastPolledOsc= 0;
643 }
644 
645 
646 
647 
648 // initialize SID and frequency dependant values
649 void sid_init ( struct SidEmulation *sidemu, unsigned long cyclesPerSec, unsigned long mixfrq )
650 {
651  sidemu->cyclesPerSec = cyclesPerSec;
652  resetEngine(sidemu, mixfrq, SID_DC_LEVEL);
653  //resetPsidDigi();
654  // envelope-generator stuff
655  sidemu->cycleOverflow= 0;
656  sidemu->cyclesPerSample= ((float)cyclesPerSec/mixfrq);
657  // in regular SID, 15-bit LFSR counter counts cpu-clocks, our problem is the lack of cycle by cycle
658  // SID emulation (we only have a SID snapshot every 20ms to work with) during rendering our computing
659  // granularity then is 'one sample' (not 'one cpu cycle' - but around 20).. instead of still trying to simulate a
660  // 15-bit cycle-counter we may directly use a sample-counter instead (which also reduces rounding issues).
661 #ifdef SID_USES_SAMPLE_ENV_COUNTER
662  sidemu->limit_LFSR = round(((float)0x8000)/sidemu->cyclesPerSample); // original counter was 15-bit
663  for (int i=0; i<16; i++) {
664  // counter must reach respective threshold before envelope value is incremented/decremented
665  sidemu->envelope_counter_period[i]= (int)round((float)(attackTimes[i]*cyclesPerSec)/1000/256/cyclesPerSample)+1; // in samples
666  sidemu->envelope_counter_period_clck[i]= (int)round((float)(attackTimes[i]*cyclesPerSec)/1000/256)+1; // in clocks
667  }
668 #else
669  sidemu->limit_LFSR = 0x8000; // counter 15-bit
670  for (int i=0; i<16; i++) {
671  // counter must reach respective threshold before envelope value is incremented/decremented
672  sidemu->envelope_counter_period[i]= (int)floor((float)(attackTimes[i]*cyclesPerSec)/1000/256)+1; // in samples
673  sidemu->envelope_counter_period_clck[i]= (int)floor((float)(attackTimes[i]*cyclesPerSec)/1000/256)+1; // in clocks
674  }
675 #endif
676  // lookup table for decay rates
677  static const unsigned char from[] = {93, 54, 26, 14, 6, 0};
678  static const unsigned char val[] = { 1, 2, 4, 8, 16, 30};
679  for (int i = 0; i<256; i++) {
680  unsigned char v= 1;
681  unsigned char j;
682  for (j= 0; j<6; j++) {
683  if (i>from[j]) {
684  v= val[j];
685  break;
686  }
687  }
688  exponential_delays[i]= v;
690  sidemu->writtenRegisterValues[i] = 0;
691  }
692 }
693 
694 
695 /* --- SNAPSHOT RELATED --- */
696 
697 
698 #ifdef XEMU_SNAPSHOT_SUPPORT
699 
700 #include <string.h>
701 
702 #define SNAPSHOT_SID_BLOCK_VERSION 0
703 #define SNAPSHOT_SID_BLOCK_SIZE 256
704 
705 int sid_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
706 {
707  Uint8 buffer[SNAPSHOT_SID_BLOCK_SIZE];
708  struct SidEmulation *sidemu = (struct SidEmulation *)def->user_data;
709  int a;
710  if (block->block_version != SNAPSHOT_SID_BLOCK_VERSION || block->sub_counter || block->sub_size != sizeof buffer)
711  RETURN_XSNAPERR_USER("Bad CIA block syntax");
712  a = xemusnap_read_file(buffer, sizeof buffer);
713  if (a) return a;
714  /* loading state ... */
715  for (a = 0; a < NUMBER_OF_SID_REGISTERS_FOR_SNAPSHOT; a++)
716  sid_write_reg(sidemu, a, buffer[a]);
717  return 0;
718 }
719 
720 
721 int sid_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
722 {
723  Uint8 buffer[SNAPSHOT_SID_BLOCK_SIZE];
724  struct SidEmulation *sidemu = (struct SidEmulation *)def->user_data;
725  int a = xemusnap_write_block_header(def->idstr, SNAPSHOT_SID_BLOCK_VERSION);
726  if (a) return a;
727  memset(buffer, 0xFF, sizeof buffer);
728  /* saving state ... */
730  return xemusnap_write_sub_block(buffer, sizeof buffer);
731 }
732 
733 #endif
sid_render
void sid_render(struct SidEmulation *sidemu, short *buffer, unsigned long len, int step)
Definition: sid.c:256
SidEmulation::sMuteVoice
unsigned int sMuteVoice[3]
Definition: sid.h:126
SidEmulation::envelope_counter_period
int envelope_counter_period[16]
Definition: sid.h:138
Release
@ Release
Definition: sid.h:71
SidEmulation::SidRegisters::SidVoice::ad
unsigned char ad
Definition: sid.h:86
pc
Uint16 pc
Definition: z8k1.c:127
SidEmulation::SidOsc::currentLFSR
signed int currentLFSR
Definition: sid.h:106
SidEmulation::level_DC
unsigned level_DC
Definition: sid.h:133
SidEmulation::SidOsc::noiseval
unsigned long noiseval
Definition: sid.h:111
SidEmulation::sAdsrBugTriggerTime
unsigned long sAdsrBugTriggerTime
Definition: sid.h:128
NUMBER_OF_SID_REGISTERS_FOR_SNAPSHOT
#define NUMBER_OF_SID_REGISTERS_FOR_SNAPSHOT
Definition: sid.h:75
SidEmulation::SidOsc::sustain
unsigned long sustain
Definition: sid.h:101
SidEmulation::cycleOverflow
float cycleOverflow
Definition: sid.h:131
SidEmulation::SidRegisters::SidVoice::wave
unsigned char wave
Definition: sid.h:85
SidEmulation::SidOsc::decay
unsigned long decay
Definition: sid.h:100
SidEmulation::SidFilter::h_ena
unsigned char h_ena
Definition: sid.h:118
SidEmulation::SidRegisters::ffreqlo
unsigned char ffreqlo
Definition: sid.h:89
SidEmulation::SidOsc::freq
unsigned long freq
Definition: sid.h:95
SID_DC_LEVEL
#define SID_DC_LEVEL
Definition: sid.h:57
SidEmulation::SidRegisters::SidVoice::sr
unsigned char sr
Definition: sid.h:87
SidEmulation::SidFilter::l_ena
unsigned char l_ena
Definition: sid.h:116
SidEmulation::SidOsc::counter
unsigned long counter
Definition: sid.h:103
SidEmulation::SidOsc::pulse
unsigned long pulse
Definition: sid.h:96
Uint8
uint8_t Uint8
Definition: fat32.c:51
SidEmulation::SidOsc::zero_lock
unsigned char zero_lock
Definition: sid.h:107
block
Uint32 block
Definition: fat32.c:156
SidEmulation::SidRegisters::SidVoice::freq
unsigned short freq
Definition: sid.h:83
SidEmulation::SidRegisters::res_ftv
unsigned char res_ftv
Definition: sid.h:91
SidEmulation::SidRegisters::ffreqhi
unsigned char ffreqhi
Definition: sid.h:90
sid
struct SidEmulation sid[NUMBER_OF_SIDS]
Definition: audio65.c:37
SidEmulation::SidOsc::envphase
unsigned char envphase
Definition: sid.h:109
SidEmulation::SidFilter::vol
int vol
Definition: sid.h:120
SidEmulation::cyclesPerSec
unsigned long cyclesPerSec
Definition: sid.h:143
SidEmulation::SidRegisters::v
struct SidEmulation::SidRegisters::SidVoice v[3]
getFrameCount
#define getFrameCount()
Definition: sid.c:67
SidEmulation::SidRegisters::SidVoice::pulse
unsigned short pulse
Definition: sid.h:84
SidEmulation::SidFilter::b
int b
Definition: sid.h:123
SidEmulation::SidFilter::freq
int freq
Definition: sid.h:115
SidEmulation::writtenRegisterValues
unsigned char writtenRegisterValues[NUMBER_OF_SID_REGISTERS_FOR_SNAPSHOT]
Definition: sid.h:80
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
sid_write_reg
void sid_write_reg(struct SidEmulation *sidemu, int reg, unsigned char val)
Definition: sid.c:513
SidEmulation::SidFilter::v3ena
unsigned char v3ena
Definition: sid.h:119
SidEmulation::SidOsc::attack
unsigned long attack
Definition: sid.h:99
SidEmulation::bval
unsigned char bval
Definition: sid.h:145
SidEmulation::SidOsc::release
unsigned long release
Definition: sid.h:102
SidEmulation::wval
unsigned short wval
Definition: sid.h:146
SidEmulation::SidOsc::exponential_counter
unsigned char exponential_counter
Definition: sid.h:108
SidEmulation::filtmul
int filtmul
Definition: sid.h:142
SidEmulation::SidOsc::noisepos
unsigned long noisepos
Definition: sid.h:110
sid.h
Sustain
@ Sustain
Definition: sid.h:70
SidEmulation::SidOsc::filter
unsigned char filter
Definition: sid.h:98
SidEmulation::filter
struct SidEmulation::SidFilter filter
SidEmulation::cyclesPerSample
float cyclesPerSample
Definition: sid.h:130
step
int step
Definition: dma65.c:84
SidEmulation::limit_LFSR
int limit_LFSR
Definition: sid.h:137
SidEmulation::SidOsc::envelopeOutput
unsigned char envelopeOutput
Definition: sid.h:105
SidEmulation::envelope_counter_period_clck
int envelope_counter_period_clck[16]
Definition: sid.h:139
SidEmulation::sLastPolledOsc
unsigned long sLastPolledOsc
Definition: sid.h:147
sid_init
void sid_init(struct SidEmulation *sidemu, unsigned long cyclesPerSec, unsigned long mixfrq)
Definition: sid.c:649
Decay
@ Decay
Definition: sid.h:69
SidEmulation::sid
struct SidEmulation::SidRegisters sid
SidEmulation::SidOsc::noiseout
unsigned char noiseout
Definition: sid.h:112
SidEmulation::SidFilter::l
int l
Definition: sid.h:124
Attack
@ Attack
Definition: sid.h:68
SidEmulation::SidFilter::rez
int rez
Definition: sid.h:121
SidEmulation::sCycles
unsigned long sCycles
Definition: sid.h:127
SidEmulation::mixing_frequency
unsigned long mixing_frequency
Definition: sid.h:140
SidEmulation::SidRegisters::ftp_vol
unsigned char ftp_vol
Definition: sid.h:92
SidEmulation::SidFilter::b_ena
unsigned char b_ena
Definition: sid.h:117
SidEmulation::sFrameCount
int sFrameCount
Definition: sid.h:79
SidEmulation::SidOsc::wave
unsigned char wave
Definition: sid.h:97
SidEmulation::osc
struct SidEmulation::SidOsc osc[3]
SidEmulation::sLastFrameCount
unsigned long sLastFrameCount
Definition: sid.h:144
SidEmulation::freqmul
unsigned long freqmul
Definition: sid.h:141
SidEmulation
Definition: sid.h:78
SidEmulation::SidFilter::h
int h
Definition: sid.h:122
SidEmulation::sAdsrBugFrameCount
unsigned long sAdsrBugFrameCount
Definition: sid.h:129