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