Author: aandrejevic
Date: Sun Oct 26 23:37:54 2014
New Revision: 65035
URL:
http://svn.reactos.org/svn/reactos?rev=65035&view=rev
Log:
[FAST486]
Implement an (optional) instruction prefetch cache.
Implement the INVLPG instruction.
Modified:
trunk/reactos/include/reactos/libs/fast486/fast486.h
trunk/reactos/lib/fast486/common.c
trunk/reactos/lib/fast486/common.h
trunk/reactos/lib/fast486/common.inl
trunk/reactos/lib/fast486/extraops.c
trunk/reactos/lib/fast486/opcodes.c
trunk/reactos/lib/fast486/opgroups.c
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fast4…
==============================================================================
--- trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] (original)
+++ trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] Sun Oct 26 23:37:54
2014
@@ -92,6 +92,18 @@
#define FAST486_PREFIX_REP (1 << 5)
#define FAST486_FPU_DEFAULT_CONTROL 0x037F
+
+#define FAST486_PAGE_SIZE 4096
+#define FAST486_CACHE_SIZE 32
+
+/*
+ * These are condiciones sine quibus non that should be respected, because
+ * otherwise when fetching DWORDs you would read extra garbage bytes
+ * (by reading outside of the prefetch buffer). The prefetch cache must
+ * also not cross a page boundary.
+ */
+C_ASSERT((FAST486_CACHE_SIZE >= sizeof(DWORD))
+ && (FAST486_CACHE_SIZE <= FAST486_PAGE_SIZE));
struct _FAST486_STATE;
typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE;
@@ -486,6 +498,11 @@
FAST486_INT_STATUS IntStatus;
UCHAR PendingIntNum;
PULONG Tlb;
+#ifndef FAST486_NO_PREFETCH
+ BOOLEAN PrefetchValid;
+ ULONG PrefetchAddress;
+ UCHAR PrefetchCache[FAST486_CACHE_SIZE];
+#endif
#ifndef FAST486_NO_FPU
FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS];
FAST486_FPU_STATUS_REG FpuStatus;
Modified: trunk/reactos/lib/fast486/common.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.c?rev=6…
==============================================================================
--- trunk/reactos/lib/fast486/common.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.c [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -95,8 +95,40 @@
/* Find the linear address */
LinearAddress = CachedDescriptor->Base + Offset;
- /* Read from the linear address */
- return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
+#ifndef FAST486_NO_PREFETCH
+ if (InstFetch && ((Offset + FAST486_CACHE_SIZE - 1) <=
CachedDescriptor->Limit))
+ {
+ State->PrefetchAddress = LinearAddress;
+
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
+ && (PAGE_OFFSET(State->PrefetchAddress) > (FAST486_PAGE_SIZE -
FAST486_CACHE_SIZE)))
+ {
+ /* We mustn't prefetch across a page boundary */
+ State->PrefetchAddress = PAGE_ALIGN(State->PrefetchAddress)
+ | (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE);
+ }
+
+ /* Prefetch */
+ if (Fast486ReadLinearMemory(State,
+ State->PrefetchAddress,
+ State->PrefetchCache,
+ FAST486_CACHE_SIZE))
+ {
+ State->PrefetchValid = TRUE;
+
+ RtlMoveMemory(Buffer,
+ &State->PrefetchCache[LinearAddress -
State->PrefetchAddress],
+ Size);
+ return TRUE;
+ }
+ else return FALSE;
+ }
+ else
+#endif
+ {
+ /* Read from the linear address */
+ return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
+ }
}
BOOLEAN
@@ -155,6 +187,18 @@
/* Find the linear address */
LinearAddress = CachedDescriptor->Base + Offset;
+
+#ifndef FAST486_NO_PREFETCH
+ if (State->PrefetchValid
+ && (LinearAddress >= State->PrefetchAddress)
+ && ((LinearAddress + Size) <= (State->PrefetchAddress +
FAST486_CACHE_SIZE)))
+ {
+ /* Update the prefetch */
+ RtlMoveMemory(&State->PrefetchCache[LinearAddress -
State->PrefetchAddress],
+ Buffer,
+ min(Size, FAST486_CACHE_SIZE + State->PrefetchAddress -
LinearAddress));
+ }
+#endif
/* Write to the linear address */
return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
Modified: trunk/reactos/lib/fast486/common.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.h?rev=6…
==============================================================================
--- trunk/reactos/lib/fast486/common.h [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.h [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -69,10 +69,6 @@
#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
-#endif
typedef struct _FAST486_MOD_REG_RM
{
Modified: trunk/reactos/lib/fast486/common.inl
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.inl?rev…
==============================================================================
--- trunk/reactos/lib/fast486/common.inl [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.inl [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -163,9 +163,9 @@
for (Page = PAGE_ALIGN(LinearAddress);
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
- Page += PAGE_SIZE)
- {
- ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+ Page += FAST486_PAGE_SIZE)
+ {
+ ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
/* Get the table entry */
TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
@@ -230,9 +230,9 @@
for (Page = PAGE_ALIGN(LinearAddress);
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
- Page += PAGE_SIZE)
- {
- ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+ Page += FAST486_PAGE_SIZE)
+ {
+ ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
/* Get the table entry */
TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
@@ -521,6 +521,11 @@
else if (Segment == FAST486_REG_CS)
{
/* Loading the code segment */
+
+#ifndef FAST486_NO_PREFETCH
+ /* Invalidate the prefetch */
+ State->PrefetchValid = FALSE;
+#endif
if (GET_SEGMENT_INDEX(Selector) == 0)
{
@@ -641,21 +646,39 @@
PUCHAR Data)
{
PFAST486_SEG_REG CachedDescriptor;
+ ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+ ULONG LinearAddress;
+#endif
/* Get the cached descriptor of CS */
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
- /* Read from memory */
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord,
- TRUE,
- Data,
- sizeof(UCHAR)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
+ Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+ : State->InstPtr.LowWord;
+#ifndef FAST486_NO_PREFETCH
+ LinearAddress = CachedDescriptor->Base + Offset;
+
+ if (State->PrefetchValid
+ && (LinearAddress >= State->PrefetchAddress)
+ && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress +
FAST486_CACHE_SIZE)))
+ {
+ *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress -
State->PrefetchAddress];
+ }
+ else
+#endif
+ {
+ /* Read from memory */
+ if (!Fast486ReadMemory(State,
+ FAST486_REG_CS,
+ Offset,
+ TRUE,
+ Data,
+ sizeof(UCHAR)))
+ {
+ /* Exception occurred during instruction fetch */
+ return FALSE;
+ }
}
/* Advance the instruction pointer */
@@ -672,22 +695,41 @@
PUSHORT Data)
{
PFAST486_SEG_REG CachedDescriptor;
+ ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+ ULONG LinearAddress;
+#endif
/* Get the cached descriptor of CS */
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
- /* Read from memory */
- // FIXME: Fix byte order on big-endian machines
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord,
- TRUE,
- Data,
- sizeof(USHORT)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
+ Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+ : State->InstPtr.LowWord;
+
+#ifndef FAST486_NO_PREFETCH
+ LinearAddress = CachedDescriptor->Base + Offset;
+
+ if (State->PrefetchValid
+ && (LinearAddress >= State->PrefetchAddress)
+ && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress +
FAST486_CACHE_SIZE)))
+ {
+ *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress -
State->PrefetchAddress];
+ }
+ else
+#endif
+ {
+ /* Read from memory */
+ // FIXME: Fix byte order on big-endian machines
+ if (!Fast486ReadMemory(State,
+ FAST486_REG_CS,
+ Offset,
+ TRUE,
+ Data,
+ sizeof(USHORT)))
+ {
+ /* Exception occurred during instruction fetch */
+ return FALSE;
+ }
}
/* Advance the instruction pointer */
@@ -704,22 +746,41 @@
PULONG Data)
{
PFAST486_SEG_REG CachedDescriptor;
+ ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+ ULONG LinearAddress;
+#endif
/* Get the cached descriptor of CS */
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
- /* Read from memory */
- // FIXME: Fix byte order on big-endian machines
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord,
- TRUE,
- Data,
- sizeof(ULONG)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
+ Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+ : State->InstPtr.LowWord;
+
+#ifndef FAST486_NO_PREFETCH
+ LinearAddress = CachedDescriptor->Base + Offset;
+
+ if (State->PrefetchValid
+ && (LinearAddress >= State->PrefetchAddress)
+ && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress +
FAST486_CACHE_SIZE)))
+ {
+ *Data = *(PULONG)&State->PrefetchCache[LinearAddress -
State->PrefetchAddress];
+ }
+ else
+#endif
+ {
+ /* Read from memory */
+ // FIXME: Fix byte order on big-endian machines
+ if (!Fast486ReadMemory(State,
+ FAST486_REG_CS,
+ Offset,
+ TRUE,
+ Data,
+ sizeof(ULONG)))
+ {
+ /* Exception occurred during instruction fetch */
+ return FALSE;
+ }
}
/* Advance the instruction pointer */
Modified: trunk/reactos/lib/fast486/extraops.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/extraops.c?rev…
==============================================================================
--- trunk/reactos/lib/fast486/extraops.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/extraops.c [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -686,6 +686,11 @@
}
}
+#ifndef FAST486_NO_PREFETCH
+ /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
+ State->PrefetchValid = FALSE;
+#endif
+
/* Load a value to the control register */
State->ControlRegisters[ModRegRm.Register] = Value;
}
Modified: trunk/reactos/lib/fast486/opcodes.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opcodes.c?rev=…
==============================================================================
--- trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -4240,6 +4240,11 @@
{
UCHAR BopCode;
+#ifndef FAST486_NO_PREFETCH
+ /* Invalidate the prefetch since BOP handlers can alter the memory */
+ State->PrefetchValid = FALSE;
+#endif
+
/* Fetch the BOP code */
if (!Fast486FetchByte(State, &BopCode))
{
Modified: trunk/reactos/lib/fast486/opgroups.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opgroups.c?rev…
==============================================================================
--- trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] Sun Oct 26 23:37:54 2014
@@ -2177,7 +2177,31 @@
/* INVLPG */
case 7:
{
- UNIMPLEMENTED;
+#ifndef FAST486_NO_PREFETCH
+ /* Invalidate the prefetch */
+ State->PrefetchValid = FALSE;
+#endif
+
+ /* This is a privileged instruction */
+ if (Fast486GetCurrentPrivLevel(State) != 0)
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_GP);
+ return;
+ }
+
+ if (!ModRegRm.Memory)
+ {
+ /* The second operand must be a memory location */
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ return;
+ }
+
+ if (State->Tlb != NULL)
+ {
+ /* Clear the TLB entry */
+ State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
+ }
+
break;
}