BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) { /* Allocate memory for the 16-bit address space */ BaseAddress = HeapAlloc(GetProcessHeap(), /*HEAP_ZERO_MEMORY*/ 0, MAX_ADDRESS); if (BaseAddress == NULL) { wprintf(L"FATAL: Failed to allocate VDM memory.\n"); return FALSE; } /* * For diagnostics purposes, we fill the memory with INT 0x03 codes * so that if a program wants to execute random code in memory, we can * retrieve the exact CS:IP where the problem happens. */ RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC); /* Initialize I/O ports */ /* Initialize RAM */ /* Initialize the CPU */ /* Initialize the internal clock */ if (!ClockInitialize()) { wprintf(L"FATAL: Failed to initialize the clock\n"); return FALSE; } /* Initialize the CPU */ CpuInitialize(); // Fast486Initialize(&EmulatorContext, // EmulatorReadMemory, // EmulatorWriteMemory, // EmulatorReadIo, // EmulatorWriteIo, // NULL, // EmulatorBiosOperation, // EmulatorIntAcknowledge, // NULL /* TODO: Use a TLB */); /* Initialize DMA */ /* Initialize the PIC, the PIT, the CMOS and the PC Speaker */ PicInitialize(); PitInitialize(); CmosInitialize(); SpeakerInitialize(); /* Set output functions */ PitSetOutFunction(0, NULL, PitChan0Out); PitSetOutFunction(1, NULL, PitChan1Out); PitSetOutFunction(2, NULL, PitChan2Out); /* Register the I/O Ports */ RegisterIoPort(CONTROL_SYSTEM_PORT61H, Port61hRead, Port61hWrite); /* Set the console input mode */ // FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions // upon console window events (screen buffer resize, ...). SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */); // SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); /**/EnableExtraHardware(ConsoleInput);/**/ /* Initialize the PS/2 port */ PS2Initialize(); /* Initialize the keyboard and mouse and connect them to their PS/2 ports */ KeyboardInit(0); MouseInit(1); /**************** ATTACH INPUT WITH CONSOLE *****************/ /* Start the input thread */ InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL); if (InputThread == NULL) { DisplayMessage(L"Failed to create the console input thread."); return FALSE; } /************************************************************/ /* Initialize the VGA */ if (!VgaInitialize(ConsoleOutput)) { DisplayMessage(L"Failed to initialize VGA support."); return FALSE; } /* Initialize the software callback system and register the emulator BOPs */ InitializeInt32(); RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop); // RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop); /* Initialize VDD support */ VDDSupInitialize(); return TRUE; }
void EmulatorThread::run() { // Load PC from Reset Vector CpuInitialize(); lcdoffshift0flag = false; //g_stp = 1; // test #ifndef FAKENMI unsigned int nmistart = GetTickCount(); #endif gThreadFlags &= 0xFFFEu; // Remove 0x01 from gThreadFlags (stack related) #ifdef AUTOTEST unsigned totalline = 0; // TODO: long long enablelogging = false; #endif while(fKeeping) { #if 1 const unsigned spdc1016freq = GlobalSetting.SPDC1016Frequency; #endif #ifdef FAMENMI twohznmicycle = spdc1016freq / 2; #endif while (batchcount >= 0 && fKeeping) { #ifdef AUTOTEST totalline++; TryTest(totalline); #endif // AUTOTEST #ifdef LOGASM #ifdef AUTOTEST if (enablelogging) { #endif #ifdef HANDYPSP LogDisassembly(mPC, NULL); #else LogDisassembly(regs.pc, NULL); #endif // HANDYPSP #ifdef AUTOTEST } #endif // AUTOTEST #endif // LOGASM if (matrixupdated) { matrixupdated = false; AppendLog("keypadmatrix updated."); } nmicount++; // MERGEASM // 2Hz NMI // TODO: use batchcount as NMI source #ifdef FAKENMI if (nmicount % 400000 == 0) { nmicount = 0; // MERGEASM //if (twohznmicycle < 0) { // twohznmicycle = spdc1016freq / 2; // reset #else // in CC800 hardware, NMI is generated by 32.768k crystal, but spdc1016 use RC oscillator so cycle/NMI can be mismatched. unsigned int dummynow = GetTickCount(); if (dummynow - nmistart >= 500) { nmistart += 500; #endif //g_nmi = 0; // next CpuExecute will execute two instructions gThreadFlags |= 0x08; // Add NMIFlag } // NMI > IRQ if ((gThreadFlags & 0x08) != 0) { gThreadFlags &= 0xFFF7u; // remove 0x08 NMI Flag // FIXME: NO MORE REVERSE g_nmi = TRUE; // next CpuExecute will execute two instructions qDebug("ggv wanna NMI."); //fprintf(stderr, "ggv wanna NMI.\n"); gDeadlockCounter--; // wrong behavior of wqxsim #ifdef HANDYPSP } else if (((PS() & AF_INTERRUPT) == 0) && ((gThreadFlags & TF_IRQFLAG) != 0)) { #else } else if (((regs.ps & 0x4) == 0) && ((gThreadFlags & 0x10) != 0)) { #endif gThreadFlags &= 0xFFEFu; // remove 0x10 IRQ Flag g_irq = TRUE; // B flag (AF_BREAK) will remove in CpuExecute qDebug("ggv wanna IRQ."); gDeadlockCounter--; // wrong behavior of wqxsim } DWORD CpuTicks = CpuExecute(); totalcycle += CpuTicks; twohznmicycle -= CpuTicks; // add checks for reset, IRQ, NMI, and other pin signals if (lastTicket == 0) { lastTicket = GetTickCount(); } gDeadlockCounter++; if (gDeadlockCounter == 6000) { // overflowed gDeadlockCounter = 0; if ((gThreadFlags & 0x80u) == 0) { // CheckTimerbaseAndEnableIRQnEXIE1 CheckTimebaseAndEnableIRQnEXIE1(); if (timer0started) { // mayDestAddr == 5 in ReadRegister // mayBaseTable have 0x100 elements? //increment = mayBasetable[mayDestAddr]; // mayBaseTable[5] == 3 //t0overflow = (unsigned int)(increment + mayPreviousTimer0Value) < 0xFF; //mayPreviousTimer0Value += increment; //if ( !t0overflow ) //{ // mayPreviousTimer0Value = 0; // Turnoff2HzNMIMaskAddIRQFlag(); //} int increment = 3; prevtimer0value += increment; if (prevtimer0value >= 0xFFu) { prevtimer0value = 0; Turnoff2HzNMIMaskAddIRQFlag(); } } } else { // RESET fixedram0000[io01_int_enable] |= 0x1; // TIMER A INTERRUPT ENABLE fixedram0000[io02_timer0_val] |= 0x1; // [io01+1] Timer0 bit1 = 1 gThreadFlags &= 0xFF7F; // remove 0x80 | 0x10 #ifdef HANDYPSP mPC = *(unsigned short*)&pmemmap[mapE000][0x1FFC]; #else regs.pc = *(unsigned short*)&pmemmap[mapE000][0x1FFC]; #endif } } else { if (timer0started) { // mayDestAddr == 5 in ReadRegister // mayBaseTable have 0x100 elements? int increment = 3; prevtimer0value += increment; if (prevtimer0value >= 0xFFu) { prevtimer0value = 0; Turnoff2HzNMIMaskAddIRQFlag(); } } } //if (timer0started) { // fixedram0000[io02_timer0_val] = fixedram0000[io02_timer0_val] + 1; //} //if (timer1started) { // fixedram0000[io03_timer1_val] = fixedram0000[io03_timer1_val] + 1; //} // TODO: dynamic re-measure if (measured == false && totalcycle % spdc1016freq < 10 && totalcycle > spdc1016freq) { measured = true; #if 0 // fixed rate on device // realworld time = 106 #ifdef HANDYPSP batchlimiter = spdc1016freq / 88; // 12*10=120ms #else batchlimiter = spdc1016freq / 4; #endif batchcount = batchlimiter; #else if (totalcycle < spdc1016freq * 2) { // first loop check! // spdc1016 executed one second in fullspeed virtual timeline unsigned long long realworldtime = GetTickCount() - lastTicket; // should less than 1000ms lastTicket = GetTickCount(); //double virtual100ms = realworldtime / 100.0; qDebug("realworldtime:%llu", realworldtime); fprintf(stderr, "realworldtime:%llu\n", realworldtime); if (realworldtime > 1000) { // TODO: device may slower than simulator // in my test iPad I get 3528/3779/3630 msec to finish one sdpc1016freq loop // we should make screen refresh at least twice per real world second or screen will never been updated // 1000->500 2000->250 4000->125 batchlimiter = 500 * spdc1016freq / realworldtime; if (remeasure) { qDebug("remeasure on batchlimiter: %u", batchlimiter); fprintf(stderr, "remeasure on batchlimiter: %u\n", batchlimiter); measured = false; totalcycle = 0; remeasure--; } batchcount = batchlimiter; } else if (batchlimiter == 0) { // 1000 - realworldtime = overflow time, overflow time / 10 = sleepcount, freq / sleepcount = batchcount //batchlimiter = spdc1016freq / ((1000 - realworldtime) / 10); sleepcount = (1000 - realworldtime) / sleepgap; batchlimiter = spdc1016freq * sleepgap / (1000 - realworldtime); } else { // wrong path? // sleep(0) is less than 10ms, but we'd never go here } batchcount = batchlimiter; } else { // totalcycle > spdc1016freq * 2 // TODO: check once more } #endif // TARGET_IPHONE_SIMULATOR } // measured == false && totalcycle % spdc1016freq < 10 && totalcycle > spdc1016freq if (totalcycle % spdc1016freq > 10 && totalcycle > spdc1016freq) { // FIXME: bug on slow device //measured = false; } if (batchlimiter != 0) { batchcount -= CpuTicks; } //usleep(10); //Sleep(0); } if (memcmp(&fixedram0000[0x9C0], fLCDBuffer, 160*80/8) != 0) { memcpy(fLCDBuffer, &fixedram0000[0x9C0], 160*80/8); qDebug("lcdBufferChanged"); fprintf(stderr, "lcdBufferChanged\n"); emit lcdBufferChanged(new QByteArray((const char*)fLCDBuffer, 160*80/8)); } Sleep(10); // SleepGap. 10ms = 10us if (batchlimiter > 0) { batchcount = batchlimiter; } else { batchcount = spdc1016freq * 2; // dirty fix } } //this->deleteLater(); } void EmulatorThread::StopKeeping() { fKeeping = false; } #ifdef AUTOTEST void EmulatorThread::TryTest( unsigned line ) { // Network if (line == 1024000) { keypadmatrix[1][6] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 1064000) { keypadmatrix[1][6] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Down if (line == 1224000) { keypadmatrix[6][3] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 1264000) { keypadmatrix[6][3] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Enter if (line == 1424000) { keypadmatrix[6][5] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); enablelogging = true; } if (line == 1524000) { keypadmatrix[6][5] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } // Splash if (line == 4724000) { keypadmatrix[6][5] = 1; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } if (line == 4764000) { keypadmatrix[6][5] = 0; CheckLCDOffShift0HotkeyAndEnableWatchDog(); } } #endif void CheckLCDOffShift0HotkeyAndEnableWatchDog() { //// may check hotkey press //if ( gLcdoffShift0Flag ) //{ // if ( keypadmatrix1[6] || keypadmatrix1[7] ) // { // // Line6 Dict Card // // Line7 on/off // EnableWatchDogFlag(); // 0x80 // gLcdoffShift0Flag = 0; // } //} //else //{ // // Set lcdoffshift0flag only when keypadmatrix3 == 0xFB // if ( keypadmatrix1[7] == 0xFBu ) // gLcdoffShift0Flag = 1; //} matrixupdated = true; if (lcdoffshift0flag) { // we don't have invert bit for row6,7 //bool row67down = false; for (int y = 0; y < 2; y++) { for (int x = 0; x < 8; x++) { if (keypadmatrix[y][x] == 1) { //row6,7down = true; EnableWatchDogFlag(); lcdoffshift0flag = false; return; } } } } else { if (keypadmatrix[0][2] == 1) { lcdoffshift0flag = true; // this flag is used for UI? (IO05_ClockControl) } } }
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) { USHORT i; /* Initialize memory */ if (!MemInitialize()) { wprintf(L"Memory initialization failed.\n"); return FALSE; } /* Initialize I/O ports */ /* Initialize RAM */ /* Initialize the CPU */ /* Initialize the internal clock */ if (!ClockInitialize()) { wprintf(L"FATAL: Failed to initialize the clock\n"); EmulatorCleanup(); return FALSE; } /* Initialize the CPU */ CpuInitialize(); /* Initialize DMA */ DmaInitialize(); /* Initialize PIC, PIT, CMOS, PC Speaker and PS/2 */ PicInitialize(); PitInitialize(); PitSetOutFunction(0, NULL, PitChan0Out); PitSetOutFunction(1, NULL, PitChan1Out); PitSetOutFunction(2, NULL, PitChan2Out); CmosInitialize(); SpeakerInitialize(); PpiInitialize(); PS2Initialize(); /* Initialize the keyboard and mouse and connect them to their PS/2 ports */ KeyboardInit(0); MouseInit(1); /**************** ATTACH INPUT WITH CONSOLE *****************/ /* Create the task event */ VdmTaskEvent = CreateEventW(NULL, TRUE, FALSE, NULL); ASSERT(VdmTaskEvent != NULL); /* Start the input thread */ InputThread = CreateThread(NULL, 0, &ConsoleEventThread, ConsoleInput, 0, NULL); if (InputThread == NULL) { wprintf(L"FATAL: Failed to create the console input thread.\n"); EmulatorCleanup(); return FALSE; } ResumeEventThread(); /************************************************************/ /* Initialize the VGA */ if (!VgaInitialize(ConsoleOutput)) { wprintf(L"FATAL: Failed to initialize VGA support.\n"); EmulatorCleanup(); return FALSE; } /* Initialize the disk controller */ if (!DiskCtrlInitialize()) { wprintf(L"FATAL: Failed to completely initialize the disk controller.\n"); EmulatorCleanup(); return FALSE; } /* Mount the available floppy disks */ for (i = 0; i < ARRAYSIZE(GlobalSettings.FloppyDisks); ++i) { if (GlobalSettings.FloppyDisks[i].Length != 0 && GlobalSettings.FloppyDisks[i].Buffer && GlobalSettings.FloppyDisks[i].Buffer != '\0') { if (!MountDisk(FLOPPY_DISK, i, GlobalSettings.FloppyDisks[i].Buffer, FALSE)) { DPRINT1("Failed to mount floppy disk file '%wZ'.\n", &GlobalSettings.FloppyDisks[i]); RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[i]); RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[i], NULL, 0); } } } /* * Mount the available hard disks. Contrary to floppies, failing * mounting a hard disk is considered as an unrecoverable error. */ for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i) { if (GlobalSettings.HardDisks[i].Length != 0 && GlobalSettings.HardDisks[i].Buffer && GlobalSettings.HardDisks[i].Buffer != L'\0') { if (!MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE)) { wprintf(L"FATAL: Failed to mount hard disk file '%wZ'.\n", &GlobalSettings.HardDisks[i]); EmulatorCleanup(); return FALSE; } } } /* Refresh the menu state */ UpdateVdmMenuDisks(); /* Initialize the software callback system and register the emulator BOPs */ InitializeInt32(); RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop); // RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop); /* Initialize VDD support */ VDDSupInitialize(); return TRUE; }