reactos/subsystems/mvdm/ntvdm/hardware/cmos.c

537 lines
14 KiB
C
Raw Normal View History

/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: subsystems/mvdm/ntvdm/hardware/cmos.c
* PURPOSE: CMOS Real Time Clock emulation
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
#define NDEBUG
#include <debug.h>
#include "emulator.h"
#include "cmos.h"
#include "io.h"
#include "pic.h"
#include "clock.h"
/* PRIVATE VARIABLES **********************************************************/
static HANDLE hCmosRam = INVALID_HANDLE_VALUE;
static CMOS_MEMORY CmosMemory;
static BOOLEAN NmiEnabled = TRUE;
static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
static PHARDWARE_TIMER ClockTimer;
static PHARDWARE_TIMER PeriodicTimer;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID RtcUpdatePeriodicTimer(VOID)
{
BYTE RateSelect = CmosMemory.StatusRegA & 0x0F;
if (RateSelect == 0)
{
/* No periodic interrupt */
DisableHardwareTimer(PeriodicTimer);
return;
}
/* 1 and 2 act like 8 and 9 */
if (RateSelect <= 2) RateSelect += 7;
SetHardwareTimerDelay(PeriodicTimer, HZ_TO_NS(1 << (16 - RateSelect)));
// FIXME: This call keeps EnableCount increasing without compensating it!
EnableHardwareTimer(PeriodicTimer);
}
static VOID FASTCALL RtcPeriodicTick(ULONGLONG ElapsedTime)
{
UNREFERENCED_PARAMETER(ElapsedTime);
/* Set PF */
CmosMemory.StatusRegC |= CMOS_STC_PF;
/* Check if there should be an interrupt on a periodic timer tick */
if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
{
CmosMemory.StatusRegC |= CMOS_STC_IRQF;
/* Interrupt! */
PicInterruptRequest(RTC_IRQ_NUMBER);
}
}
/* Should be called every second */
static VOID FASTCALL RtcTimeUpdate(ULONGLONG ElapsedTime)
{
SYSTEMTIME CurrentTime;
UNREFERENCED_PARAMETER(ElapsedTime);
/* Get the current time */
GetLocalTime(&CurrentTime);
/* Set UF */
CmosMemory.StatusRegC |= CMOS_STC_UF;
/* Check if the time matches the alarm time */
if ((CurrentTime.wHour == CmosMemory.AlarmHour ) &&
(CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
(CurrentTime.wSecond == CmosMemory.AlarmSecond))
{
/* Set the alarm flag */
CmosMemory.StatusRegC |= CMOS_STC_AF;
/* Set IRQF if there should be an interrupt */
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_ALARM) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
}
/* Check if there should be an interrupt on update */
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_UPDATE) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
if (CmosMemory.StatusRegC & CMOS_STC_IRQF)
{
/* Interrupt! */
PicInterruptRequest(RTC_IRQ_NUMBER);
}
}
static VOID WINAPI CmosWriteAddress(USHORT Port, BYTE Data)
{
UNREFERENCED_PARAMETER(Port);
/* Update the NMI enabled flag */
NmiEnabled = !(Data & CMOS_DISABLE_NMI);
/* Get the register number */
Data &= ~CMOS_DISABLE_NMI;
if (Data < CMOS_REG_MAX)
{
/* Select the new register */
SelectedRegister = Data;
}
else
{
/* Default to Status Register D */
SelectedRegister = CMOS_REG_STATUS_D;
}
}
static BYTE WINAPI CmosReadData(USHORT Port)
{
BYTE Value;
SYSTEMTIME CurrentTime;
UNREFERENCED_PARAMETER(Port);
/* Get the current time */
GetLocalTime(&CurrentTime);
switch (SelectedRegister)
{
case CMOS_REG_SECONDS:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wSecond);
break;
}
case CMOS_REG_ALARM_SEC:
{
Value = READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmSecond);
break;
}
case CMOS_REG_MINUTES:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wMinute);
break;
}
case CMOS_REG_ALARM_MIN:
{
Value = READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmMinute);
break;
}
case CMOS_REG_HOURS:
{
BOOLEAN Afternoon = FALSE;
Value = CurrentTime.wHour;
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
{
Value -= 12;
Afternoon = TRUE;
}
Value = READ_CMOS_DATA(CmosMemory, Value);
/* Convert to 12-hour */
if (Afternoon) Value |= 0x80;
break;
}
case CMOS_REG_ALARM_HRS:
{
BOOLEAN Afternoon = FALSE;
Value = CmosMemory.AlarmHour;
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
{
Value -= 12;
Afternoon = TRUE;
}
Value = READ_CMOS_DATA(CmosMemory, Value);
/* Convert to 12-hour */
if (Afternoon) Value |= 0x80;
break;
}
case CMOS_REG_DAY_OF_WEEK:
{
/*
* The CMOS value is 1-based but the
* GetLocalTime API value is 0-based.
* Correct it.
*/
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wDayOfWeek + 1);
break;
}
case CMOS_REG_DAY:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wDay);
break;
}
case CMOS_REG_MONTH:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wMonth);
break;
}
case CMOS_REG_YEAR:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wYear % 100);
break;
}
[NTVDM] - Add some level of "Advanced debugging" (see ntvdm.h) which one can adjust to enable/disable debugging features inside NTVDM (this can be useful as long as NTVDM is under heavy bugfixing. When it will be more perfect, this stuff will be removed). - Add the possibility to load option ROMs at a given segment. Currently their list should be specified from inside ntvdm.c (in the BiosInitialize call), but I plan to make it available from a registry option (or via command-line for NTVDM-standalone mode). - Start to separate the initialization of "static" BIOS data (stuff that lives in ROM space) and initialization of "dynamic" BIOS data (eg. initializing the interrupt vector table, the BIOS data area at segment 40h, ...) so that we may be able to reuse part of our code to be able to more-or-less run external (16-bit) BIOSes, or the Windows NTVDM BIOS that uses BOPs to run some of its stuff in ntvdm in 32-bit (as we do for our 32-bit BIOS, except that *all* of our bios is 32-bit, not just some parts). Also, some file reorganization will be in order there soon... - Add video BIOS version information in memory so that tools such as Microsoft Diagnostics can correctly recognize our video BIOS (btw, we try to emulate the functionality of Cirrus' CL-GD5434). - Correctly put video BIOS ROM header (+ checksum) in memory so that it is recognized as such by diagnostics tools. - During BIOS POST, scan for ROMs starting segment 0xC000 (where video ROMs reside). - Store statically the BIOS configuration table. - Fix INT 16h, AH=12h "Get extended shift states" so that it correctly returns the state of right Ctrl and Alt keys. - Fix bit-setting state; report that our keyboard is 101/102 enhanced keyboard. - Correctly set the error return values (AH=86h and CF set) when a function of INT 15h is unsupported. - Implement INT 15h, AH=C9h "Get CPU Type and Mask Revision"; INT 1Ah, AH=02h "Get Real-Time Clock Time" and Ah=04h "Get Real-Time Clock Date" by reading the CMOS. - Implement CMOS century register support. svn path=/trunk/; revision=68598
2015-08-04 20:17:05 +00:00
case CMOS_REG_CENTURY:
{
Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wYear / 100 + 19);
break;
}
case CMOS_REG_STATUS_C:
{
/* Return the old status register value, then clear it */
Value = CmosMemory.StatusRegC;
CmosMemory.StatusRegC = 0x00;
break;
}
case CMOS_REG_STATUS_A:
case CMOS_REG_STATUS_B:
case CMOS_REG_STATUS_D:
case CMOS_REG_DIAGNOSTICS:
case CMOS_REG_SHUTDOWN_STATUS:
default:
{
// ASSERT(SelectedRegister < CMOS_REG_MAX);
Value = CmosMemory.Regs[SelectedRegister];
}
}
/* Return to Status Register D */
SelectedRegister = CMOS_REG_STATUS_D;
return Value;
}
static VOID WINAPI CmosWriteData(USHORT Port, BYTE Data)
{
BOOLEAN ChangeTime = FALSE;
SYSTEMTIME CurrentTime;
UNREFERENCED_PARAMETER(Port);
/* Get the current time */
GetLocalTime(&CurrentTime);
switch (SelectedRegister)
{
case CMOS_REG_SECONDS:
{
ChangeTime = TRUE;
CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_ALARM_SEC:
{
CmosMemory.AlarmSecond = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_MINUTES:
{
ChangeTime = TRUE;
CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_ALARM_MIN:
{
CmosMemory.AlarmMinute = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_HOURS:
{
BOOLEAN Afternoon = FALSE;
ChangeTime = TRUE;
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
{
Data &= ~0x80;
Afternoon = TRUE;
}
CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Data);
/* Convert to 24-hour format */
if (Afternoon) CurrentTime.wHour += 12;
break;
}
case CMOS_REG_ALARM_HRS:
{
BOOLEAN Afternoon = FALSE;
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
{
Data &= ~0x80;
Afternoon = TRUE;
}
CmosMemory.AlarmHour = WRITE_CMOS_DATA(CmosMemory, Data);
/* Convert to 24-hour format */
if (Afternoon) CmosMemory.AlarmHour += 12;
break;
}
case CMOS_REG_DAY_OF_WEEK:
{
ChangeTime = TRUE;
/*
* The CMOS value is 1-based but the
* SetLocalTime API value is 0-based.
* Correct it.
*/
Data -= 1;
CurrentTime.wDayOfWeek = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_DAY:
{
ChangeTime = TRUE;
CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_MONTH:
{
ChangeTime = TRUE;
CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
case CMOS_REG_YEAR:
{
ChangeTime = TRUE;
/* Clear everything except the century */
CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Data);
break;
}
[NTVDM] - Add some level of "Advanced debugging" (see ntvdm.h) which one can adjust to enable/disable debugging features inside NTVDM (this can be useful as long as NTVDM is under heavy bugfixing. When it will be more perfect, this stuff will be removed). - Add the possibility to load option ROMs at a given segment. Currently their list should be specified from inside ntvdm.c (in the BiosInitialize call), but I plan to make it available from a registry option (or via command-line for NTVDM-standalone mode). - Start to separate the initialization of "static" BIOS data (stuff that lives in ROM space) and initialization of "dynamic" BIOS data (eg. initializing the interrupt vector table, the BIOS data area at segment 40h, ...) so that we may be able to reuse part of our code to be able to more-or-less run external (16-bit) BIOSes, or the Windows NTVDM BIOS that uses BOPs to run some of its stuff in ntvdm in 32-bit (as we do for our 32-bit BIOS, except that *all* of our bios is 32-bit, not just some parts). Also, some file reorganization will be in order there soon... - Add video BIOS version information in memory so that tools such as Microsoft Diagnostics can correctly recognize our video BIOS (btw, we try to emulate the functionality of Cirrus' CL-GD5434). - Correctly put video BIOS ROM header (+ checksum) in memory so that it is recognized as such by diagnostics tools. - During BIOS POST, scan for ROMs starting segment 0xC000 (where video ROMs reside). - Store statically the BIOS configuration table. - Fix INT 16h, AH=12h "Get extended shift states" so that it correctly returns the state of right Ctrl and Alt keys. - Fix bit-setting state; report that our keyboard is 101/102 enhanced keyboard. - Correctly set the error return values (AH=86h and CF set) when a function of INT 15h is unsupported. - Implement INT 15h, AH=C9h "Get CPU Type and Mask Revision"; INT 1Ah, AH=02h "Get Real-Time Clock Time" and Ah=04h "Get Real-Time Clock Date" by reading the CMOS. - Implement CMOS century register support. svn path=/trunk/; revision=68598
2015-08-04 20:17:05 +00:00
case CMOS_REG_CENTURY:
{
UNIMPLEMENTED;
break;
}
case CMOS_REG_STATUS_A:
{
CmosMemory.StatusRegA = Data & 0x7F; // Bit 7 is read-only
RtcUpdatePeriodicTimer();
break;
}
case CMOS_REG_STATUS_B:
{
CmosMemory.StatusRegB = Data;
break;
}
case CMOS_REG_STATUS_C:
case CMOS_REG_STATUS_D:
// Status registers C and D are read-only
break;
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/* Is the following correct? */
case CMOS_REG_EXT_MEMORY_LOW:
case CMOS_REG_ACTUAL_EXT_MEMORY_LOW:
{
/* Sync EMS and UMS */
CmosMemory.ExtMemoryLow =
CmosMemory.ActualExtMemoryLow = Data;
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
break;
}
/* Is the following correct? */
case CMOS_REG_EXT_MEMORY_HIGH:
case CMOS_REG_ACTUAL_EXT_MEMORY_HIGH:
{
/* Sync EMS and UMS */
CmosMemory.ExtMemoryHigh =
CmosMemory.ActualExtMemoryHigh = Data;
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
break;
}
default:
{
CmosMemory.Regs[SelectedRegister] = Data;
}
}
if (ChangeTime) SetLocalTime(&CurrentTime);
/* Return to Status Register D */
SelectedRegister = CMOS_REG_STATUS_D;
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN IsNmiEnabled(VOID)
{
return NmiEnabled;
}
VOID CmosInitialize(VOID)
{
DWORD CmosSize = sizeof(CmosMemory);
/* File must not be opened before */
ASSERT(hCmosRam == INVALID_HANDLE_VALUE);
/* Clear the CMOS memory */
RtlZeroMemory(&CmosMemory, sizeof(CmosMemory));
/* Always open (and if needed, create) a RAM file with shared access */
SetLastError(0); // For debugging purposes
hCmosRam = CreateFileW(L"cmos.ram",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
DPRINT1("CMOS opening %s (Error: %u)\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
if (hCmosRam != INVALID_HANDLE_VALUE)
{
BOOL Success;
/* Attempt to fill the CMOS memory with the RAM file */
SetLastError(0); // For debugging purposes
Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
if (CmosSize != sizeof(CmosMemory))
{
/* Bad CMOS RAM file. Reinitialize the CMOS memory. */
DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
RtlZeroMemory(&CmosMemory, sizeof(CmosMemory));
}
DPRINT1("CMOS loading %s (Error: %u)\n", Success ? "succeeded" : "failed", GetLastError());
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
}
/* Overwrite some registers with default values */
CmosMemory.StatusRegA = CMOS_DEFAULT_STA;
CmosMemory.StatusRegB = CMOS_DEFAULT_STB;
CmosMemory.StatusRegC = 0x00;
CmosMemory.StatusRegD = CMOS_BATTERY_OK; // Our CMOS battery works perfectly forever.
CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any errors.
CmosMemory.ShutdownStatus = 0x00;
CmosMemory.EquipmentList = CMOS_EQUIPMENT_LIST;
// HACK: For the moment, set the boot sequence to: 1-Floppy, 2-Hard Disk .
CmosMemory.Regs[CMOS_REG_SYSOP] |= (1 << 5);
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/* Memory settings */
/*
* Conventional memory size is 640 kB,
* see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
* and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
* for more information.
*/
CmosMemory.BaseMemoryLow = LOBYTE(0x0280);
CmosMemory.BaseMemoryHigh = HIBYTE(0x0280);
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
CmosMemory.ExtMemoryLow =
CmosMemory.ActualExtMemoryLow = LOBYTE((MAX_ADDRESS - 0x100000) / 1024);
CmosMemory.ExtMemoryHigh =
CmosMemory.ActualExtMemoryHigh = HIBYTE((MAX_ADDRESS - 0x100000) / 1024);
[NTVDM] - Move all the hardware initialization to EmulatorInitialize (since emulator.c can be viewed as support functions for emulating a PC motherboard) --> PS2 and VGA go there. - Break bios.c into bios.c and kbdbios.c (the keyboard bios module) (according to the IBM documentation as well as other emulator sources or SeaBIOS or...). - Move Exception handling from int32.c to emulator.c, because it's something tight to the emulator, not to the interrupt system by itself (yet it happens that INT 00h to 07h are commonly set to some exception handlers). In the bios.c, initialize those vectors with the default exception handler. - Handling IRQs is done fully in bios.c now: introduce PicSetIRQMask and EnableHwIRQ helper functions (adapted from their equivalents from SeaBIOS) that allows the bios to set (and activate in the PIC) a given IRQ with its corresponding handler. Also introduce PicIRQComplete that serves as a PIC IRQ completer (i.e. sends the EOI to the right PIC(s)). - Continuing on that, at the moment I set dumb default PIC IRQ handlers for IRQ 08h - 0Fh and IRQ 70h - 77h). - By default I disable all the IRQs; there are then set on-demand with EnableHwIRQ. - Rework the POST (aka. BiosInitialize function): * the memory size is now get from the CMOS (as well as the extended memory size via INT 12h, AH=88h), * then we initialize the interrupts, * then platform hardware (ie. the chips) are initialized, * and finally the keyboard and video bioses. - As said before, move memory sizes into the CMOS. - Simplify video bios initialization. svn path=/branches/ntvdm/; revision=61796
2014-01-25 00:21:51 +00:00
/* Register the I/O Ports */
RegisterIoPort(CMOS_ADDRESS_PORT, NULL, CmosWriteAddress);
RegisterIoPort(CMOS_DATA_PORT , CmosReadData, CmosWriteData );
ClockTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED,
HZ_TO_NS(1),
RtcTimeUpdate);
PeriodicTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED | HARDWARE_TIMER_PRECISE,
HZ_TO_NS(1000),
RtcPeriodicTick);
}
VOID CmosCleanup(VOID)
{
DWORD CmosSize = sizeof(CmosMemory);
if (hCmosRam == INVALID_HANDLE_VALUE) return;
DestroyHardwareTimer(PeriodicTimer);
DestroyHardwareTimer(ClockTimer);
/* Flush the CMOS memory back to the RAM file and close it */
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
CloseHandle(hCmosRam);
hCmosRam = INVALID_HANDLE_VALUE;
}
/* EOF */