system.cpp
  1  //
  2  // Copyright (c) 2004 K. Wilkins
  3  //
  4  // This software is provided 'as-is', without any express or implied warranty.
  5  // In no event will the authors be held liable for any damages arising from
  6  // the use of this software.
  7  //
  8  // Permission is granted to anyone to use this software for any purpose,
  9  // including commercial applications, and to alter it and redistribute it
 10  // freely, subject to the following restrictions:
 11  //
 12  // 1. The origin of this software must not be misrepresented; you must not
 13  //    claim that you wrote the original software. If you use this software
 14  //    in a product, an acknowledgment in the product documentation would be
 15  //    appreciated but is not required.
 16  //
 17  // 2. Altered source versions must be plainly marked as such, and must not
 18  //    be misrepresented as being the original software.
 19  //
 20  // 3. This notice may not be removed or altered from any source distribution.
 21  //
 22  
 23  //////////////////////////////////////////////////////////////////////////////
 24  //                       Handy - An Atari Lynx Emulator                     //
 25  //                          Copyright (c) 1996,1997                         //
 26  //                                 K. Wilkins                               //
 27  //////////////////////////////////////////////////////////////////////////////
 28  // System object class                                                      //
 29  //////////////////////////////////////////////////////////////////////////////
 30  //                                                                          //
 31  // This class provides the glue to bind of of the emulation objects         //
 32  // together via peek/poke handlers and pass thru interfaces to lower        //
 33  // objects, all control of the emulator is done via this class. Update()    //
 34  // does most of the work and each call emulates one CPU instruction and     //
 35  // updates all of the relevant hardware if required. It must be remembered  //
 36  // that if that instruction involves setting SPRGO then, it will cause a    //
 37  // sprite painting operation and then a corresponding update of all of the  //
 38  // hardware which will usually involve recursive calls to Update, see       //
 39  // Mikey SPRGO code for more details.                                       //
 40  //                                                                          //
 41  //    K. Wilkins                                                            //
 42  // August 1997                                                              //
 43  //                                                                          //
 44  //////////////////////////////////////////////////////////////////////////////
 45  // Revision History:                                                        //
 46  // -----------------                                                        //
 47  //                                                                          //
 48  // 01Aug1997 KW Document header added & class documented.                   //
 49  //                                                                          //
 50  //////////////////////////////////////////////////////////////////////////////
 51  #include <Arduino.h>
 52  
 53  #include <stdio.h>
 54  #include <stdlib.h>
 55  #include <string.h>
 56  #include "system.h"
 57  
 58  //
 59  // Define the global variable list
 60  //
 61  ULONG   gSystemCycleCount=0;
 62  ULONG   gNextTimerEvent=0;
 63  ULONG   gCPUWakeupTime=0;
 64  ULONG   gIRQEntryCycle=0;
 65  ULONG   gCPUBootAddress=0;
 66  ULONG   gBreakpointHit=FALSE;
 67  ULONG   gSingleStepMode=FALSE;
 68  ULONG   gSingleStepModeSprites=FALSE;
 69  ULONG   gSystemIRQ=FALSE;
 70  ULONG   gSystemNMI=FALSE;
 71  ULONG   gSystemCPUSleep=FALSE;
 72  ULONG   gSystemCPUSleep_Saved=FALSE;
 73  ULONG   gSystemHalt=FALSE;
 74  ULONG   gThrottleMaxPercentage=100;
 75  ULONG   gThrottleLastTimerCount=0;
 76  ULONG   gThrottleNextCycleCheckpoint=0;
 77  ULONG   gEndOfFrame=0;
 78  ULONG   gTimerCount=0;
 79  ULONG   gRenderFrame=1;
 80  
 81  ULONG   gAudioEnabled=FALSE;
 82  ULONG   *gAudioBuffer;
 83  ULONG   gAudioBufferPointer=0;
 84  ULONG   gAudioLastUpdateCycle=0;
 85  UBYTE   *gPrimaryFrameBuffer=NULL;
 86  
 87  
 88  extern void lynx_decrypt(unsigned char * result, const unsigned char * encrypted, const int length);
 89  
 90  PROGMEM static const ULONG   crc32Table[256] =
 91  {
 92     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 93     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 94     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
 95     0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
 96     0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
 97     0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
 98     0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
 99     0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
100     0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
101     0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
102     0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
103     0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
104     0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
105     0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
106     0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
107     0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
108     0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
109     0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
110     0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
111     0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
112     0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
113     0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
114     0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
115     0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
116     0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
117     0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
118     0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
119     0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
120     0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
121     0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
122     0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
123     0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
124     0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
125     0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
126     0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
127     0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
128     0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
129     0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
130     0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
131     0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
132     0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
133     0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
134     0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
135  };
136  
137  
138  ULONG crc32_le(ULONG crc32, UBYTE const * array, ULONG size)
139  {
140     for (ULONG i = 0; i < size; i++)
141        crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF];
142  
143     return (~crc32);
144  }
145  
146  #if 0
147  int lss_read(void* dest, int varsize, int varcount, LSS_FILE *fp)
148  {
149     ULONG copysize;
150     copysize=varsize*varcount;
151     if((fp->index + copysize) > fp->index_limit) copysize=fp->index_limit - fp->index;
152     memcpy(dest,fp->memptr+fp->index,copysize);
153     fp->index+=copysize;
154     return copysize;
155  }
156  
157  int lss_write(void* src, int varsize, int varcount, LSS_FILE *fp)
158  {
159     ULONG copysize;
160     copysize=varsize*varcount;
161     //if((fp->index + copysize) > fp->index_limit) copysize=fp->index_limit - fp->index;
162     memcpy(fp->memptr+fp->index,src,copysize);
163     fp->index+=copysize;
164     return copysize;
165  }
166  
167  int lss_printf(LSS_FILE *fp, const char *str)
168  {
169     ULONG copysize;
170     copysize=strlen(str);
171     memcpy(fp->memptr+fp->index,str,copysize);
172     fp->index+=copysize;
173     return copysize;
174  }
175  #endif
176  
177  
178  CSystem::CSystem(const char* filename, long displayformat, long samplerate)
179   : mCart(NULL),
180     mRam(NULL),
181     mCpu(NULL),
182     mMikie(NULL),
183     mSusie(NULL),
184     mEEPROM(NULL)
185  {
186     UBYTE *filedata = NULL;
187     ULONG filesize = 0;
188     FILE *fp;
189  
190     log_printf("Loading '%s'...\n", filename);
191  
192     filesize = emu_FileSize((char*)filename);
193     if (filesize > 0) {
194        filedata = (UBYTE*)emu_SMalloc(filesize);
195        emu_LoadFile((char*)filename, (char*)filedata, filesize);
196     }
197     /*
198     if ((fp = fopen(filename, "rb"))) {
199        fseek(fp, 0, SEEK_END);
200        filesize = ftell(fp);
201        filedata = (UBYTE*)emu_SMalloc(filesize);
202        fseek(fp, 0, SEEK_SET);
203        if (!filedata) {
204           log_printf("-> memory allocation failed (%d bytes)!\n", filesize);
205        } else if (fread(filedata, filesize, 1, fp) != 1) {
206           log_printf("-> fread failed (%d bytes)!\n", filesize);
207        } else {
208           log_printf("-> read ok. size=%d, crc32=%08X\n", filesize, crc32_le(0, filedata, filesize));
209        }
210        fclose(fp);
211     } 
212     */
213     else {
214        log_printf("-> fopen failed!\n");
215     }
216  
217     // Now try and determine the filetype we have opened
218     if (!filedata || filesize < 16) {
219        mFileType = HANDY_FILETYPE_ILLEGAL;
220        mCart = new CCart(0, 0);
221        mRam = new CRam(0, 0);
222     } else if (!memcmp(filedata + 6, "BS93", 4)) {
223        mFileType = HANDY_FILETYPE_HOMEBREW;
224        mCart = new CCart(0, 0);
225        mRam = new CRam(filedata, filesize);
226     } else {
227        mFileType = memcmp(filedata, "LYNX", 4) ? HANDY_FILETYPE_RAW : HANDY_FILETYPE_LNX;
228        mCart = new CCart(filedata, filesize);
229        mRam = new CRam(0, 0);
230  
231        // Setup BIOS
232        memset(mBiosRom, 0x88, sizeof(mBiosRom));
233        mBiosRom[0x00] = 0x8d;
234        mBiosRom[0x01] = 0x97;
235        mBiosRom[0x02] = 0xfd;
236        mBiosRom[0x03] = 0x60; // RTS
237        mBiosRom[0x19] = 0x8d;
238        mBiosRom[0x20] = 0x97;
239        mBiosRom[0x21] = 0xfd;
240        mBiosRom[0x4A] = 0x8d;
241        mBiosRom[0x4B] = 0x97;
242        mBiosRom[0x4C] = 0xfd;
243        mBiosRom[0x180] = 0x8d;
244        mBiosRom[0x181] = 0x97;
245        mBiosRom[0x182] = 0xfd;
246     }
247  
248     // Vectors
249     mBiosVectors[0] = 0x00;
250     mBiosVectors[1] = 0x30;
251     mBiosVectors[2] = 0x80;
252     mBiosVectors[3] = 0xFF;
253     mBiosVectors[4] = 0x80;
254     mBiosVectors[5] = 0xFF;
255  
256     // Regain some memory before initializing the rest
257     //emu_SFree(filedata);
258  
259     mRamPointer = mRam->GetRamPointer();
260     mMemMapReg = 0x00;
261  
262     mCycleCountBreakpoint = 0xffffffff;
263     mpDebugCallback = NULL;
264     mDebugCallbackObject = 0;
265  
266     mMikie = new CMikie(*this, displayformat, samplerate);
267     mSusie = new CSusie(*this);
268     mCpu = new C65C02(*this);
269     mEEPROM = new CEEPROM(mCart->CartGetEEPROMType());
270  
271     // Now init is complete do a reset, this will cause many things to be reset twice
272     // but what the hell, who cares, I don't.....
273  
274     Reset();
275  }
276  
277  void CSystem::SaveEEPROM(void)
278  {
279     if(mEEPROM!=NULL) mEEPROM->Save();
280  }
281  
282  CSystem::~CSystem()
283  {
284     // Cleanup all our objects
285  
286     if(mEEPROM!=NULL) delete mEEPROM;
287     if(mCart!=NULL) delete mCart;
288     if(mRam!=NULL) delete mRam;
289     if(mCpu!=NULL) delete mCpu;
290     if(mMikie!=NULL) delete mMikie;
291     if(mSusie!=NULL) delete mSusie;
292  }
293  
294  void CSystem::HLE_BIOS_FE00(void)
295  {
296      // Select Block in A
297      C6502_REGS regs;
298      mCpu->GetRegs(regs);
299      mCart->SetShifterValue(regs.A);
300      // we just put an RTS behind in fake ROM!
301  }
302  
303  void CSystem::HLE_BIOS_FE19(void)
304  {
305     // (not) initial jump from reset vector
306     // Clear full 64k memory!
307     memset(mRamPointer, 0x00, RAM_SIZE);
308  
309     // Set Load adresse to $200 ($05,$06)
310     Poke_CPU(0x0005,0x00);
311     Poke_CPU(0x0006,0x02);
312     // Call to $FE00
313     mCart->SetShifterValue(0);
314     // Fallthrough $FE4A
315     HLE_BIOS_FE4A();
316  }
317  
318  void CSystem::HLE_BIOS_FE4A(void)
319  {
320     UWORD addr=PeekW_CPU(0x0005);
321  
322     // Load from Cart (loader blocks)
323     unsigned char buff[256];// maximum 5 blocks
324     unsigned char res[256];
325  
326     buff[0]=mCart->Peek0();
327     int blockcount = 0x100 -  buff[0];
328  
329     for (int i = 1; i < 1+51*blockcount; ++i) { // first encrypted loader
330        buff[i] = mCart->Peek0();
331     }
332  
333     lynx_decrypt(res, buff, 51);
334  
335     for (int i = 0; i < 50*blockcount; ++i) {
336        Poke_CPU(addr++, res[i]);
337     }
338  
339     // Load Block(s), decode to ($05,$06)
340     // jmp $200
341  
342     C6502_REGS regs;
343     mCpu->GetRegs(regs);
344     regs.PC=0x0200;
345     mCpu->SetRegs(regs);
346  }
347  
348  void CSystem::HLE_BIOS_FF80(void)
349  {
350      // initial jump from reset vector ... calls FE19
351      HLE_BIOS_FE19();
352  }
353  
354  void CSystem::Reset(void)
355  {
356     gSystemCycleCount=0;
357     gNextTimerEvent=0;
358     gCPUBootAddress=0;
359     gBreakpointHit=FALSE;
360     gSingleStepMode=FALSE;
361     gSingleStepModeSprites=FALSE;
362     gSystemIRQ=FALSE;
363     gSystemNMI=FALSE;
364     gSystemCPUSleep=FALSE;
365     gSystemHalt=FALSE;
366  
367     gThrottleLastTimerCount=0;
368     gThrottleNextCycleCheckpoint=0;
369  
370     gTimerCount=0;
371  
372     gAudioBufferPointer=0;
373     gAudioLastUpdateCycle=0;
374  
375  #ifdef _LYNXDBG
376     gSystemHalt=TRUE;
377  #endif
378  
379     mCart->Reset();
380     mEEPROM->Reset();
381     mRam->Reset();
382     mMikie->Reset();
383     mSusie->Reset();
384     mCpu->Reset();
385  
386     // Homebrew hashup
387     if(mFileType==HANDY_FILETYPE_HOMEBREW) {
388        mMikie->PresetForHomebrew();
389        C6502_REGS regs;
390        mCpu->GetRegs(regs);
391        regs.PC=(UWORD)gCPUBootAddress;
392        mCpu->SetRegs(regs);
393     }
394  }
395  
396  bool CSystem::ContextSave(LSS_FILE *fp)
397  {
398     bool status=1;
399  
400     // fp->index = 0;
401     if(!lss_printf(fp, LSS_VERSION)) status=0;
402  
403     // Save ROM CRC
404     ULONG checksum=mCart->CRC32();
405     if(!lss_write(&checksum,sizeof(ULONG),1,fp)) status=0;
406  
407     if(!lss_printf(fp, "CSystem::ContextSave")) status=0;
408  
409     if(!lss_write(&mCycleCountBreakpoint,sizeof(ULONG),1,fp)) status=0;
410     if(!lss_write(&gSystemCycleCount,sizeof(ULONG),1,fp)) status=0;
411     if(!lss_write(&gNextTimerEvent,sizeof(ULONG),1,fp)) status=0;
412     if(!lss_write(&gCPUWakeupTime,sizeof(ULONG),1,fp)) status=0;
413     if(!lss_write(&gCPUBootAddress,sizeof(ULONG),1,fp)) status=0;
414     if(!lss_write(&gIRQEntryCycle,sizeof(ULONG),1,fp)) status=0;
415     if(!lss_write(&gBreakpointHit,sizeof(ULONG),1,fp)) status=0;
416     if(!lss_write(&gSingleStepMode,sizeof(ULONG),1,fp)) status=0;
417     if(!lss_write(&gSystemIRQ,sizeof(ULONG),1,fp)) status=0;
418     if(!lss_write(&gSystemNMI,sizeof(ULONG),1,fp)) status=0;
419     if(!lss_write(&gSystemCPUSleep,sizeof(ULONG),1,fp)) status=0;
420     if(!lss_write(&gSystemCPUSleep_Saved,sizeof(ULONG),1,fp)) status=0;
421     if(!lss_write(&gSystemHalt,sizeof(ULONG),1,fp)) status=0;
422     if(!lss_write(&gThrottleMaxPercentage,sizeof(ULONG),1,fp)) status=0;
423     if(!lss_write(&gThrottleLastTimerCount,sizeof(ULONG),1,fp)) status=0;
424     if(!lss_write(&gThrottleNextCycleCheckpoint,sizeof(ULONG),1,fp)) status=0;
425  
426     if(!lss_write(&gTimerCount,sizeof(ULONG),1,fp)) status=0;
427  
428     if(!lss_write(&gAudioLastUpdateCycle,sizeof(ULONG),1,fp)) status=0;
429  
430     if(!lss_write(&mMemMapReg,sizeof(UBYTE),1,fp)) status=0;
431  
432     // Save other device contexts
433     if(!mCart->ContextSave(fp)) status=0;
434     if(!mRam->ContextSave(fp)) status=0;
435     if(!mMikie->ContextSave(fp)) status=0;
436     if(!mSusie->ContextSave(fp)) status=0;
437     if(!mCpu->ContextSave(fp)) status=0;
438     if(!mEEPROM->ContextSave(fp)) status=0;
439  
440     return status;
441  }
442  
443  bool CSystem::ContextLoad(LSS_FILE *fp)
444  {
445     bool status=1;
446  
447     // fp->index=0;
448  
449     char teststr[32];
450     // Check identifier
451     if(!lss_read(teststr,sizeof(char),4,fp)) status=0;
452     teststr[4]=0;
453  
454     if(strcmp(teststr,LSS_VERSION)==0) {
455        ULONG checksum;
456        // Read CRC32 and check against the CART for a match
457        lss_read(&checksum,sizeof(ULONG),1,fp);
458        if(mCart->CRC32()!=checksum) {
459           log_printf("CSystem::ContextLoad() LSS Snapshot CRC does not match the loaded cartridge image...\n");
460           // return 0;
461        }
462  
463        // Check our block header
464        if(!lss_read(teststr,sizeof(char),20,fp)) status=0;
465        teststr[20]=0;
466        if(strcmp(teststr,"CSystem::ContextSave")!=0) status=0;
467  
468        if(!lss_read(&mCycleCountBreakpoint,sizeof(ULONG),1,fp)) status=0;
469        if(!lss_read(&gSystemCycleCount,sizeof(ULONG),1,fp)) status=0;
470        if(!lss_read(&gNextTimerEvent,sizeof(ULONG),1,fp)) status=0;
471        if(!lss_read(&gCPUWakeupTime,sizeof(ULONG),1,fp)) status=0;
472        if(!lss_read(&gCPUBootAddress,sizeof(ULONG),1,fp)) status=0;
473        if(!lss_read(&gIRQEntryCycle,sizeof(ULONG),1,fp)) status=0;
474        if(!lss_read(&gBreakpointHit,sizeof(ULONG),1,fp)) status=0;
475        if(!lss_read(&gSingleStepMode,sizeof(ULONG),1,fp)) status=0;
476        if(!lss_read(&gSystemIRQ,sizeof(ULONG),1,fp)) status=0;
477        if(!lss_read(&gSystemNMI,sizeof(ULONG),1,fp)) status=0;
478        if(!lss_read(&gSystemCPUSleep,sizeof(ULONG),1,fp)) status=0;
479        if(!lss_read(&gSystemCPUSleep_Saved,sizeof(ULONG),1,fp)) status=0;
480        if(!lss_read(&gSystemHalt,sizeof(ULONG),1,fp)) status=0;
481        if(!lss_read(&gThrottleMaxPercentage,sizeof(ULONG),1,fp)) status=0;
482        if(!lss_read(&gThrottleLastTimerCount,sizeof(ULONG),1,fp)) status=0;
483        if(!lss_read(&gThrottleNextCycleCheckpoint,sizeof(ULONG),1,fp)) status=0;
484  
485        if(!lss_read(&gTimerCount,sizeof(ULONG),1,fp)) status=0;
486  
487        if(!lss_read(&gAudioLastUpdateCycle,sizeof(ULONG),1,fp)) status=0;
488  
489        if(!lss_read(&mMemMapReg,sizeof(UBYTE),1,fp)) status=0;
490  
491        if(!mCart->ContextLoad(fp)) status=0;
492        if(!mRam->ContextLoad(fp)) status=0;
493        if(!mMikie->ContextLoad(fp)) status=0;
494        if(!mSusie->ContextLoad(fp)) status=0;
495        if(!mCpu->ContextLoad(fp)) status=0;
496        if(!mEEPROM->ContextLoad(fp)) status=0;
497  
498        gAudioBufferPointer = 0;
499     } else {
500        log_printf("CSystem::ContextLoad() Not a recognised LSS file!\n");
501     }
502  
503     return status;
504  }
505  
506  #ifdef _LYNXDBG
507  
508  void CSystem::DebugTrace(int address)
509  {
510     char message[1024+1];
511     int count=0;
512  
513     log_printf(message,"%08x - DebugTrace(): ",gSystemCycleCount);
514     count=strlen(message);
515  
516     if(address) {
517        if(address==0xffff) {
518           C6502_REGS regs;
519           char linetext[1024];
520           // Register dump
521           mCpu->GetRegs(regs);
522           log_printf(linetext,"PC=$%04x SP=$%02x PS=0x%02x A=0x%02x X=0x%02x Y=0x%02x",regs.PC,regs.SP, regs.PS,regs.A,regs.X,regs.Y);
523           strcat(message,linetext);
524           count=strlen(message);
525        } else {
526           // The RAM address contents should be dumped to an open debug file in this function
527           do {
528              message[count++]=Peek_RAM(address);
529           } while(count<1024 && Peek_RAM(address++)!=0);
530        }
531     } else {
532        strcat(message,"CPU Breakpoint");
533        count=strlen(message);
534     }
535     message[count]=0;
536  
537     // Callback to dump the message
538     if(mpDebugCallback) {
539        (*mpDebugCallback)(mDebugCallbackObject,message);
540     }
541  }
542  
543  void CSystem::DebugSetCallback(void (*function)(ULONG objref,char *message),ULONG objref)
544  {
545     mDebugCallbackObject=objref;
546     mpDebugCallback=function;
547  }
548  
549  #endif