-
Notifications
You must be signed in to change notification settings - Fork 1
/
m114s.c
848 lines (713 loc) · 30.2 KB
/
m114s.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
/**********************************************************************************************
*
* SGS-Thomson Microelectronics M114S/M114A/M114AF Digital Sound Generator
* by Steve Ellenoff
* 09/02/2004
*
* Thanks to R.Belmont for Support & Agreeing to read through that nasty data sheet with me..
* Big thanks to Destruk for help in tracking down the data sheet.. Could have never done it
* without it!!
*
* A note about the word "table" as used by the M114S datasheet. A table refers to rom data
* representing 1 full period/cycle of a sound. The chip always reads from 2 different tables
* and intermixes them during playback for smoother sound. Different table lengths simply allow
* the chip to play lower frequencies due to the fact that the table represents 1 full period,ie
* 1 full sine wave, if that's what the rom data happens to contain.
*
* It would seem that the chip comes in two versions - the 4Mhz & 6Mhz versions. Unlike other sound chips which
* allow for clock variations on the same chip, this chip seems to use hard coded frequency tables
* in an internal ROM based on which version of the chip is being used.
*
* Some ideas were taken from the source from BSMT2000 & AY8910
*
* Note: No support yet for the 6Mhz version of the chip
**********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "driver.h"
#include "m114s.h"
#if 0
#define LOG(x) printf x
#else
#define LOG(x) logerror x
#endif
/**********************************************************************************************
CONSTANTS
***********************************************************************************************/
#define M114S_CHANNELS 16 // Chip has 16 internal channels for sound output
#define FRAC_BITS 16
#define FRAC_ONE (1 << FRAC_BITS)
#define FRAC_MASK (FRAC_ONE - 1)
/**********************************************************************************************
INTERNAL DATA STRUCTURES
***********************************************************************************************/
/* struct describing a single table */
struct M114STable
{
UINT32 sample_rate; /* Current Sample Rate to play back table */
UINT8 reread; /* # of times to re-read each byte from table */
UINT32 position; /* current reading position for table */
UINT32 start_address; /* start address (offset into ROM) for table */
UINT32 stop_address; /* stop address (offset into ROM) for table */
UINT16 length; /* length in bytes of the table */
UINT16 total_length; /* total length in bytes of the table (including repetitions) */
};
/* struct describing the registers for a single channel */
struct M114SChannelRegs
{
UINT8 atten; /* Attenuation Register */
UINT8 outputs; /* Output Pin Register */
UINT8 table1_addr; /* Table 1 MSB Starting Address Register */
UINT8 table2_addr; /* Table 2 MSB Starting Address Register */
UINT8 table_len; /* Table Length Register */
UINT8 read_meth; /* Read Method Register */
UINT8 interp; /* Interpolation Register */
UINT8 env_enable; /* Envelope Enable Register */
UINT8 oct_divisor; /* Octave Divisor Register */
UINT8 frequency; /* Frequency Register */
};
/* struct describing a single playing channel */
struct M114SChannel
{
/* registers */
struct M114SChannelRegs regs; /* register data for the channel */
/* internal state */
UINT8 active; /* is the channel active */
INT16 output[4096]; /* Holds output samples mixed from table 1 & 2 */
UINT32 outpos; /* Index into output samples */
UINT8 last_volume; /* Holds the last volume code set for the channel */
double sample_vol; /* Volume to apply to each sample output */
double vol_step; /* Volume step for volume envelope */
int end_of_table; /* End of Table Flag */
struct M114STable table1; /* Table 1 Data */
struct M114STable table2; /* Table 2 Data */
};
/* struct describing the entire M114S chip */
struct M114SChip
{
/* vars to be reset when the chip is reset */
int bytes_read; /* # of bytes read */
int channel; /* Which channel is being programmed via the data bus */
struct M114SChannelRegs tempch_regs; /* temporary channel register data for gathering the data programming */
struct M114SChannel channels[M114S_CHANNELS]; /* All the chip's internal channels */
/* static vars, ie do not reset values */
int stream; /* which stream are we using */
INT8 * region_base; /* pointer to the base of the ROM region */
struct M114Sinterface* intf; /* Pointer to the interface */
double reset_cycles; /* # of cycles that must pass between programming bytes to auto reset the chip */
int cpu_num; /* # of the cpu controlling the M114S */
};
/**********************************************************************************************
GLOBALS
***********************************************************************************************/
static struct M114SChip m114schip[MAX_M114S]; //Each M114S chip
static unsigned int VolTable[63]; //Store Volume Adjustment Table
static INT8 tb1[4096]; //Temp buffer for Table 1
static INT8 tb2[4096]; //Temp buffer for Table 2
/* Table 1 & Table 2 Repetition Values based on Mode */
static const int mode_to_rep[8][2] = {
{2,2}, //Mode 0
{1,1}, //Mode 1
{4,4}, //Mode 2
{1,1}, //Mode 3
{1,2}, //Mode 4
{1,1}, //Mode 5
{1,4}, //Mode 6
{1,1} //Mode 7
};
/* Table 1 Length Values based on Mode */
static const int mode_to_len_t1[8][8] = {
{16,32,64,128,256,512,1024,2048 }, //Mode 0
{16,32,64,128,256,512,1024,2048 }, //Mode 1
{16,32,64,128,256,512,1024,1024 }, //Mode 2
{16,32,64,128,256,512,1024,2048 }, //Mode 3
{16,32,64,128,256,512,1024,2048 }, //Mode 4
{16,32,64,128,256,512,1024,2048 }, //Mode 5
{16,32,64,128,256,512,1024,2048 }, //Mode 6
{16,32,64,128,256,512,1024,2048 }, //Mode 7
};
/* Table 2 Length Values based on Mode */
static const int mode_to_len_t2[8][8] = {
{16,32,64,128,256,512,1024,2048 }, //Mode 0
{16,32,64,128,256,512,1024,2048 }, //Mode 1
{16,32,64,128,256,512,1024,1024 }, //Mode 2
{16,32,64,128,256,512,1024,2048 }, //Mode 3
{ 8,16,32, 64,128,256, 512,1024 }, //Mode 4
{16,16,16, 32, 64,128, 256, 512 }, //Mode 5
{ 4, 8,16, 32, 64,128, 256, 512 }, //Mode 6
{16,16,16, 16, 32, 64, 128, 256 }, //Mode 7
};
#if 0
/* Frequency Table for a 4Mhz Clocked Chip */
static const double freqtable4Mhz[0xff] = {
1016.78,1021.45,1026.69,1031.46,1036.27,1041.67,1044.39,1045.48,
1046.57,1047.67,1048.77,1051.52,1056.52,1061.57,1066.67,1071.81, //0x00 - 0x0F
1077.01,1082.25,1087.55,1092.90,1098.30,1103.14,1106.81,1107.42,
1108.65,1109.88,1111.11,1114.21,1119.19,1124.86,1130.58,1135.72, //0x10 - 0x1F
1140.90,1146.79,1152.07,1158.08,1163.47,1168.91,1172.33,1173.71,
1174.40,1175.78,1177.16,1180.64,1186.24,1191.90,1197.60,1203.37, //0x20 - 0x2F
1209.19,1215.07,1221.00,1226.99,1232.29,1238.39,1242.24,1243.78,
1244.56,1245.33,1246.88,1250.78,1256.28,1262.63,1269.04,1274.70, //0x30 - 0x3F
1281.23,1287.00,1293.66,1299.55,1305.48,1312.34,1315.79,1317.52,
1318.39,1319.26,1321.00,1324.50,1331.56,1337.79,1344.09,1350.44, //0x40 - 0x4F
1356.85,1363.33,1369.86,1376.46,1383.13,1389.85,1393.73,1395.67,
1396.65,1397.62,1398.60,1403.51,1410.44,1417.43,1424.50,1430.62, //0x50 - 0x5F
1437.81,1445.09,1451.38,1458.79,1466.28,1472.75,1478.20,1479.29,
1480.38,1481.48,1482.58,1486.99,1494.77,1501.50,1508.30,1516.30, //0x60 - 0x6F
1523.23,1530.22,1538.46,1545.60,1552.80,1560.06,1564.95,1566.17,
1567.40,1568.63,1569.86,1576.04,1583.53,1591.09,1598.72,1606.43, //0x70 - 0x7F
1614.21,1622.06,1629.99,1638.00,1644.74,1652.89,1658.37,1659.75,
1661.13,1662.51,1663.89,1669.45,1677.85,1684.92,1693.48,1702.13, //0x80 - 0x8F
1709.40,1718.21,1727.12,1734.61,1743.68,1751.31,1757.47,1759.01, //(2nd entry in manual shows 1781.21 but that's cleary wrong)
1760.56,1762.11,1763.89,1768.35,1777.78,1785.71,1793.72,1803.43, //0x90 - 0x9F
1811.59,1819.84,1829.83,1838.24,1846.72,1855.29,1860.47,1862.20,
1863.93,1865.67,1867.41,1874.41,1883.24,1892.15,1901.14,1910.22, //0xA0 - 0xAF
1919.39,1928.64,1937.98,1947.42,1956.95,1966.57,1972.39,1974.33,
1976.28,1978.24,1980.20,1984.13,1994.02,2004.01,2014.10,2024.29, //0xB0 - 0xBF
2032.52,2042.90,2053.39,2063.98,2072.54,2083.33,2087.68,2089.86,
2092.05,2094.24,2096.44,2103.05,2114.16,2123.14,2134.47,2143.62, //0xC0 - 0xCF
2155.17,2164.50,2176.28,2185.79,2195.39,2207.51,2212.39,2214.84,
2217.29,2219.76,2222.22,2227.17,2239.64,2249.72,2259.89,2272.73, //0xD0 - 0xDF
2283.11,2293.58,2304.15,2314.81,2325.58,2339.18,2344.67,2347.42,
2350.18,2352.94,2355.71,2361.28,2372.48,2383.79,2395.21,2406.74, //0xE0 - 0xEF
0,0,0,0,0,0,0,
0,0,0,0,0,0,0, //0xF0 - 0xFF (Special codes)
};
#else
/* Frequency Table for a 4Mhz Clocked Chip
Note: Only the 1st set of frequencies came from the manual, the rest were calculated using 1 semitone increments
using a program called Test Tone Generator 3.91
*/
static const double freqtable4Mhz[0xff] = {
1016.78,1021.45,1026.69,1031.46,1036.27,1041.67,1044.39,1045.48,
1046.57,1047.67,1048.77,1051.52,1056.52,1061.57,1066.67,1071.81, //0x00 - 0x0F
1077.24,1082.19,1087.74,1092.79,1097.89,1103.61,1106.49,1107.65,
1108.80,1109.97,1111.13,1114.05,1119.34,1124.69,1130.10,1135.54, //0x10 - 0x1F
1141.29,1146.54,1152.42,1157.77,1163.17,1169.24,1172.29,1173.51,
1174.74,1175.97,1177.20,1180.29,1185.90,1191.57,1197.30,1203.07, //0x20 - 0x2F
1209.16,1214.72,1220.95,1226.62,1232.34,1238.76,1242.00,1243.29,
1244.59,1245.90,1247.20,1250.47,1256.42,1262.43,1268.49,1274.60, //0x30 - 0x3F
1281.06,1286.95,1293.55,1299.56,1305.62,1312.42,1315.85,1317.22,
1318.60,1319.98,1321.37,1324.83,1331.13,1337.49,1343.92,1350.40, //0x40 - 0x4F
1357.24,1363.47,1370.46,1376.83,1383.25,1390.46,1394.09,1395.55,
1397.00,1398.47,1399.94,1403.61,1410.29,1417.03,1423.83,1430.70, //0x50 - 0x5F
1437.94,1444.55,1451.96,1457.07,1465.51,1473.14,1477.00,1478.53,
1480.07,1481.63,1483.18,1486.99,1494.14,1501.29,1508.50,1515.77, //0x60 - 0x6F
1523.45,1530.45,1538.30,1545.44,1552.65,1560.74,1564.82,1566.45,
1568.08,1569.73,1571.38,1575.50,1583.00,1590.56,1598.20,1605.90, //0x70 - 0x7F
1614.04,1621.45,1629.77,1637.34,1644.98,1653.55,1657.87,1659.60,
1661.33,1663.07,1664.82,1669.18,1677.12,1685.14,1693.23,1701.39, //0x80 - 0x8F
1710.01,1717.87,1726.69,1734.70,1742.79,1751.87,1756.45,1758.28, //(2nd entry in manual shows 1781.21 but that's cleary wrong)
1760.11,1761.96,1763.81,1768.44,1776.85,1785.34,1793.92,1802.56, //0x90 - 0x9F
1811.70,1820.02,1829.35,1837.85,1846.42,1856.05,1860.89,1862.83,
1864.78,1866.74,1868.70,1873.60,1882.50,1891.50,1900.59,1909.75, //0xA0 - 0xAF
1919.43,1928.24,1938.13,1947.14,1956.22,1966.41,1971.55,1973.60,
1975.66,1977.74,1979.81,1985.01,1994.44,2003.98,2013.61,2023.31, //0xB0 - 0xBF
2033.56,2042.90,2053.38,2062.92,2072.54,2083.34,2088.78,2090.96,
2093.14,2095.34,2097.54,2103.04,2113.04,2123.14,2133.34,2143.62, //0xC0 - 0xCF
2154.48,2164.38,2175.48,2185.59,2195.78,2207.22,2212.99,2215.30,
2217.60,2219.94,2222.27,2228.09,2238.69,2249.39,2260.20,2271.09, //0xD0 - 0xDF
2282.59,2293.08,2304.84,2315.55,2326.35,2338.47,2344.58,2347.02,
2349.47,2351.94,2354.41,2360.58,2371.80,2383.14,2394.59,2406.13, //0xE0 - 0xEF
0,0,0,0,0,0,0,
0,0,0,0,0,0,0, //0xF0 - 0xFF (Special codes)
};
#endif
/**********************************************************************************************
build_vol_table -- Create volume table for each of the 62 possible volume codes
***********************************************************************************************/
static void build_vol_table(void)
{
int i;
double out;
/* calculate the volume->voltage conversion table */
/* The M114S has 62 levels, in a logarithmic scale (0.75 dB per step) */
//out = 0x7f; //Max Volume is 0x7F for an INT16 value
out = 0x6f; //Max Volume is 0x7F for an INT16 value
for (i = 0;i < 62;i++)
{
VolTable[i] = out + 0.5; /* round to nearest */
out /= 1.090184492; /* = 10 ^ (0.75/20) = 0.75dB */
}
//Max Attenuation
VolTable[62] = 0;
}
/**********************************************************************************************
read_sample -- returns 1 sample from the channel's output buffer, but upsamples the data
as necessary to match the Machine driver's output sample rate.
Note: eventually we should put some interpolation here to improve the sound quality.
***********************************************************************************************/
static INT16 read_sample(struct M114SChannel *channel, int sample_rate, int length)
{
UINT32 incr = (sample_rate<<FRAC_BITS)/Machine->sample_rate;
INT16 sample = 0;
INT16 offset = channel->outpos >> FRAC_BITS;
if(channel->outpos < (length << FRAC_BITS))
{
sample = channel->output[offset];
channel->outpos += incr;
}
else {
//printf("End of Table\n");
channel->end_of_table++;
channel->outpos = 0;
}
return sample;
}
/**********************************************************************************************
read_table -- Reads the two tables of rom data into a temporary buffer,
mixes the samples using the chip's internal interpolation equation,
applies the volume, and writes the single mixed sample to the output buffer for the channel.
It processes the entire table1 length of data.
Note: Eventually this should flag an End of Table, and should process new table data
***********************************************************************************************/
static void read_table(struct M114SChip *chip, struct M114SChannel *channel)
{
int t1start, t2start, lent1,lent2, rep1, rep2, i,j,intp;
INT16 d;
INT8 *rom = &chip->region_base[0];
t1start = channel->table1.start_address;
t2start = channel->table2.start_address;
lent1 = channel->table1.length;
lent2 = channel->table2.length;
rep1 = channel->table1.reread;
rep2 = channel->table2.reread;
intp = channel->regs.interp;
memset(&tb1,0,sizeof(tb1));
memset(&tb2,0,sizeof(tb2));
//printf("t1s = %d t2s = %d, l1=%d l2=%d, r1=%d, r2=%d, int = %d\n",t1start,t2start,lent1,lent2,rep1,rep2,intp);
//Table1 is always larger, so use that as the size
//Scan Table 1
for(i=0; i<lent1; i++)
for(j=0; j<rep1; j++)
tb1[j+(i*rep1)] = rom[i+t1start];
//Scan Table 2
for(i=0; i<lent2; i++)
for(j=0; j<rep2; j++)
tb2[j+(i*rep2)] = rom[i+t2start+0x2000]; //A13 is toggled high on Table 2 reading (Implementation specific - ie, Mr. Game)
//Make up difference with zero?
for(i=0;i<(lent1-lent2);i++)
tb2[lent2+i] = 0;
//Now Mix based on Interpolation Bits
for(i=0; i<lent1*rep1; i++) {
d = (INT16)(tb1[i] * (intp + 1) / 16) + (tb2[i] * (15-intp) / 16);
//Apply volume - If envelope - use volume step to calculate sample volume, otherwise, apply directly
#if USE_VOL_ENVELOPE
if(channel->regs.env_enable) {
channel->sample_vol+= channel->vol_step;
}
#endif
d *= channel->sample_vol;
//write to output buffer
channel->output[i] = d;
}
}
#if USE_REAL_OUTPUTS
/**********************************************************************************************
m114s_update -- update the sound chip so that it is in sync with CPU execution
***********************************************************************************************/
//Seems this sometimes still produces some static, but I don't know why!
static void m114s_update(int num, INT16 **buffer, int samples)
{
struct M114SChip *chip = &m114schip[num];
struct M114SChannel *channel;
INT16 sample;
INT16 accum[M114S_OUTPUT_CHANNELS];
int c;
while (samples > 0)
{
/* clear accum */
for( c = 0; c < M114S_OUTPUT_CHANNELS; c++)
accum[c] = 0;
/* loop over channels */
for (c = 0; c < M114S_CHANNELS; c++)
{
channel = &chip->channels[c];
/* Grab the next sample from the table data if the channel is active */
if(channel->active) {
//We use Table 1 to drive everything, as Table 2 is really for mixing into Table 1..
sample = read_sample(channel, channel->table1.sample_rate, channel->table1.total_length);
//Mix the output of this channel to the appropriate output channel
accum[channel->regs.outputs]+= sample;
}
}
/* Update the buffer & Ensure we don't clip */
for( c = 0; c < M114S_OUTPUT_CHANNELS; c++)
*buffer[c]++ = (accum[c] < -16384) ? -16384 : (accum[c] > 16384) ? 16384 : accum[c];
samples--;
}
}
#else
/**********************************************************************************************
m114s_update -- update the sound chip so that it is in sync with CPU execution
***********************************************************************************************/
static void m114s_update(int num, INT16 **buffer, int samples)
{
struct M114SChip *chip = &m114schip[num];
struct M114SChannel *channel;
INT16 sample;
int c;
while (samples > 0)
{
/* loop over channels - each channel write's to it's own output mixer channel (not accurate for emulation)*/
for (c = 0; c < M114S_CHANNELS; c++)
{
sample = 0;
channel = &chip->channels[c];
/* Grab the next sample from the table data if the channel is active */
if(channel->active) {
//We use Table 1 to drive everything, as Table 2 is really for mixing into Table 1..
sample = read_sample(channel, channel->table1.sample_rate, channel->table1.total_length);
*buffer[c]++ = sample;
}
else {
*buffer[c]++ = 0;
}
}
samples--;
}
}
#endif
/**********************************************************************************************
M114S_sh_start -- start emulation of the M114S
***********************************************************************************************/
INLINE void init_channel(struct M114SChannel *channel)
{
//set all internal registers to 0!
channel->active = 0;
channel->outpos = 0;
memset(&channel->output,0,sizeof(channel->output));
memset(&channel->regs,0,sizeof(channel->regs));
memset(&channel->table1,0,sizeof(channel->table1));
memset(&channel->table2,0,sizeof(channel->table2));
}
INLINE void init_all_channels(struct M114SChip *chip)
{
int i;
/* init the channels */
for (i = 0; i < M114S_CHANNELS; i++)
init_channel(&chip->channels[i]);
//Chip init stuff
memset(&chip->tempch_regs,0,sizeof(&chip->tempch_regs));
chip->channel = 0;
chip->bytes_read = 0;
memset(&tb1,0,sizeof(tb1));
memset(&tb2,0,sizeof(tb2));
}
int M114S_sh_start(const struct MachineSound *msound)
{
const struct M114Sinterface *intf = msound->sound_interface;
char stream_name[M114S_OUTPUT_CHANNELS][40];
const char *stream_name_ptrs[M114S_OUTPUT_CHANNELS];
int vol[M114S_OUTPUT_CHANNELS];
int i,j;
/* create the volume table */
build_vol_table();
/* initialize the chips */
memset(&m114schip, 0, sizeof(m114schip));
for (i = 0; i < intf->num; i++)
{
/* generate the name and create the stream */
for(j=0; j<M114S_OUTPUT_CHANNELS; j++) {
sprintf(stream_name[j], "%s #%d Ch%d",sound_name(msound),i,j);
stream_name_ptrs[j] = stream_name[j];
vol[j] = 25;
}
/* Chip specific setup based on clock speed */
switch(intf->baseclock[i]) {
// 4 Mhz
case 4000000:
m114schip[i].reset_cycles = 4000000 * 0.000128; // Chip resets in 128us (microseconds)
break;
// 6 Mhz
case 6000000:
m114schip[i].reset_cycles = 6000000 * 0.000085; // Chip resets in 85us (microseconds)
LOG(("M114S Chip #%d - 6Mhz chip clock not supported at this time!\n",i));
return 1;
default:
LOG(("M114S Chip #%d - Invalid Base Clock value specified! Only 4Mhz & 6Mhz values allowed!\n",i));
return 1;
}
//If this value is not used, the pitch is wrong, why?!!
Machine->sample_rate = 44100;
/* create the stream */
m114schip[i].stream = stream_init_multi(M114S_OUTPUT_CHANNELS, stream_name_ptrs, vol, Machine->sample_rate, i, m114s_update);
if (m114schip[i].stream == -1)
return 1;
/* initialize the region & interface info */
m114schip[i].cpu_num = intf->cpunum[i];
m114schip[i].region_base = (INT8 *)memory_region(intf->region[i]);
m114schip[i].intf = (struct M114Sinterface *)intf;
/* init the channels */
init_all_channels(&m114schip[i]);
}
/* success */
return 0;
}
/**********************************************************************************************
M114S_sh_stop -- stop emulation of the M114S
***********************************************************************************************/
void M114S_sh_stop(void)
{
}
/**********************************************************************************************
M114S_sh_reset -- reset emulation of the M114S
***********************************************************************************************/
void M114S_sh_reset(void)
{
int i;
for (i = 0; i < MAX_M114S; i++) {
/* reset all channels */
init_all_channels(&m114schip[i]);
}
}
/**********************************************************************************************
process_freq_codes -- There are up to 16 special values for frequency that signify a code
***********************************************************************************************/
static void process_freq_codes(struct M114SChip *chip)
{
//Grab pointer to channel being programmed
struct M114SChannel *channel = &chip->channels[chip->channel];
switch(channel->regs.frequency)
{
//ROMID - ROM Identification (Are you kidding me?)
case 0xf8:
LOG(("* * Channel: %02d: Frequency Code: %02x - ROMID * * \n",chip->channel,channel->regs.frequency));
break;
//SSG - Set Syncro Global
case 0xf9:
LOG(("* * Channel: %02d: Frequency Code: %02x - SSG * * \n",chip->channel,channel->regs.frequency));
break;
//RSS - Reverse Syncro Status
case 0xfa:
LOG(("* * Channel: %02d: Frequency Code: %02x - RSS * * \n",chip->channel,channel->regs.frequency));
break;
//RSG - Reset Syncro Global
case 0xfb:
LOG(("* * Channel: %02d: Frequency Code: %02x - RSG * * \n",chip->channel,channel->regs.frequency));
break;
//PSF - Previously Selected Frequency
case 0xfc:
LOG(("* * Channel: %02d: Frequency Code: %02x - PSF * * \n",chip->channel,channel->regs.frequency));
break;
//FFT - Forced Table Termination
case 0xff:
//Stop whatever output from playing by simulating an end of table event!
channel->outpos = 0;
//LOG(("* * Channel: %02d: Frequency Code: %02x - FFT * * \n",chip->channel,channel->regs.frequency));
break;
default:
LOG(("* * Channel: %02d: Frequency Code: %02x - UNKNOWN * * \n",chip->channel,channel->regs.frequency));
}
}
/**********************************************************************************************
process_channel_data -- complete programming for a channel now exists, process it!
***********************************************************************************************/
static void process_channel_data(struct M114SChip *chip)
{
//Grab pointer to channel being programmed
struct M114SChannel *channel = &chip->channels[chip->channel];
/* Force stream to update */
stream_update(chip->stream, 0);
//Reset # of bytes for next group
chip->bytes_read = 0;
//Copy data to the appropriate channel registers from our temp channel registers
memcpy(channel,&chip->tempch_regs,sizeof(chip->tempch_regs));
//Look for the 16 special frequency codes starting from 0xff
if(channel->regs.frequency > (0xff-16)) {
process_freq_codes(chip);
//FFT & PSF are the only codes that should continue to process channel data AFAIK
if(channel->regs.frequency != 0xff && channel->regs.frequency !=0xfc)
return;
}
//If Attenuation set to 0x3F - The channel becomes inactive
if(channel->regs.atten == 0x3f) {
channel->active = 0;
return;
}
else
//Process this channel
{
//Calculate new volume
int newvol = VolTable[channel->regs.atten];
//Calculate # of repetitions for Table 1 & Table 2
int rep1 = mode_to_rep[channel->regs.read_meth][0];
int rep2 = mode_to_rep[channel->regs.read_meth][1];
//Calculate Table Length for Table 1 & Table 2
int lent1 = mode_to_len_t1[channel->regs.read_meth][channel->regs.table_len];
int lent2 = mode_to_len_t2[channel->regs.read_meth][channel->regs.table_len];
//Calculate Table 1 Start & End Address in ROM
int t1start = (channel->regs.table1_addr<<5) & (~(lent1-1)&0x1fff); //T1 Addr is upper 8 bits, but masked by length
int t1end = t1start + (lent1-1);
//Calculate Table 2 Start & End Address in ROM
int t2start = (channel->regs.table2_addr<<5) & (~(lent2-1)&0x1fff); //T2 Addr is upper 8 bits, but masked by length
int t2end = t2start + (lent2-1);
//Calculate initial frequency of both tables
double freq1, freq2;
freq1 = freq2 = freqtable4Mhz[channel->regs.frequency];
//Freq Table is based on 16 byte length & 1 pass read - adjust for length..
if(lent1>16) freq1 /= (double)(lent1/16);
if(lent2>16) freq2 /= (double)(lent2/16);
//Adjust Start & Stop Address - Special case for table length of 16 - Bit 5 always 1 in this case
if(lent1 == 16) {
t1start |= 0x10;
t1end |= 0x10;
}
if(lent2 == 16) {
t2start |= 0x10;
t2end |= 0x10;
}
//Channel is now active!
channel->active = 1;
//Adjust frequency if octave divisor set
if(channel->regs.oct_divisor)
{
freq1/=2;
freq2/=2;
}
//Setup Sample Rate - Current Adjusted Frequency * the length of the table
channel->table1.sample_rate = freq1 * lent1;
channel->table2.sample_rate = freq2 * lent2;
//Assign start & stop address offsets to ROM
channel->table1.start_address = t1start;
channel->table2.start_address = t2start;
channel->table1.stop_address = t1end;
channel->table2.stop_address = t2end;
//Assign # of times to re-read & Length
channel->table1.reread = rep1;
channel->table2.reread = rep2;
channel->table1.length = lent1;
channel->table2.length = lent2;
channel->table1.total_length = lent1*rep1;
channel->table2.total_length = lent2*rep2;
//Calculate Sample Volume
//- If Envelope should be used, Take the difference in new volume & current volume, and break it into the # of samples in the table
//- If No Envelope should be used, Volume is simply based on the Volume Table
#if USE_VOL_ENVELOPE
if(channel->regs.env_enable) {
INT8 voldiff = newvol - channel->last_volume;
channel->vol_step = (double)voldiff / channel->table1.total_length;
channel->sample_vol = channel->last_volume;
}
else
#endif
{
channel->sample_vol = newvol;
}
//Update Last Volume
channel->last_volume = newvol;
//Temp hack to ensure we only generate the ouput data 1x - this is WRONG and needs to be addressed eventually!
//if(channel->output[0] == 0)
read_table(chip,channel);
#if 1
//if(chip->channel == 2) {
if(channel->regs.outputs == 2) {
if(channel->regs.frequency == 0x70)
{
LOG(("orig: = %0f, freq1 = %0f, sample_rate = %0d \n",freqtable4Mhz[channel->regs.frequency],freq1,channel->table1.sample_rate));
}
//printf("EOT=%d\n",channel->end_of_table);
LOG(("C:%02d V:%02d FQ:%03x TS1:%02x TS2:%02x T1L:%04d T1R:%01d T2L:%04d T2R:%01d OD=%01d I:%02d E:%01d\n",
chip->channel,
channel->regs.atten,
channel->regs.frequency,
t1start,t2start,
lent1,rep1,
lent2,rep2,
channel->regs.oct_divisor,
channel->regs.interp,
channel->regs.env_enable
));
}
#endif
}
}
/**********************************************************************************************
m114s_data_write -- handle a write to the data bus of the M114S
The chip has a data bus width of 6 bits, and must be fed 8 consecutive bytes
- thus 48 bits of programming! All data must be fed in order, so we make a few assumptions.
***********************************************************************************************/
static void m114s_data_write(struct M114SChip *chip, data8_t data)
{
/* Check if the chip needs to 'auto-reset' - this occurs if during the programming sequence (ie before all 8 bytes read)
a certain amount of time elapses without receiving another byte of programming...
128us in the 4Mhz chip, 85us in the 6Mhz chip.
*/
static double last_totcyc = 0;
double curr_totcyc = cpu_gettotalcycles(chip->cpu_num);
double diff = abs(curr_totcyc-last_totcyc);
last_totcyc = curr_totcyc;
if(chip->bytes_read && diff > chip->reset_cycles) {
LOG(("M114S: Auto Reset - bytes read=%0d - data=%0x, elapsed cycles = %f\n",chip->bytes_read,data&0x3f,diff));
M114S_sh_reset();
}
data &= 0x3f; //Strip off bits 7-8 (only 6 bits for the data bus to the chip)
chip->bytes_read++;
switch(chip->bytes_read)
{
/* BYTE #1 -
Bits 0-5: Attenuation Value (0-63) - 0 = No Attenuation, 3E = Max, 3F = Silence active channel */
case 1:
chip->tempch_regs.atten = data;
break;
/* BYTE #2 -
Bits 0-1: Table 2 Address (Bits 6-7)
Bits 2-3: Table 1 Address (Bits 6-7)
Bits 3-5: Output Pin Selection (0-3) */
case 2:
chip->tempch_regs.table2_addr = (data & 0x03)<<6;
chip->tempch_regs.table1_addr = (data & 0x0c)<<4;
chip->tempch_regs.outputs = (data & 0x30)>>4;
break;
/* BYTE #3 -
Bits 0-5: Table 2 Address (Bits 0-5) */
case 3:
chip->tempch_regs.table2_addr |= data;
break;
/* BYTE #4 -
Bits 0-5: Table 1 Address (Bits 0-5) */
case 4:
chip->tempch_regs.table1_addr |= data;
break;
/* BYTE #5 -
Bits 0-2: Reading Method
Bits 3-5: Table Length */
case 5:
chip->tempch_regs.read_meth = data & 0x07;
chip->tempch_regs.table_len = (data & 0x38)>>3;
break;
/* BYTE #6 -
Bits 0 : Octave Divisor
Bits 1 : Envelope Enable/Disable
Bits 2-5: Interpolation Value (0-4) */
case 6:
chip->tempch_regs.oct_divisor = data & 1;
chip->tempch_regs.env_enable = (data & 2)>>1;
chip->tempch_regs.interp = (data & 0x3c)>>2;
break;
/* BYTE #7 -
Bits 0-1: Frequency (Bits 0-1)
Bits 2-5: Channel */
case 7:
chip->tempch_regs.frequency = (data&0x03);
chip->channel = (data & 0x3c)>>2;
break;
/* BYTE #8 -
Bits 0-5: Frequency (Bits 2-7) */
case 8:
chip->tempch_regs.frequency |= (data<<2);
/* Process the channel data */
process_channel_data(chip);
break;
default:
LOG(("M114S.C - logic error - too many bytes processed: %x\n",chip->bytes_read));
}
}
/**********************************************************************************************
M114S_data_0_w -- handle a write to the current register
***********************************************************************************************/
WRITE_HANDLER( M114S_data_w )
{
m114s_data_write(&m114schip[offset], data);
}