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