mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 17:25:55 +00:00
[FAST486]
Modularize linear memory access by adding two new functions: Fast486ReadLinearMemory and Fast486WriteLinearMemory. Implement Fast486GetPageTableEntry. svn path=/branches/ntvdm/; revision=60923
This commit is contained in:
parent
7c036fd0f7
commit
c3c7bb89c1
6 changed files with 264 additions and 146 deletions
|
@ -401,6 +401,7 @@ struct _FAST486_STATE
|
|||
FAST486_SEG_REGS SegmentOverride;
|
||||
FAST486_INT_STATUS IntStatus;
|
||||
UCHAR PendingIntNum;
|
||||
PULONG Tlb;
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
@ -414,7 +415,8 @@ Fast486Initialize(PFAST486_STATE State,
|
|||
FAST486_IO_WRITE_PROC IoWriteCallback,
|
||||
FAST486_IDLE_PROC IdleCallback,
|
||||
FAST486_BOP_PROC BopCallback,
|
||||
FAST486_INT_ACK_PROC IntAckCallback);
|
||||
FAST486_INT_ACK_PROC IntAckCallback,
|
||||
PULONG Tlb);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
|
|
|
@ -29,19 +29,6 @@
|
|||
#include <fast486.h>
|
||||
#include "common.h"
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static inline
|
||||
ULONG
|
||||
Fast486GetPageTableEntry(PFAST486_STATE State,
|
||||
ULONG VirtualAddress)
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN
|
||||
|
@ -54,7 +41,6 @@ Fast486ReadMemory(PFAST486_STATE State,
|
|||
{
|
||||
ULONG LinearAddress;
|
||||
PFAST486_SEG_REG CachedDescriptor;
|
||||
INT Cpl = Fast486GetCurrentPrivLevel(State);
|
||||
|
||||
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
|
||||
|
||||
|
@ -108,58 +94,8 @@ Fast486ReadMemory(PFAST486_STATE State,
|
|||
/* Find the linear address */
|
||||
LinearAddress = CachedDescriptor->Base + Offset;
|
||||
|
||||
/* Check if paging is enabled */
|
||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
|
||||
{
|
||||
ULONG Page;
|
||||
FAST486_PAGE_TABLE TableEntry;
|
||||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page);
|
||||
|
||||
if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
|
||||
{
|
||||
/* Exception */
|
||||
Fast486ExceptionWithErrorCode(State,
|
||||
FAST486_EXCEPTION_PF,
|
||||
TableEntry.Value & 0x07);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check if this is the first page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress))
|
||||
{
|
||||
/* Start copying from the offset from the beginning of the page */
|
||||
PageOffset = PAGE_OFFSET(LinearAddress);
|
||||
}
|
||||
|
||||
/* Check if this is the last page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
|
||||
{
|
||||
/* Copy only a part of the page */
|
||||
PageLength = PAGE_OFFSET(LinearAddress + Size);
|
||||
}
|
||||
|
||||
/* Read the memory */
|
||||
State->MemReadCallback(State,
|
||||
(TableEntry.Address << 12) | PageOffset,
|
||||
Buffer,
|
||||
PageLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the memory */
|
||||
State->MemReadCallback(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
/* Read from the linear address */
|
||||
return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
|
@ -171,7 +107,6 @@ Fast486WriteMemory(PFAST486_STATE State,
|
|||
{
|
||||
ULONG LinearAddress;
|
||||
PFAST486_SEG_REG CachedDescriptor;
|
||||
INT Cpl = Fast486GetCurrentPrivLevel(State);
|
||||
|
||||
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
|
||||
|
||||
|
@ -220,60 +155,8 @@ Fast486WriteMemory(PFAST486_STATE State,
|
|||
/* Find the linear address */
|
||||
LinearAddress = CachedDescriptor->Base + Offset;
|
||||
|
||||
/* Check if paging is enabled */
|
||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
|
||||
{
|
||||
ULONG Page;
|
||||
FAST486_PAGE_TABLE TableEntry;
|
||||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page);
|
||||
|
||||
if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
|
||||
|| ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
|
||||
&& !TableEntry.Writeable))
|
||||
{
|
||||
/* Exception */
|
||||
Fast486ExceptionWithErrorCode(State,
|
||||
FAST486_EXCEPTION_PF,
|
||||
TableEntry.Value & 0x07);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check if this is the first page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress))
|
||||
{
|
||||
/* Start copying from the offset from the beginning of the page */
|
||||
PageOffset = PAGE_OFFSET(LinearAddress);
|
||||
}
|
||||
|
||||
/* Check if this is the last page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
|
||||
{
|
||||
/* Copy only a part of the page */
|
||||
PageLength = PAGE_OFFSET(LinearAddress + Size);
|
||||
}
|
||||
|
||||
/* Write the memory */
|
||||
State->MemWriteCallback(State,
|
||||
(TableEntry.Address << 12) | PageOffset,
|
||||
Buffer,
|
||||
PageLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the memory */
|
||||
State->MemWriteCallback(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
/* Write to the linear address */
|
||||
return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
|
@ -293,11 +176,14 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
|||
if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
|
||||
{
|
||||
/* Read the TSS */
|
||||
// FIXME: This code is only correct when paging is disabled!!!
|
||||
State->MemReadCallback(State,
|
||||
State->Tss.Address,
|
||||
&Tss,
|
||||
sizeof(Tss));
|
||||
if (!Fast486ReadLinearMemory(State,
|
||||
State->Tss.Address,
|
||||
&Tss,
|
||||
sizeof(Tss)))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check the new (higher) privilege level */
|
||||
switch (GET_SEGMENT_RPL(SegmentSelector))
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
|
||||
#define PAGE_ALIGN(x) ((x) & 0xFFFFF000)
|
||||
#define PAGE_OFFSET(x) ((x) & 0x00000FFF)
|
||||
#define GET_ADDR_PDE(x) ((x) >> 22)
|
||||
#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
|
||||
#define INVALID_TLB_FIELD 0xFFFFFFFF
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
|
@ -92,6 +95,8 @@ typedef union _FAST486_PAGE_DIR
|
|||
ULONG Value;
|
||||
} FAST486_PAGE_DIR, *PFAST486_PAGE_DIR;
|
||||
|
||||
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
|
||||
|
||||
typedef union _FAST486_PAGE_TABLE
|
||||
{
|
||||
struct
|
||||
|
@ -111,6 +116,8 @@ typedef union _FAST486_PAGE_TABLE
|
|||
ULONG Value;
|
||||
} FAST486_PAGE_TABLE, *PFAST486_PAGE_TABLE;
|
||||
|
||||
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
|
|
@ -19,8 +19,222 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
Fast486GetPageTableEntry(PFAST486_STATE State,
|
||||
ULONG VirtualAddress,
|
||||
BOOLEAN MarkAsDirty)
|
||||
{
|
||||
ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
|
||||
ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
|
||||
FAST486_PAGE_DIR DirectoryEntry;
|
||||
FAST486_PAGE_TABLE TableEntry;
|
||||
ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
|
||||
|
||||
if ((State->Tlb != NULL)
|
||||
&& (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
|
||||
{
|
||||
/* Return the cached entry */
|
||||
return State->Tlb[VirtualAddress >> 12];
|
||||
}
|
||||
|
||||
/* Read the directory entry */
|
||||
State->MemReadCallback(State,
|
||||
PageDirectory + PdeIndex * sizeof(ULONG),
|
||||
&DirectoryEntry.Value,
|
||||
sizeof(DirectoryEntry));
|
||||
|
||||
/* Make sure it is present */
|
||||
if (!DirectoryEntry.Present) return 0;
|
||||
|
||||
/* Was the directory entry accessed before? */
|
||||
if (!DirectoryEntry.Accessed)
|
||||
{
|
||||
/* Well, it is now */
|
||||
DirectoryEntry.Accessed = TRUE;
|
||||
|
||||
/* Write back the directory entry */
|
||||
State->MemWriteCallback(State,
|
||||
PageDirectory + PdeIndex * sizeof(ULONG),
|
||||
&DirectoryEntry.Value,
|
||||
sizeof(DirectoryEntry));
|
||||
}
|
||||
|
||||
/* Read the table entry */
|
||||
State->MemReadCallback(State,
|
||||
(DirectoryEntry.TableAddress << 12)
|
||||
+ PteIndex * sizeof(ULONG),
|
||||
&TableEntry.Value,
|
||||
sizeof(TableEntry));
|
||||
|
||||
/* Make sure it is present */
|
||||
if (!TableEntry.Present) return 0;
|
||||
|
||||
if (MarkAsDirty) TableEntry.Dirty = TRUE;
|
||||
|
||||
/* Was the table entry accessed before? */
|
||||
if (!TableEntry.Accessed)
|
||||
{
|
||||
/* Well, it is now */
|
||||
TableEntry.Accessed = TRUE;
|
||||
|
||||
/* Write back the table entry */
|
||||
State->MemWriteCallback(State,
|
||||
(DirectoryEntry.TableAddress << 12)
|
||||
+ PteIndex * sizeof(ULONG),
|
||||
&TableEntry.Value,
|
||||
sizeof(TableEntry));
|
||||
}
|
||||
|
||||
/*
|
||||
* The resulting permissions depend on the permissions
|
||||
* in the page directory table too
|
||||
*/
|
||||
TableEntry.Writeable &= DirectoryEntry.Writeable;
|
||||
TableEntry.Usermode &= DirectoryEntry.Usermode;
|
||||
|
||||
if (State->Tlb != NULL)
|
||||
{
|
||||
/* Set the TLB entry */
|
||||
State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
|
||||
}
|
||||
|
||||
/* Return the table entry */
|
||||
return TableEntry.Value;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
Fast486ReadLinearMemory(PFAST486_STATE State,
|
||||
ULONG LinearAddress,
|
||||
PVOID Buffer,
|
||||
ULONG Size)
|
||||
{
|
||||
INT Cpl = Fast486GetCurrentPrivLevel(State);
|
||||
|
||||
/* Check if paging is enabled */
|
||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
|
||||
{
|
||||
ULONG Page;
|
||||
FAST486_PAGE_TABLE TableEntry;
|
||||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
|
||||
|
||||
if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
|
||||
{
|
||||
/* Exception */
|
||||
Fast486ExceptionWithErrorCode(State,
|
||||
FAST486_EXCEPTION_PF,
|
||||
TableEntry.Value & 0x07);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check if this is the first page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress))
|
||||
{
|
||||
/* Start copying from the offset from the beginning of the page */
|
||||
PageOffset = PAGE_OFFSET(LinearAddress);
|
||||
}
|
||||
|
||||
/* Check if this is the last page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
|
||||
{
|
||||
/* Copy only a part of the page */
|
||||
PageLength = PAGE_OFFSET(LinearAddress + Size);
|
||||
}
|
||||
|
||||
/* Read the memory */
|
||||
State->MemReadCallback(State,
|
||||
(TableEntry.Address << 12) | PageOffset,
|
||||
Buffer,
|
||||
PageLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the memory */
|
||||
State->MemReadCallback(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
Fast486WriteLinearMemory(PFAST486_STATE State,
|
||||
ULONG LinearAddress,
|
||||
PVOID Buffer,
|
||||
ULONG Size)
|
||||
{
|
||||
INT Cpl = Fast486GetCurrentPrivLevel(State);
|
||||
|
||||
/* Check if paging is enabled */
|
||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
|
||||
{
|
||||
ULONG Page;
|
||||
FAST486_PAGE_TABLE TableEntry;
|
||||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
|
||||
|
||||
if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
|
||||
|| ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
|
||||
&& !TableEntry.Writeable))
|
||||
{
|
||||
/* Exception */
|
||||
Fast486ExceptionWithErrorCode(State,
|
||||
FAST486_EXCEPTION_PF,
|
||||
TableEntry.Value & 0x07);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check if this is the first page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress))
|
||||
{
|
||||
/* Start copying from the offset from the beginning of the page */
|
||||
PageOffset = PAGE_OFFSET(LinearAddress);
|
||||
}
|
||||
|
||||
/* Check if this is the last page */
|
||||
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
|
||||
{
|
||||
/* Copy only a part of the page */
|
||||
PageLength = PAGE_OFFSET(LinearAddress + Size);
|
||||
}
|
||||
|
||||
/* Write the memory */
|
||||
State->MemWriteCallback(State,
|
||||
(TableEntry.Address << 12) | PageOffset,
|
||||
Buffer,
|
||||
PageLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the memory */
|
||||
State->MemWriteCallback(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
Fast486Exception(PFAST486_STATE State,
|
||||
|
@ -185,12 +399,15 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
}
|
||||
|
||||
/* Read the GDT */
|
||||
// FIXME: This code is only correct when paging is disabled!!!
|
||||
State->MemReadCallback(State,
|
||||
State->Gdtr.Address
|
||||
+ GET_SEGMENT_INDEX(Selector),
|
||||
&GdtEntry,
|
||||
sizeof(GdtEntry));
|
||||
if (!Fast486ReadLinearMemory(State,
|
||||
State->Gdtr.Address
|
||||
+ GET_SEGMENT_INDEX(Selector),
|
||||
&GdtEntry,
|
||||
sizeof(GdtEntry)))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Segment == FAST486_REG_SS)
|
||||
{
|
||||
|
@ -388,12 +605,15 @@ Fast486GetIntVector(PFAST486_STATE State,
|
|||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
|
||||
{
|
||||
/* Read from the IDT */
|
||||
// FIXME: This code is only correct when paging is disabled!!!
|
||||
State->MemReadCallback(State,
|
||||
State->Idtr.Address
|
||||
+ Number * sizeof(*IdtEntry),
|
||||
IdtEntry,
|
||||
sizeof(*IdtEntry));
|
||||
if (!Fast486ReadLinearMemory(State,
|
||||
State->Idtr.Address
|
||||
+ Number * sizeof(*IdtEntry),
|
||||
IdtEntry,
|
||||
sizeof(*IdtEntry)))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -417,10 +637,6 @@ Fast486GetIntVector(PFAST486_STATE State,
|
|||
IdtEntry->OffsetHigh = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Once paging support is implemented this function
|
||||
* will not always return true
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,8 @@ Fast486Initialize(PFAST486_STATE State,
|
|||
FAST486_IO_WRITE_PROC IoWriteCallback,
|
||||
FAST486_IDLE_PROC IdleCallback,
|
||||
FAST486_BOP_PROC BopCallback,
|
||||
FAST486_INT_ACK_PROC IntAckCallback)
|
||||
FAST486_INT_ACK_PROC IntAckCallback,
|
||||
PULONG Tlb)
|
||||
{
|
||||
/* Set the callbacks (or use default ones if some are NULL) */
|
||||
State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
|
||||
|
@ -214,6 +215,9 @@ Fast486Initialize(PFAST486_STATE State,
|
|||
State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
|
||||
State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
|
||||
|
||||
/* Set the TLB (if given) */
|
||||
State->Tlb = Tlb;
|
||||
|
||||
/* Reset the CPU */
|
||||
Fast486Reset(State);
|
||||
}
|
||||
|
@ -231,6 +235,7 @@ Fast486Reset(PFAST486_STATE State)
|
|||
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
|
||||
FAST486_BOP_PROC BopCallback = State->BopCallback;
|
||||
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
|
||||
PULONG Tlb = State->Tlb;
|
||||
|
||||
/* Clear the entire structure */
|
||||
RtlZeroMemory(State, sizeof(*State));
|
||||
|
@ -266,7 +271,7 @@ Fast486Reset(PFAST486_STATE State)
|
|||
/* Initialize CR0 */
|
||||
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
|
||||
|
||||
/* Restore the callbacks */
|
||||
/* Restore the callbacks and TLB */
|
||||
State->MemReadCallback = MemReadCallback;
|
||||
State->MemWriteCallback = MemWriteCallback;
|
||||
State->IoReadCallback = IoReadCallback;
|
||||
|
@ -274,6 +279,7 @@ Fast486Reset(PFAST486_STATE State)
|
|||
State->IdleCallback = IdleCallback;
|
||||
State->BopCallback = BopCallback;
|
||||
State->IntAckCallback = IntAckCallback;
|
||||
State->Tlb = Tlb;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
|
@ -296,7 +296,8 @@ BOOLEAN EmulatorInitialize(VOID)
|
|||
EmulatorWriteIo,
|
||||
NULL,
|
||||
EmulatorBiosOperation,
|
||||
EmulatorIntAcknowledge);
|
||||
EmulatorIntAcknowledge,
|
||||
NULL /* TODO: Use a TLB */);
|
||||
|
||||
/* Enable interrupts */
|
||||
EmulatorSetFlag(EMULATOR_FLAG_IF);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue