mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 16:02:56 +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_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;
|
struct _FAST486_STATE;
|
||||||
typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE;
|
typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE;
|
||||||
|
|
||||||
|
@ -486,6 +498,11 @@ struct _FAST486_STATE
|
||||||
FAST486_INT_STATUS IntStatus;
|
FAST486_INT_STATUS IntStatus;
|
||||||
UCHAR PendingIntNum;
|
UCHAR PendingIntNum;
|
||||||
PULONG Tlb;
|
PULONG Tlb;
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
BOOLEAN PrefetchValid;
|
||||||
|
ULONG PrefetchAddress;
|
||||||
|
UCHAR PrefetchCache[FAST486_CACHE_SIZE];
|
||||||
|
#endif
|
||||||
#ifndef FAST486_NO_FPU
|
#ifndef FAST486_NO_FPU
|
||||||
FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS];
|
FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS];
|
||||||
FAST486_FPU_STATUS_REG FpuStatus;
|
FAST486_FPU_STATUS_REG FpuStatus;
|
||||||
|
|
|
@ -95,8 +95,40 @@ Fast486ReadMemory(PFAST486_STATE State,
|
||||||
/* Find the linear address */
|
/* Find the linear address */
|
||||||
LinearAddress = CachedDescriptor->Base + Offset;
|
LinearAddress = CachedDescriptor->Base + Offset;
|
||||||
|
|
||||||
/* Read from the linear address */
|
#ifndef FAST486_NO_PREFETCH
|
||||||
return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
|
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
|
BOOLEAN
|
||||||
|
@ -156,6 +188,18 @@ Fast486WriteMemory(PFAST486_STATE State,
|
||||||
/* Find the linear address */
|
/* Find the linear address */
|
||||||
LinearAddress = CachedDescriptor->Base + Offset;
|
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 */
|
/* Write to the linear address */
|
||||||
return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
|
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 GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
|
||||||
#define INVALID_TLB_FIELD 0xFFFFFFFF
|
#define INVALID_TLB_FIELD 0xFFFFFFFF
|
||||||
|
|
||||||
#ifndef PAGE_SIZE
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _FAST486_MOD_REG_RM
|
typedef struct _FAST486_MOD_REG_RM
|
||||||
{
|
{
|
||||||
FAST486_GEN_REGS Register;
|
FAST486_GEN_REGS Register;
|
||||||
|
|
|
@ -163,9 +163,9 @@ Fast486ReadLinearMemory(PFAST486_STATE State,
|
||||||
|
|
||||||
for (Page = PAGE_ALIGN(LinearAddress);
|
for (Page = PAGE_ALIGN(LinearAddress);
|
||||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
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 */
|
/* Get the table entry */
|
||||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
|
TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
|
||||||
|
@ -230,9 +230,9 @@ Fast486WriteLinearMemory(PFAST486_STATE State,
|
||||||
|
|
||||||
for (Page = PAGE_ALIGN(LinearAddress);
|
for (Page = PAGE_ALIGN(LinearAddress);
|
||||||
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
|
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 */
|
/* Get the table entry */
|
||||||
TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
|
TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
|
||||||
|
@ -522,6 +522,11 @@ Fast486LoadSegment(PFAST486_STATE State,
|
||||||
{
|
{
|
||||||
/* Loading the code segment */
|
/* Loading the code segment */
|
||||||
|
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
/* Invalidate the prefetch */
|
||||||
|
State->PrefetchValid = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (GET_SEGMENT_INDEX(Selector) == 0)
|
if (GET_SEGMENT_INDEX(Selector) == 0)
|
||||||
{
|
{
|
||||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||||
|
@ -641,21 +646,39 @@ Fast486FetchByte(PFAST486_STATE State,
|
||||||
PUCHAR Data)
|
PUCHAR Data)
|
||||||
{
|
{
|
||||||
PFAST486_SEG_REG CachedDescriptor;
|
PFAST486_SEG_REG CachedDescriptor;
|
||||||
|
ULONG Offset;
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
ULONG LinearAddress;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get the cached descriptor of CS */
|
/* Get the cached descriptor of CS */
|
||||||
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
||||||
|
|
||||||
/* Read from memory */
|
Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
|
||||||
if (!Fast486ReadMemory(State,
|
: State->InstPtr.LowWord;
|
||||||
FAST486_REG_CS,
|
#ifndef FAST486_NO_PREFETCH
|
||||||
(CachedDescriptor->Size) ? State->InstPtr.Long
|
LinearAddress = CachedDescriptor->Base + Offset;
|
||||||
: State->InstPtr.LowWord,
|
|
||||||
TRUE,
|
if (State->PrefetchValid
|
||||||
Data,
|
&& (LinearAddress >= State->PrefetchAddress)
|
||||||
sizeof(UCHAR)))
|
&& ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
|
||||||
{
|
{
|
||||||
/* Exception occurred during instruction fetch */
|
*Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
|
||||||
return FALSE;
|
}
|
||||||
|
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 */
|
/* Advance the instruction pointer */
|
||||||
|
@ -672,22 +695,41 @@ Fast486FetchWord(PFAST486_STATE State,
|
||||||
PUSHORT Data)
|
PUSHORT Data)
|
||||||
{
|
{
|
||||||
PFAST486_SEG_REG CachedDescriptor;
|
PFAST486_SEG_REG CachedDescriptor;
|
||||||
|
ULONG Offset;
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
ULONG LinearAddress;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get the cached descriptor of CS */
|
/* Get the cached descriptor of CS */
|
||||||
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
||||||
|
|
||||||
/* Read from memory */
|
Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
|
||||||
// FIXME: Fix byte order on big-endian machines
|
: State->InstPtr.LowWord;
|
||||||
if (!Fast486ReadMemory(State,
|
|
||||||
FAST486_REG_CS,
|
#ifndef FAST486_NO_PREFETCH
|
||||||
(CachedDescriptor->Size) ? State->InstPtr.Long
|
LinearAddress = CachedDescriptor->Base + Offset;
|
||||||
: State->InstPtr.LowWord,
|
|
||||||
TRUE,
|
if (State->PrefetchValid
|
||||||
Data,
|
&& (LinearAddress >= State->PrefetchAddress)
|
||||||
sizeof(USHORT)))
|
&& ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
|
||||||
{
|
{
|
||||||
/* Exception occurred during instruction fetch */
|
*Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
|
||||||
return FALSE;
|
}
|
||||||
|
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 */
|
/* Advance the instruction pointer */
|
||||||
|
@ -704,22 +746,41 @@ Fast486FetchDword(PFAST486_STATE State,
|
||||||
PULONG Data)
|
PULONG Data)
|
||||||
{
|
{
|
||||||
PFAST486_SEG_REG CachedDescriptor;
|
PFAST486_SEG_REG CachedDescriptor;
|
||||||
|
ULONG Offset;
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
ULONG LinearAddress;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get the cached descriptor of CS */
|
/* Get the cached descriptor of CS */
|
||||||
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
|
||||||
|
|
||||||
/* Read from memory */
|
Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
|
||||||
// FIXME: Fix byte order on big-endian machines
|
: State->InstPtr.LowWord;
|
||||||
if (!Fast486ReadMemory(State,
|
|
||||||
FAST486_REG_CS,
|
#ifndef FAST486_NO_PREFETCH
|
||||||
(CachedDescriptor->Size) ? State->InstPtr.Long
|
LinearAddress = CachedDescriptor->Base + Offset;
|
||||||
: State->InstPtr.LowWord,
|
|
||||||
TRUE,
|
if (State->PrefetchValid
|
||||||
Data,
|
&& (LinearAddress >= State->PrefetchAddress)
|
||||||
sizeof(ULONG)))
|
&& ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
|
||||||
{
|
{
|
||||||
/* Exception occurred during instruction fetch */
|
*Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
|
||||||
return FALSE;
|
}
|
||||||
|
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 */
|
/* 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 */
|
/* Load a value to the control register */
|
||||||
State->ControlRegisters[ModRegRm.Register] = Value;
|
State->ControlRegisters[ModRegRm.Register] = Value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4240,6 +4240,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
|
||||||
{
|
{
|
||||||
UCHAR BopCode;
|
UCHAR BopCode;
|
||||||
|
|
||||||
|
#ifndef FAST486_NO_PREFETCH
|
||||||
|
/* Invalidate the prefetch since BOP handlers can alter the memory */
|
||||||
|
State->PrefetchValid = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Fetch the BOP code */
|
/* Fetch the BOP code */
|
||||||
if (!Fast486FetchByte(State, &BopCode))
|
if (!Fast486FetchByte(State, &BopCode))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2177,7 +2177,31 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
|
||||||
/* INVLPG */
|
/* INVLPG */
|
||||||
case 7:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue