mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[NTVDM]
- 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:
parent
80b0d263d2
commit
105aff1c51
14 changed files with 618 additions and 282 deletions
|
@ -32,6 +32,10 @@ extern "C" {
|
|||
* VDM Control
|
||||
*/
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDSimulate16(VOID);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDTerminateVDM(VOID);
|
||||
|
|
|
@ -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
173
subsystems/ntvdm/clock.c
Normal 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
20
subsystems/ntvdm/clock.h
Normal 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 */
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "emulator.h"
|
||||
|
||||
#include "clock.h"
|
||||
#include "bios/bios.h"
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/pic.h"
|
||||
|
@ -24,6 +25,8 @@
|
|||
#include "vddsup.h"
|
||||
#include "io.h"
|
||||
|
||||
#include <isvbop.h>
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
FAST486_STATE EmulatorContext;
|
||||
|
@ -33,6 +36,8 @@ BOOLEAN VdmRunning = TRUE;
|
|||
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)
|
||||
|
|
|
@ -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,37 +280,23 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI InputThreadProc(LPVOID Parameter)
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord)
|
||||
{
|
||||
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)
|
||||
switch (InputRecord->EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
{
|
||||
BYTE ScanCode = (BYTE)InputRecord.Event.KeyEvent.wVirtualScanCode;
|
||||
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;
|
||||
if (!InputRecord->Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code onto the keyboard queue */
|
||||
for (i = 0; i < InputRecord.Event.KeyEvent.wRepeatCount; i++)
|
||||
for (i = 0; i < InputRecord->Event.KeyEvent.wRepeatCount; i++)
|
||||
{
|
||||
KeyboardQueuePush(ScanCode);
|
||||
}
|
||||
|
@ -326,26 +311,16 @@ static DWORD WINAPI InputThreadProc(LPVOID Parameter)
|
|||
break;
|
||||
}
|
||||
|
||||
/* We ignore all the rest */
|
||||
default:
|
||||
{
|
||||
/* Ignored */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
|
||||
VOID GenerateKeyboardInterrupts(VOID);
|
||||
|
||||
BOOLEAN PS2Initialize(HANDLE ConsoleInput);
|
||||
|
|
13
subsystems/ntvdm/lang/en-US.rc
Normal file
13
subsystems/ntvdm/lang/en-US.rc
Normal 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
|
13
subsystems/ntvdm/lang/fr-FR.rc
Normal file
13
subsystems/ntvdm/lang/fr-FR.rc
Normal 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
|
|
@ -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();
|
||||
|
|
|
@ -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, ...);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue