mirror of
https://github.com/reactos/reactos.git
synced 2025-07-23 10:53:42 +00:00
[FAST486]
Implement an (optional) instruction prefetch cache. Implement the INVLPG instruction. svn path=/trunk/; revision=65035
This commit is contained in:
parent
dd58a72a8b
commit
bc64e37fd1
7 changed files with 195 additions and 43 deletions
|
@ -93,6 +93,18 @@
|
|||
|
||||
#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 @@ struct _FAST486_STATE
|
|||
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;
|
||||
|
|
|
@ -95,8 +95,40 @@ Fast486ReadMemory(PFAST486_STATE State,
|
|||
/* 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
|
||||
|
@ -156,6 +188,18 @@ Fast486WriteMemory(PFAST486_STATE State,
|
|||
/* 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);
|
||||
}
|
||||
|
|
|
@ -70,10 +70,6 @@ if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
|
|||
#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
|
||||
{
|
||||
FAST486_GEN_REGS Register;
|
||||
|
|
|
@ -163,9 +163,9 @@ Fast486ReadLinearMemory(PFAST486_STATE State,
|
|||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
Page += FAST486_PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
|
||||
|
@ -230,9 +230,9 @@ Fast486WriteLinearMemory(PFAST486_STATE State,
|
|||
|
||||
for (Page = PAGE_ALIGN(LinearAddress);
|
||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
||||
Page += PAGE_SIZE)
|
||||
Page += FAST486_PAGE_SIZE)
|
||||
{
|
||||
ULONG PageOffset = 0, PageLength = PAGE_SIZE;
|
||||
ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
|
||||
|
||||
/* Get the table entry */
|
||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
|
||||
|
@ -522,6 +522,11 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
{
|
||||
/* Loading the code segment */
|
||||
|
||||
#ifndef FAST486_NO_PREFETCH
|
||||
/* Invalidate the prefetch */
|
||||
State->PrefetchValid = FALSE;
|
||||
#endif
|
||||
|
||||
if (GET_SEGMENT_INDEX(Selector) == 0)
|
||||
{
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
|
@ -641,21 +646,39 @@ Fast486FetchByte(PFAST486_STATE State,
|
|||
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)))
|
||||
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)))
|
||||
{
|
||||
/* Exception occurred during instruction fetch */
|
||||
return FALSE;
|
||||
*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 @@ Fast486FetchWord(PFAST486_STATE State,
|
|||
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)))
|
||||
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)))
|
||||
{
|
||||
/* Exception occurred during instruction fetch */
|
||||
return FALSE;
|
||||
*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 @@ Fast486FetchDword(PFAST486_STATE State,
|
|||
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)))
|
||||
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)))
|
||||
{
|
||||
/* Exception occurred during instruction fetch */
|
||||
return FALSE;
|
||||
*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 */
|
||||
|
|
|
@ -686,6 +686,11 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
|
|||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -4240,6 +4240,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
|
|||
{
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -2177,7 +2177,31 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
|
|||
/* 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue