[FAST486]

Implement an (optional) instruction prefetch cache.
Implement the INVLPG instruction.


svn path=/trunk/; revision=65035
This commit is contained in:
Aleksandar Andrejevic 2014-10-26 23:37:54 +00:00
parent dd58a72a8b
commit bc64e37fd1
7 changed files with 195 additions and 43 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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 */

View file

@ -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;
}

View file

@ -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))
{

View file

@ -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;
}