Esempio n. 1
0
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;
}
Esempio n. 2
0
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)
        }
    }
}
Esempio n. 3
0
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;
}