- Define and export VDDSimulate16 and host_simulate.
- Move the big emulation loop from ntvdm.c to clock.c, and the console input pump thread from ps2.c to ntvdm.c.
  Indeed:
  * Moving the emulation loop out of the main initialization function will be helpful if one wants to modify how emulation is done,
  * The console input pump thread deals also with console UI bits that have nothing to do with keyboard/mouse/ps-2. Instead, the pump thread will dispatch keyboard and mouse events to the ps/2 controller.
- Implement a custom menu in the console's system menu to be able to parametrize ROS VDM (work-in-progress); at the moment only a menu item to show/hide mouse pointer, and another one allowing us to quit properly the VDM are implemented. The menu code was taken from the GUI frontend in winsrv.dll. Only english and french translations available at the moment.

svn path=/branches/ntvdm/; revision=61902
This commit is contained in:
Hermès Bélusca-Maïto 2014-02-01 16:32:20 +00:00
parent 80b0d263d2
commit 105aff1c51
14 changed files with 618 additions and 282 deletions

View file

@ -32,6 +32,10 @@ extern "C" {
* VDM Control
*/
VOID
WINAPI
VDDSimulate16(VOID);
VOID
WINAPI
VDDTerminateVDM(VOID);

View file

@ -19,6 +19,7 @@ list(APPEND SOURCE
dos/dos32krnl/dos.c
dos/dem.c
bop.c
clock.c
emulator.c
int32.c
io.c

173
subsystems/ntvdm/clock.c Normal file
View file

@ -0,0 +1,173 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: clock.c
* PURPOSE: Clock for VDM
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
// #include "clock.h"
#include "hardware/cmos.h"
#include "hardware/ps2.h"
#include "hardware/timer.h"
#include "hardware/vga.h"
/* DEFINES ********************************************************************/
/*
* Activate IPS_DISPLAY if you want to display the
* number of instructions per second, as well as
* the computed number of ticks for the PIT.
*/
// #define IPS_DISPLAY
/*
* Activate WORKING_TIMER when the PIT timing problem is fixed.
*/
// #define WORKING_TIMER
/* Processor speed */
#define STEPS_PER_CYCLE 256
#define KBD_INT_CYCLES 16
/* VARIABLES ******************************************************************/
LARGE_INTEGER StartPerfCount, Frequency;
LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
LONGLONG TimerTicks;
DWORD StartTickCount, CurrentTickCount;
DWORD LastClockUpdate;
DWORD LastVerticalRefresh;
INT KeyboardIntCounter = 0;
#ifdef IPS_DISPLAY
DWORD LastCyclePrintout;
DWORD Cycles = 0;
#endif
/* PUBLIC FUNCTIONS ***********************************************************/
VOID ClockUpdate(VOID)
{
UINT i;
#ifdef WORKING_TIMER
DWORD PitResolution = PitGetResolution();
#endif
DWORD RtcFrequency = RtcGetTicksPerSecond();
/* Get the current number of ticks */
CurrentTickCount = GetTickCount();
#ifdef WORKING_TIMER
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
{
/* Calculate the approximate performance counter value instead */
Counter.QuadPart = StartPerfCount.QuadPart
+ (CurrentTickCount - StartTickCount)
* (Frequency.QuadPart / 1000);
}
else
#endif
{
/* Get the current performance counter value */
QueryPerformanceCounter(&Counter);
}
/* Get the number of PIT ticks that have passed */
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
/* Update the PIT */
if (TimerTicks > 0)
{
PitClock(TimerTicks);
LastTimerTick = Counter;
}
/* Check for RTC update */
if ((CurrentTickCount - LastClockUpdate) >= 1000)
{
RtcTimeUpdate();
LastClockUpdate = CurrentTickCount;
}
/* Check for RTC periodic tick */
if ((Counter.QuadPart - LastRtcTick.QuadPart)
>= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
{
RtcPeriodicTick();
LastRtcTick = Counter;
}
/* Check for vertical retrace */
if ((CurrentTickCount - LastVerticalRefresh) >= 15)
{
VgaRefreshDisplay();
LastVerticalRefresh = CurrentTickCount;
}
if (++KeyboardIntCounter == KBD_INT_CYCLES)
{
GenerateKeyboardInterrupts();
KeyboardIntCounter = 0;
}
/* Horizontal retrace occurs as fast as possible */
VgaHorizontalRetrace();
/* Continue CPU emulation */
// EmulatorSimulate();
for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
{
EmulatorStep();
#ifdef IPS_DISPLAY
Cycles++;
#endif
}
#ifdef IPS_DISPLAY
if ((CurrentTickCount - LastCyclePrintout) >= 1000)
{
DPRINT1("NTVDM: %lu Instructions Per Second; TimerTicks = %I64d\n", Cycles, TimerTicks);
LastCyclePrintout = CurrentTickCount;
Cycles = 0;
}
#endif
}
BOOLEAN ClockInitialize(VOID)
{
/* Initialize the performance counter (needed for hardware timers) */
if (!QueryPerformanceFrequency(&Frequency))
{
wprintf(L"FATAL: Performance counter not available\n");
return FALSE;
}
/* Find the starting performance and tick count */
StartTickCount = GetTickCount();
QueryPerformanceCounter(&StartPerfCount);
/* Set the different last counts to the starting count */
LastClockUpdate = LastVerticalRefresh =
#ifdef IPS_DISPLAY
LastCyclePrintout =
#endif
StartTickCount;
/* Set the last timer ticks to the current time */
LastTimerTick = LastRtcTick = StartPerfCount;
return TRUE;
}

20
subsystems/ntvdm/clock.h Normal file
View file

@ -0,0 +1,20 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: clock.h
* PURPOSE: Clock for VDM
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
#ifndef _CLOCK_H_
#define _CLOCK_H_
/* FUNCTIONS ******************************************************************/
VOID ClockUpdate(VOID);
BOOLEAN ClockInitialize(VOID);
#endif // _CLOCK_H_
/* EOF */

View file

@ -12,6 +12,7 @@
#include "emulator.h"
#include "clock.h"
#include "bios/bios.h"
#include "hardware/cmos.h"
#include "hardware/pic.h"
@ -24,15 +25,19 @@
#include "vddsup.h"
#include "io.h"
#include <isvbop.h>
/* PRIVATE VARIABLES **********************************************************/
FAST486_STATE EmulatorContext;
LPVOID BaseAddress = NULL;
BOOLEAN VdmRunning = TRUE;
static BOOLEAN A20Line = FALSE;
static BOOLEAN A20Line = FALSE;
static BYTE Port61hState = 0x00;
static HANDLE InputThread = NULL;
LPCWSTR ExceptionName[] =
{
L"Division By Zero",
@ -120,12 +125,93 @@ UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
return PicGetInterrupt();
}
VOID WINAPI EmulatorDebugBreak(LPWORD Stack)
VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
{
WORD CodeSegment, InstructionPointer;
PBYTE Opcode;
ASSERT(ExceptionNumber < 8);
/* Get the CS:IP */
InstructionPointer = Stack[STACK_IP];
CodeSegment = Stack[STACK_CS];
Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
/* Display a message to the user */
DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
ExceptionName[ExceptionNumber],
CodeSegment,
InstructionPointer,
Opcode[0],
Opcode[1],
Opcode[2],
Opcode[3],
Opcode[4],
Opcode[5],
Opcode[6],
Opcode[7],
Opcode[8],
Opcode[9]);
/* Stop the VDM */
VdmRunning = FALSE;
return;
}
// FIXME: This function assumes 16-bit mode!!!
VOID EmulatorExecute(WORD Segment, WORD Offset)
{
/* Tell Fast486 to move the instruction pointer */
Fast486ExecuteAt(&EmulatorContext, Segment, Offset);
}
VOID EmulatorStep(VOID)
{
/* Dump the state for debugging purposes */
// Fast486DumpState(&EmulatorContext);
/* Execute the next instruction */
Fast486StepInto(&EmulatorContext);
}
VOID EmulatorSimulate(VOID)
{
UNIMPLEMENTED;
}
VOID EmulatorUnsimulate(VOID)
{
UNIMPLEMENTED;
}
VOID EmulatorInterrupt(BYTE Number)
{
/* Call the Fast486 API */
Fast486Interrupt(&EmulatorContext, Number);
}
VOID EmulatorInterruptSignal(VOID)
{
/* Call the Fast486 API */
Fast486InterruptSignal(&EmulatorContext);
}
VOID EmulatorSetA20(BOOLEAN Enabled)
{
A20Line = Enabled;
}
VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
{
DPRINT1("NTVDM: BOP_DEBUGGER\n");
DebugBreak();
}
VOID WINAPI EmulatorUnsimulateBop(LPWORD Stack)
{
EmulatorUnsimulate();
}
static BYTE WINAPI Port61hRead(ULONG Port)
{
@ -211,6 +297,8 @@ static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
/* PUBLIC FUNCTIONS ***********************************************************/
DWORD WINAPI PumpConsoleInput(LPVOID Parameter);
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
{
/* Allocate memory for the 16-bit address space */
@ -224,6 +312,13 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
/* Initialize I/O ports */
/* Initialize RAM */
/* Initialize the internal clock */
if (!ClockInitialize())
{
wprintf(L"FATAL: Failed to initialize the clock\n");
return FALSE;
}
/* Initialize the CPU */
Fast486Initialize(&EmulatorContext,
EmulatorReadMemory,
@ -238,6 +333,8 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
/* Enable interrupts */
setIF(1);
/* Initialize DMA */
/* Initialize the PIC, the PIT, the CMOS and the PC Speaker */
PicInitialize();
PitInitialize();
@ -258,12 +355,17 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
/* Set the console input mode */
// SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
/* Start the input thread */
InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
// if (InputThread == NULL) return FALSE;
/* Initialize the VGA */
// if (!VgaInitialize(ConsoleOutput)) return FALSE;
VgaInitialize(ConsoleOutput);
/* Register the DebugBreak BOP */
RegisterBop(BOP_DEBUGGER, EmulatorDebugBreak);
/* Register the emulator BOPs */
RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
RegisterBop(BOP_UNSIMULATE, EmulatorUnsimulateBop);
/* Initialize VDD support */
VDDSupInitialize();
@ -274,6 +376,11 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
VOID EmulatorCleanup(VOID)
{
// VgaCleanup();
/* Close the input thread handle */
if (InputThread != NULL) CloseHandle(InputThread);
InputThread = NULL;
PS2Cleanup();
SpeakerCleanup();
@ -287,75 +394,15 @@ VOID EmulatorCleanup(VOID)
if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
}
VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
VOID
WINAPI
VDDSimulate16(VOID)
{
WORD CodeSegment, InstructionPointer;
PBYTE Opcode;
ASSERT(ExceptionNumber < 8);
/* Get the CS:IP */
InstructionPointer = Stack[STACK_IP];
CodeSegment = Stack[STACK_CS];
Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
/* Display a message to the user */
DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
ExceptionName[ExceptionNumber],
CodeSegment,
InstructionPointer,
Opcode[0],
Opcode[1],
Opcode[2],
Opcode[3],
Opcode[4],
Opcode[5],
Opcode[6],
Opcode[7],
Opcode[8],
Opcode[9]);
/* Stop the VDM */
VdmRunning = FALSE;
return;
EmulatorSimulate();
}
// FIXME: This function assumes 16-bit mode!!!
VOID EmulatorExecute(WORD Segment, WORD Offset)
{
/* Tell Fast486 to move the instruction pointer */
Fast486ExecuteAt(&EmulatorContext, Segment, Offset);
}
VOID EmulatorInterrupt(BYTE Number)
{
/* Call the Fast486 API */
Fast486Interrupt(&EmulatorContext, Number);
}
VOID EmulatorInterruptSignal(VOID)
{
/* Call the Fast486 API */
Fast486InterruptSignal(&EmulatorContext);
}
VOID EmulatorStep(VOID)
{
/* Dump the state for debugging purposes */
// Fast486DumpState(&EmulatorContext);
/* Execute the next instruction */
Fast486StepInto(&EmulatorContext);
}
VOID EmulatorSetA20(BOOLEAN Enabled)
{
A20Line = Enabled;
}
VOID
WINAPI
VDDTerminateVDM(VOID)

View file

@ -25,7 +25,6 @@ static BYTE KeyboardData = 0, KeyboardResponse = 0;
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
static HANDLE QueueMutex = NULL;
static HANDLE InputThread = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
@ -281,71 +280,47 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
}
}
static DWORD WINAPI InputThreadProc(LPVOID Parameter)
{
INT i;
HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord;
DWORD Count;
while (VdmRunning)
{
/* Wait for an input record */
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
{
DWORD LastError = GetLastError();
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
return LastError;
}
ASSERT(Count != 0);
/* Check the event type */
switch (InputRecord.EventType)
{
case KEY_EVENT:
{
BYTE ScanCode = (BYTE)InputRecord.Event.KeyEvent.wVirtualScanCode;
/* If this is a key release, set the highest bit in the scan code */
if (!InputRecord.Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
/* Push the scan code onto the keyboard queue */
for (i = 0; i < InputRecord.Event.KeyEvent.wRepeatCount; i++)
{
KeyboardQueuePush(ScanCode);
}
break;
}
case MOUSE_EVENT:
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
break;
}
default:
{
/* Ignored */
break;
}
}
}
return 0;
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID PS2Dispatch(PINPUT_RECORD InputRecord)
{
/* Check the event type */
switch (InputRecord->EventType)
{
case KEY_EVENT:
{
WORD i;
BYTE ScanCode = (BYTE)InputRecord->Event.KeyEvent.wVirtualScanCode;
/* If this is a key release, set the highest bit in the scan code */
if (!InputRecord->Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
/* Push the scan code onto the keyboard queue */
for (i = 0; i < InputRecord->Event.KeyEvent.wRepeatCount; i++)
{
KeyboardQueuePush(ScanCode);
}
break;
}
case MOUSE_EVENT:
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
break;
}
/* We ignore all the rest */
default:
break;
}
}
VOID GenerateKeyboardInterrupts(VOID)
{
if (KeyboardQueuePop(&KeyboardData))
{
/* IRQ 1 */
PicInterruptRequest(1);
}
/* Generate an IRQ 1 if there is a key ready in the queue */
if (KeyboardQueuePop(&KeyboardData)) PicInterruptRequest(1);
}
BOOLEAN PS2Initialize(HANDLE ConsoleInput)
@ -353,11 +328,6 @@ BOOLEAN PS2Initialize(HANDLE ConsoleInput)
/* Create the mutex */
QueueMutex = CreateMutex(NULL, FALSE, NULL);
/* Start the input thread */
InputThread = CreateThread(NULL, 0, &InputThreadProc, ConsoleInput, 0, NULL);
// if (InputThread == NULL) return FALSE;
/* Register the I/O Ports */
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
@ -367,10 +337,6 @@ BOOLEAN PS2Initialize(HANDLE ConsoleInput)
VOID PS2Cleanup(VOID)
{
/* Close the input thread handle */
if (InputThread != NULL) CloseHandle(InputThread);
InputThread = NULL;
CloseHandle(QueueMutex);
}

View file

@ -24,6 +24,7 @@
/* FUNCTIONS ******************************************************************/
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
VOID GenerateKeyboardInterrupts(VOID);
BOOLEAN PS2Initialize(HANDLE ConsoleInput);

View file

@ -0,0 +1,13 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
BEGIN
IDS_HIDE_MOUSE, "&Hide Mouse Pointer"
IDS_SHOW_MOUSE, "&Display Mouse Pointer"
IDS_VDM_MENU , "ReactOS &VDM"
END
STRINGTABLE
BEGIN
IDS_VDM_QUIT, "&Quit the ReactOS VDM"
END

View file

@ -0,0 +1,13 @@
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_HIDE_MOUSE, "Mas&quer le pointeur de la souris"
IDS_SHOW_MOUSE, "&Afficher le pointeur de la souris"
IDS_VDM_MENU , "ReactOS &VDM"
END
STRINGTABLE
BEGIN
IDS_VDM_QUIT, "&Quitter la ReactOS VDM"
END

View file

@ -13,12 +13,13 @@
#include "ntvdm.h"
#include "emulator.h"
#include "clock.h"
#include "hardware/ps2.h"
#include "hardware/vga.h"
#include "bios/bios.h"
#include "dos/dem.h"
#include "hardware/cmos.h"
#include "hardware/ps2.h"
#include "hardware/timer.h"
#include "hardware/vga.h"
#include "resource.h"
/*
* Activate this line if you want to be able to test NTVDM with:
@ -26,19 +27,7 @@
*/
#define TESTING
/*
* Activate IPS_DISPLAY if you want to display the
* number of instructions per second, as well as
* the computed number of ticks for the PIT.
*/
// #define IPS_DISPLAY
/*
* Activate WORKING_TIMER when the PIT timing problem is fixed.
*/
// #define WORKING_TIMER
/* PUBLIC VARIABLES ***********************************************************/
/* VARIABLES ******************************************************************/
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
@ -46,6 +35,134 @@ static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE;
/*
* Those menu helpers were taken from the GUI frontend in winsrv.dll
*/
typedef struct _VDM_MENUITEM
{
UINT uID;
const struct _VDM_MENUITEM *SubMenu;
WORD wCmdID;
} VDM_MENUITEM, *PVDM_MENUITEM;
static const VDM_MENUITEM VdmMenuItems[] =
{
{ IDS_VDM_QUIT, NULL, ID_VDM_QUIT },
{ 0, NULL, 0 } /* End of list */
};
static const VDM_MENUITEM VdmMainMenuItems[] =
{
{ -1, NULL, 0 }, /* Separator */
{ IDS_HIDE_MOUSE, NULL, ID_SHOWHIDE_MOUSE }, /* Hide mouse; can be renamed to Show mouse */
{ IDS_VDM_MENU , VdmMenuItems, 0 }, /* ReactOS VDM Menu */
{ 0, NULL, 0 } /* End of list */
};
static VOID
AppendMenuItems(HMENU hMenu,
const VDM_MENUITEM *Items)
{
UINT i = 0;
WCHAR szMenuString[255];
HMENU hSubMenu;
do
{
if (Items[i].uID != (UINT)-1)
{
if (LoadStringW(GetModuleHandle(NULL),
Items[i].uID,
szMenuString,
sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
{
if (Items[i].SubMenu != NULL)
{
hSubMenu = CreatePopupMenu();
if (hSubMenu != NULL)
{
AppendMenuItems(hSubMenu, Items[i].SubMenu);
if (!AppendMenuW(hMenu,
MF_STRING | MF_POPUP,
(UINT_PTR)hSubMenu,
szMenuString))
{
DestroyMenu(hSubMenu);
}
}
}
else
{
AppendMenuW(hMenu,
MF_STRING,
Items[i].wCmdID,
szMenuString);
}
}
}
else
{
AppendMenuW(hMenu,
MF_SEPARATOR,
0,
NULL);
}
i++;
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
}
static VOID
CreateVdmMenu(HANDLE ConOutHandle)
{
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
ID_SHOWHIDE_MOUSE,
ID_VDM_QUIT);
if (hConsoleMenu != NULL)
{
VdmMenuPos = GetMenuItemCount(hConsoleMenu);
AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
DrawMenuBar(GetConsoleWindow());
}
}
static VOID
DestroyVdmMenu(VOID)
{
UINT i = 0;
const VDM_MENUITEM *Items = VdmMainMenuItems;
do
{
DeleteMenu(hConsoleMenu, VdmMenuPos, MF_BYPOSITION);
i++;
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
DrawMenuBar(GetConsoleWindow());
}
static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
{
WCHAR szMenuString[255] = L"";
ShowConsoleCursor(ConOutHandle, ShowPtr);
if (LoadStringW(GetModuleHandle(NULL),
(!ShowPtr ? IDS_SHOW_MOUSE : IDS_HIDE_MOUSE),
szMenuString,
sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
{
ModifyMenu(hConsoleMenu, ID_SHOWHIDE_MOUSE,
MF_BYCOMMAND, ID_SHOWHIDE_MOUSE, szMenuString);
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID DisplayMessage(LPCWSTR Format, ...)
@ -80,6 +197,74 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
return TRUE;
}
VOID ConsoleInitUI(VOID)
{
CreateVdmMenu(ConsoleOutput);
}
VOID ConsoleCleanupUI(VOID)
{
/* Display again properly the mouse pointer */
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
DestroyVdmMenu();
}
DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
{
HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord;
DWORD Count;
while (VdmRunning)
{
/* Wait for an input record */
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
{
DWORD LastError = GetLastError();
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
return LastError;
}
ASSERT(Count != 0);
/* Check the event type */
switch (InputRecord.EventType)
{
case KEY_EVENT:
case MOUSE_EVENT:
/* Send it to the PS/2 controller */
PS2Dispatch(&InputRecord);
break;
case MENU_EVENT:
{
switch (InputRecord.Event.MenuEvent.dwCommandId)
{
case ID_SHOWHIDE_MOUSE:
ShowHideMousePointer(ConsoleOutput, ShowPointer);
ShowPointer = !ShowPointer;
break;
case ID_VDM_QUIT:
VdmRunning = FALSE;
break;
default:
break;
}
break;
}
default:
break;
}
}
return 0;
}
BOOL ConsoleInit(VOID)
{
/* Set the handler routine */
@ -134,6 +319,9 @@ BOOL ConsoleInit(VOID)
return FALSE;
}
/* Initialize the UI */
ConsoleInitUI();
return TRUE;
}
@ -166,6 +354,9 @@ VOID ConsoleCleanup(VOID)
SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
/* Cleanup the UI */
ConsoleCleanupUI();
/* Close the console handles */
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
@ -173,19 +364,7 @@ VOID ConsoleCleanup(VOID)
INT wmain(INT argc, WCHAR *argv[])
{
INT i;
CHAR CommandLine[DOS_CMDLINE_LENGTH];
LARGE_INTEGER StartPerfCount;
LARGE_INTEGER Frequency, LastTimerTick, LastRtcTick, Counter;
LONGLONG TimerTicks;
DWORD StartTickCount, CurrentTickCount;
DWORD LastClockUpdate;
DWORD LastVerticalRefresh;
#ifdef IPS_DISPLAY
DWORD LastCyclePrintout;
DWORD Cycles = 0;
#endif
INT KeyboardIntCounter = 0;
#ifndef TESTING
UNREFERENCED_PARAMETER(argc);
@ -222,13 +401,6 @@ INT wmain(INT argc, WCHAR *argv[])
goto Cleanup;
}
/* Initialize the performance counter (needed for hardware timers) */
if (!QueryPerformanceFrequency(&Frequency))
{
wprintf(L"FATAL: Performance counter not available\n");
goto Cleanup;
}
/* Initialize the system BIOS */
if (!BiosInitialize(ConsoleInput, ConsoleOutput))
{
@ -250,107 +422,8 @@ INT wmain(INT argc, WCHAR *argv[])
goto Cleanup;
}
/* Find the starting performance and tick count */
StartTickCount = GetTickCount();
QueryPerformanceCounter(&StartPerfCount);
/* Set the different last counts to the starting count */
LastClockUpdate = LastVerticalRefresh =
#ifdef IPS_DISPLAY
LastCyclePrintout =
#endif
StartTickCount;
/* Set the last timer ticks to the current time */
LastTimerTick = LastRtcTick = StartPerfCount;
/* Main loop */
while (VdmRunning)
{
#ifdef WORKING_TIMER
DWORD PitResolution = PitGetResolution();
#endif
DWORD RtcFrequency = RtcGetTicksPerSecond();
/* Get the current number of ticks */
CurrentTickCount = GetTickCount();
#ifdef WORKING_TIMER
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
{
/* Calculate the approximate performance counter value instead */
Counter.QuadPart = StartPerfCount.QuadPart
+ (CurrentTickCount - StartTickCount)
* (Frequency.QuadPart / 1000);
}
else
#endif
{
/* Get the current performance counter value */
QueryPerformanceCounter(&Counter);
}
/* Get the number of PIT ticks that have passed */
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
/* Update the PIT */
if (TimerTicks > 0)
{
PitClock(TimerTicks);
LastTimerTick = Counter;
}
/* Check for RTC update */
if ((CurrentTickCount - LastClockUpdate) >= 1000)
{
RtcTimeUpdate();
LastClockUpdate = CurrentTickCount;
}
/* Check for RTC periodic tick */
if ((Counter.QuadPart - LastRtcTick.QuadPart)
>= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
{
RtcPeriodicTick();
LastRtcTick = Counter;
}
/* Check for vertical retrace */
if ((CurrentTickCount - LastVerticalRefresh) >= 15)
{
VgaRefreshDisplay();
LastVerticalRefresh = CurrentTickCount;
}
KeyboardIntCounter++;
if (KeyboardIntCounter == KBD_INT_CYCLES)
{
GenerateKeyboardInterrupts();
KeyboardIntCounter = 0;
}
/* Horizontal retrace occurs as fast as possible */
VgaHorizontalRetrace();
/* Continue CPU emulation */
for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++)
{
EmulatorStep();
#ifdef IPS_DISPLAY
Cycles++;
#endif
}
#ifdef IPS_DISPLAY
if ((CurrentTickCount - LastCyclePrintout) >= 1000)
{
DPRINT1("NTVDM: %lu Instructions Per Second; TimerTicks = %I64d\n", Cycles, TimerTicks);
LastCyclePrintout = CurrentTickCount;
Cycles = 0;
}
#endif
}
while (VdmRunning) ClockUpdate();
/* Perform another screen refresh */
VgaRefreshDisplay();

View file

@ -25,16 +25,11 @@
#include <winuser.h>
#include <vddsvc.h>
// #include "registers.h"
#include <debug.h>
/* DEFINES ********************************************************************/
/* Processor speed */
#define STEPS_PER_CYCLE 256
#define KBD_INT_CYCLES 16
/* FUNCTIONS ******************************************************************/
VOID DisplayMessage(LPCWSTR Format, ...);

View file

@ -1,5 +1,6 @@
#include <windef.h>
#include <winuser.h>
// #include <commctrl.h>
#include "resource.h"
@ -14,3 +15,10 @@ IDI_APPICON ICON "res/ntvdm.ico"
/* UTF-8 */
#pragma code_page(65001)
#ifdef LANGUAGE_EN_US
#include "lang/en-US.rc"
#endif
#ifdef LANGUAGE_FR_FR
#include "lang/fr-FR.rc"
#endif

View file

@ -1,3 +1,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NTVDM Registers exports ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ stdcall getAF()
@ stdcall getAH()
@ stdcall getAL()
@ -89,6 +93,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NTVDM CCPU MIPS exports ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ stdcall c_getAF() getAF
@ stdcall c_getAH() getAH
@ stdcall c_getAL() getAL
@ -174,6 +179,9 @@
@ stdcall c_setZF(long) setZF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NTVDM DOS-32 Emulation exports ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ stdcall demClientErrorEx(long long long)
@ stdcall demFileDelete(ptr)
@ -192,6 +200,9 @@
;@ stdcall demWOWLFNInit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NTVDM Miscellaneous exports ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ stdcall MGetVdmPointer(long long long)
@ stdcall Sim32pGetVDMPointer(long long)
@ -204,4 +215,6 @@
@ stdcall VDDInstallIOHook(long long ptr ptr)
@ stdcall VDDDeInstallIOHook(long long ptr)
@ stdcall VDDSimulate16()
@ stdcall host_simulate() VDDSimulate16
@ stdcall VDDTerminateVDM()

View file

@ -1,5 +1,14 @@
#pragma once
#define ID_SHOWHIDE_MOUSE 1000
#define ID_VDM_QUIT 1001
#define IDS_HIDE_MOUSE 100
#define IDS_SHOW_MOUSE 101
#define IDS_VDM_MENU 102
#define IDS_VDM_QUIT 200
#define IDI_APPICON 1
/* EOF */