1 /***************************************************************************
2 player.h - description
3 -------------------
4 begin : Fri Jun 9 2000
5 copyright : (C) 2000 by Simon White
6 email : s_a_white@email.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 /***************************************************************************
18 * $Log: player.h,v $
19 * Revision 1.39 2002/12/03 23:25:53 s_a_white
20 * Prevent PSID digis from playing in real C64 mode.
21 *
22 * Revision 1.38 2002/11/27 00:16:51 s_a_white
23 * Make sure driver info gets reset and exported properly.
24 *
25 * Revision 1.37 2002/11/20 21:44:34 s_a_white
26 * Initial support for external DMA to steal cycles away from the CPU.
27 *
28 * Revision 1.36 2002/11/19 22:55:50 s_a_white
29 * PSIDv2NG/RSID changes to deal with spec updates for recommended
30 * implementation.
31 *
32 * Revision 1.35 2002/11/01 17:36:01 s_a_white
33 * Frame based support for old sidplay1 modes.
34 *
35 * Revision 1.34 2002/10/02 19:45:23 s_a_white
36 * RSID support.
37 *
38 * Revision 1.33 2002/09/12 21:01:31 s_a_white
39 * Added support for simulating the random delay before the user loads a
40 * program on a real C64.
41 *
42 * Revision 1.32 2002/09/09 18:01:30 s_a_white
43 * Prevent m_info driver details getting modified when C64 crashes.
44 *
45 * Revision 1.31 2002/07/21 19:39:41 s_a_white
46 * Proper error handling of reloc info overlapping load image.
47 *
48 * Revision 1.30 2002/07/20 08:34:52 s_a_white
49 * Remove unnecessary and pointless conts.
50 *
51 * Revision 1.29 2002/07/17 21:48:10 s_a_white
52 * PSIDv2NG reloc exclude region extension.
53 *
54 * Revision 1.28 2002/04/14 21:46:50 s_a_white
55 * PlaySID reads fixed to come from RAM only.
56 *
57 * Revision 1.27 2002/03/12 18:43:59 s_a_white
58 * Tidy up handling of envReset on illegal CPU instructions.
59 *
60 * Revision 1.26 2002/03/03 22:01:58 s_a_white
61 * New clock speed & sid model interface.
62 *
63 * Revision 1.25 2002/01/29 21:50:33 s_a_white
64 * Auto switching to a better emulation mode. m_tuneInfo reloaded after a
65 * config. Initial code added to support more than two sids.
66 *
67 * Revision 1.24 2002/01/28 19:32:01 s_a_white
68 * PSID sample improvements.
69 *
70 * Revision 1.23 2001/12/13 08:28:08 s_a_white
71 * Added namespace support to fix problems with xsidplay.
72 *
73 * Revision 1.22 2001/10/18 22:34:04 s_a_white
74 * GCC3 fixes.
75 *
76 * Revision 1.21 2001/10/02 18:26:36 s_a_white
77 * Removed ReSID support and updated for new scheduler.
78 *
79 * Revision 1.20 2001/09/20 19:32:39 s_a_white
80 * Support for a null sid emulation to use when a builder create call fails.
81 *
82 * Revision 1.19 2001/09/17 19:02:38 s_a_white
83 * Now uses fixed point maths for sample output and rtc.
84 *
85 * Revision 1.18 2001/09/01 11:15:46 s_a_white
86 * Fixes sidplay1 environment modes.
87 *
88 * Revision 1.17 2001/08/10 21:01:06 s_a_white
89 * Fixed RTC initialisation order warning.
90 *
91 * Revision 1.16 2001/08/10 20:03:19 s_a_white
92 * Added RTC reset.
93 *
94 * Revision 1.15 2001/07/25 17:01:13 s_a_white
95 * Support for new configuration interface.
96 *
97 * Revision 1.14 2001/07/14 16:46:16 s_a_white
98 * Sync with sidbuilder class project.
99 *
100 * Revision 1.13 2001/07/14 12:50:58 s_a_white
101 * Support for credits and debuging. External filter selection removed. RTC
102 * and samples obtained in a more efficient way. Support for component
103 * and sidbuilder classes.
104 *
105 * Revision 1.12 2001/04/23 17:09:56 s_a_white
106 * Fixed video speed selection using unforced/forced and NTSC clockSpeeds.
107 *
108 * Revision 1.11 2001/03/22 22:45:20 s_a_white
109 * Re-ordered initialisations to match defintions.
110 *
111 * Revision 1.10 2001/03/21 23:28:12 s_a_white
112 * Support new component names.
113 *
114 * Revision 1.9 2001/03/21 22:32:55 s_a_white
115 * Filter redefinition support. VIC & NMI support added.
116 *
117 * Revision 1.8 2001/03/08 22:48:33 s_a_white
118 * Sid reset on player destruction removed. Now handled locally by the sids.
119 *
120 * Revision 1.7 2001/03/01 23:46:37 s_a_white
121 * Support for sample mode to be selected at runtime.
122 *
123 * Revision 1.6 2001/02/28 18:52:55 s_a_white
124 * Removed initBank* related stuff.
125 *
126 * Revision 1.5 2001/02/21 21:41:51 s_a_white
127 * Added seperate ram bank to hold C64 player.
128 *
129 * Revision 1.4 2001/02/07 20:56:46 s_a_white
130 * Samples now delayed until end of simulated frame.
131 *
132 * Revision 1.3 2001/01/23 21:26:28 s_a_white
133 * Only way to load a tune now is by passing in a sidtune object. This is
134 * required for songlength database support.
135 *
136 * Revision 1.2 2001/01/07 15:58:37 s_a_white
137 * SID2_LIB_API now becomes a core define (SID_API).
138 *
139 * Revision 1.1 2000/12/12 19:15:40 s_a_white
140 * Renamed from sidplayer
141 *
142 ***************************************************************************/
143
144 #ifndef _player_h_
145 #define _player_h_
146
147 #include <string.h>
148
149 #include "config.h"
150 #include "sidplay2.h"
151 #include "sidenv.h"
152 #include "c64env.h"
153 #include "c64/c64xsid.h"
154 #include "c64/c64cia.h"
155 #include "c64/c64vic.h"
156
157 #include "mos6510/mos6510.h"
158 #include "sid6526/sid6526.h"
159 #include "nullsid.h"
160 #define SID2_MAX_SIDS 2
161
162 SIDPLAY2_NAMESPACE_START
163
164 class Player: private C64Environment, c64env
165 {
166 private:
167 static const double CLOCK_FREQ_NTSC;
168 static const double CLOCK_FREQ_PAL;
169 static const double VIC_FREQ_PAL;
170 static const double VIC_FREQ_NTSC;
171
172 static const char *TXT_PAL_VBI;
173 static const char *TXT_PAL_VBI_FIXED;
174 static const char *TXT_PAL_CIA;
175 static const char *TXT_PAL_UNKNOWN;
176 static const char *TXT_NTSC_VBI;
177 static const char *TXT_NTSC_VBI_FIXED;
178 static const char *TXT_NTSC_CIA;
179 static const char *TXT_NTSC_UNKNOWN;
180 static const char *TXT_NA;
181
182 static const char *ERR_CONF_WHILST_ACTIVE;
183 static const char *ERR_UNSUPPORTED_FREQ;
184 static const char *ERR_UNSUPPORTED_PRECISION;
185 static const char *ERR_MEM_ALLOC;
186 static const char *ERR_UNSUPPORTED_MODE;
187 static const char *credit[10]; // 10 credits max
188
189 static const char *ERR_PSIDDRV_NO_SPACE;
190 static const char *ERR_PSIDDRV_RELOC;
191
192 EventScheduler m_scheduler;
193
194 //SID6510 cpu(6510, "Main CPU");
195 SID6510 sid6510;
196 MOS6510 mos6510;
197 MOS6510 *cpu;
198 // Sid objects to use.
199 NullSID nullsid;
200 c64xsid xsid;
201 c64cia1 cia;
202 c64cia2 cia2;
203 SID6526 sid6526;
204 c64vic vic;
205 sidemu *sid[SID2_MAX_SIDS];
206
207 class EventMixer: public Event
208 {
209 private:
210 Player &m_player;
event(void)211 void event (void) { m_player.mixer (); }
212
213 public:
EventMixer(Player * player)214 EventMixer (Player *player)
215 :Event("Mixer"),
216 m_player(*player) {}
217 } mixerEvent;
218 friend class EventMixer;
219
220 class EventRTC: public Event
221 {
222 private:
223 EventContext &m_eventContext;
224 event_clock_t m_seconds;
225 event_clock_t m_period;
226 event_clock_t m_clk;
227
event(void)228 void event (void)
229 { // Fixed point 25.7 (approx 2 dp)
230 event_clock_t cycles;
231 m_clk += m_period;
232 cycles = m_clk >> 7;
233 m_clk &= 0x7F;
234 m_seconds++;
235 m_eventContext.schedule (this, cycles);
236 }
237
238 public:
EventRTC(EventContext * context)239 EventRTC (EventContext *context)
240 :Event("RTC"),
241 m_eventContext(*context),
242 m_seconds(0)
243 {;}
244
getTime()245 event_clock_t getTime () const {return m_seconds;}
246
reset(void)247 void reset (void)
248 { // Fixed point 25.7
249 m_seconds = 0;
250 m_clk = m_period & 0x7F;
251 m_eventContext.schedule (this, m_period >> 7);
252 }
253
clock(float64_t period)254 void clock (float64_t period)
255 { // Fixed point 25.7
256 m_period = (event_clock_t) (period / 10.0 * (float64_t) (1 << 7));
257 reset ();
258 }
259 } rtc;
260
261 // User Configuration Settings
262 SidTuneInfo m_tuneInfo;
263 SidTune *m_tune;
264 uint8_t *m_ram, *m_rom;
265 sid2_info_t m_info;
266 sid2_config_t m_cfg;
267
268 const char *m_errorString;
269 float64_t m_fastForwardFactor;
270 uint_least32_t m_mileage;
271 int_least32_t m_leftVolume;
272 int_least32_t m_rightVolume;
273 volatile sid2_player_t m_playerState;
274 volatile bool m_running;
275 int m_rand;
276
277 // Mixer settings
278 event_clock_t m_sampleClock;
279 event_clock_t m_samplePeriod;
280 uint_least32_t m_sampleCount;
281 uint_least32_t m_sampleIndex;
282 char *m_sampleBuffer;
283
284 // C64 environment settings
285 uint8_t m_bankReg;
286 uint8_t m_playBank;
287 uint_least16_t m_sidAddress[2];
288
289 // temp stuff -------------
290 bool isKernal;
291 bool isBasic;
292 bool isIO;
293 inline void evalBankSelect (uint8_t data);
294 void c64_initialise (void);
295 // ------------------------
296
297 private:
298 float64_t clockSpeed (sid2_clock_t clock, sid2_clock_t defaultClock,
299 bool forced);
300 int environment (sid2_env_t env);
301 void fakeIRQ (void);
302 int initialise (void);
303 void nextSequence (void);
304 void mixer (void);
305 void mixerReset (void);
306 void mileageCorrect (void);
307 int sidCreate (sidbuilder *builder, sid2_model_t model,
308 sid2_model_t defaultModel);
309 void sidSamples (bool enable);
310 void reset ();
311 uint8_t iomap (uint_least16_t addr);
312
313 uint8_t readMemByte_player (uint_least16_t addr);
314 uint8_t readMemByte_plain (uint_least16_t addr);
315 uint8_t readMemByte_io (uint_least16_t addr);
316 uint8_t readMemByte_sidplaytp (uint_least16_t addr);
317 uint8_t readMemByte_sidplaybs (uint_least16_t addr);
318 void writeMemByte_plain (uint_least16_t addr, uint8_t data);
319 void writeMemByte_playsid (uint_least16_t addr, uint8_t data);
320 void writeMemByte_sidplay (uint_least16_t addr, uint8_t data);
321
322 // Use pointers to please requirements of all the provided
323 // environments.
324 uint8_t (Player::*m_readMemByte) (uint_least16_t);
325 void (Player::*m_writeMemByte) (uint_least16_t, uint8_t);
326 uint8_t (Player::*m_readMemDataByte)(uint_least16_t);
327
readMemRamByte(uint_least16_t addr)328 uint8_t readMemRamByte (uint_least16_t addr)
329 { return m_ram[addr]; }
330
331 // Environment Function entry Points
332 void envReset (bool safe);
envReset(void)333 inline void envReset (void) { envReset (true); }
334 uint8_t envReadMemByte (uint_least16_t addr);
335 inline void envWriteMemByte (uint_least16_t addr, uint8_t data);
336 inline bool envCheckBankJump (uint_least16_t addr);
337 inline uint8_t envReadMemDataByte (uint_least16_t addr);
338 inline void envSleep (void);
339
envLoadFile(char * file)340 void envLoadFile (char *file)
341 {
342 char name[0x100] = "e:/emulators/c64/games/prgs/";
343 strcat (name, file);
344 strcat (name, ".sid");
345 m_tune->load (name);
346 stop ();
347 }
348
349 // Rev 2.0.3 Added - New Mixer Routines
350 uint_least32_t (Player::*output) (char *buffer);
351
352 // Rev 2.0.4 (saw) - Added to reduce code size
353 int_least32_t monoOutGenericLeftIn (uint_least8_t bits);
354 int_least32_t monoOutGenericStereoIn (uint_least8_t bits);
355 int_least32_t monoOutGenericRightIn (uint_least8_t bits);
356
357 // 8 bit output
358 uint_least32_t monoOut8MonoIn (char *buffer);
359 uint_least32_t monoOut8StereoIn (char *buffer);
360 uint_least32_t monoOut8StereoRIn (char *buffer);
361 uint_least32_t stereoOut8MonoIn (char *buffer);
362 uint_least32_t stereoOut8StereoIn (char *buffer);
363
364 // Rev 2.0.4 (jp) - Added 16 bit support
365 uint_least32_t monoOut16MonoIn (char *buffer);
366 uint_least32_t monoOut16StereoIn (char *buffer);
367 uint_least32_t monoOut16StereoRIn (char *buffer);
368 uint_least32_t stereoOut16MonoIn (char *buffer);
369 uint_least32_t stereoOut16StereoIn (char *buffer);
370
371 void interruptIRQ (bool state);
372 void interruptNMI (void);
373 void interruptRST (void);
signalBA(bool state)374 void signalBA (bool state) { cpu->rdySignal (state); }
signalAEC(bool state)375 void signalAEC (bool state) { cpu->aecSignal (state); }
376
377 // PSID driver
378 int psidDrvInstall (SidTuneInfo &tuneInfo, sid2_info_t &info);
379 void psidRelocAddr (SidTuneInfo &tuneInfo, int startp, int endp);
380
381 public:
382 Player ();
383
config(void)384 const sid2_config_t &config (void) const { return m_cfg; }
info(void)385 const sid2_info_t &info (void) const { return m_info; }
386
387 int config (const sid2_config_t &cfg);
388 int fastForward (uint percent);
389 int load (SidTune *tune);
mileage(void)390 uint_least8_t mileage (void) const { return m_mileage + time(); }
391 void pause (void);
392 uint_least32_t play (void *buffer, uint_least32_t length);
state(void)393 sid2_player_t state (void) const { return m_playerState; }
394 void stop (void);
time(void)395 uint_least32_t time (void) const {return rtc.getTime (); }
debug(bool enable)396 void debug (bool enable) { cpu->debug (enable); }
error(void)397 const char *error (void) const { return m_errorString; }
398 };
399
envSleep(void)400 inline void Player::envSleep (void)
401 {
402 if (m_info.environment != sid2_envR)
403 { // Start the sample sequence
404 xsid.suppress (false);
405 xsid.suppress (true);
406 }
407 }
408
interruptIRQ(bool state)409 inline void Player::interruptIRQ (bool state)
410 {
411 if (state)
412 {
413 if (m_info.environment == sid2_envR)
414 cpu->triggerIRQ ();
415 else
416 fakeIRQ ();
417 }
418 else
419 cpu->clearIRQ ();
420 }
421
interruptNMI()422 inline void Player::interruptNMI ()
423 {
424 cpu->triggerNMI ();
425 }
426
interruptRST()427 inline void Player::interruptRST ()
428 {
429 stop ();
430 }
431
432 SIDPLAY2_NAMESPACE_STOP
433
434 #endif // _player_h_
435