[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_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;

View file

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

View file

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

View file

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

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 */ /* Load a value to the control register */
State->ControlRegisters[ModRegRm.Register] = Value; State->ControlRegisters[ModRegRm.Register] = Value;
} }

View file

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

View file

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