Initial version
This commit is contained in:
commit
6f405265a5
102 changed files with 14486 additions and 0 deletions
267
code/machine/translate.cc
Normal file
267
code/machine/translate.cc
Normal file
|
@ -0,0 +1,267 @@
|
|||
// translate.cc
|
||||
// Routines to translate virtual addresses to physical addresses.
|
||||
// Software sets up a table of legal translations. We look up
|
||||
// in the table on every memory reference to find the true physical
|
||||
// memory location.
|
||||
//
|
||||
// Two types of translation are supported here.
|
||||
//
|
||||
// Linear page table -- the virtual page # is used as an index
|
||||
// into the table, to find the physical page #.
|
||||
//
|
||||
// Translation lookaside buffer -- associative lookup in the table
|
||||
// to find an entry with the same virtual page #. If found,
|
||||
// this entry is used for the translation.
|
||||
// If not, it traps to software with an exception.
|
||||
//
|
||||
// In practice, the TLB is much smaller than the amount of physical
|
||||
// memory (16 entries is common on a machine that has 1000's of
|
||||
// pages). Thus, there must also be a backup translation scheme
|
||||
// (such as page tables), but the hardware doesn't need to know
|
||||
// anything at all about that.
|
||||
//
|
||||
// Note that the contents of the TLB are specific to an address space.
|
||||
// If the address space changes, so does the contents of the TLB!
|
||||
//
|
||||
// DO NOT CHANGE -- part of the machine emulation
|
||||
//
|
||||
// Copyright (c) 1992-1993 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#include "copyright.h"
|
||||
#include "machine.h"
|
||||
#include "addrspace.h"
|
||||
#include "system.h"
|
||||
|
||||
// Routines for converting Words and Short Words to and from the
|
||||
// simulated machine's format of little endian. These end up
|
||||
// being NOPs when the host machine is also little endian (DEC and Intel).
|
||||
|
||||
unsigned int
|
||||
WordToHost(unsigned int word) {
|
||||
#ifdef HOST_IS_BIG_ENDIAN
|
||||
register unsigned long result;
|
||||
result = (word >> 24) & 0x000000ff;
|
||||
result |= (word >> 8) & 0x0000ff00;
|
||||
result |= (word << 8) & 0x00ff0000;
|
||||
result |= (word << 24) & 0xff000000;
|
||||
return result;
|
||||
#else
|
||||
return word;
|
||||
#endif /* HOST_IS_BIG_ENDIAN */
|
||||
}
|
||||
|
||||
unsigned short
|
||||
ShortToHost(unsigned short shortword) {
|
||||
#ifdef HOST_IS_BIG_ENDIAN
|
||||
register unsigned short result;
|
||||
result = (shortword << 8) & 0xff00;
|
||||
result |= (shortword >> 8) & 0x00ff;
|
||||
return result;
|
||||
#else
|
||||
return shortword;
|
||||
#endif /* HOST_IS_BIG_ENDIAN */
|
||||
}
|
||||
|
||||
unsigned int
|
||||
WordToMachine(unsigned int word) { return WordToHost(word); }
|
||||
|
||||
unsigned short
|
||||
ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Machine::ReadMem
|
||||
// Read "size" (1, 2, or 4) bytes of virtual memory at "addr" into
|
||||
// the location pointed to by "value".
|
||||
//
|
||||
// Returns FALSE if the translation step from virtual to physical memory
|
||||
// failed.
|
||||
//
|
||||
// "addr" -- the virtual address to read from
|
||||
// "size" -- the number of bytes to read (1, 2, or 4)
|
||||
// "value" -- the place to write the result
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
Machine::ReadMem(int addr, int size, int *value, bool debug)
|
||||
{
|
||||
int data;
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
if (debug)
|
||||
DEBUG('a', "Reading VA 0x%x, size %d\n", addr, size);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, FALSE, debug);
|
||||
if (exception != NoException) {
|
||||
machine->RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = machine->mainMemory[physicalAddress];
|
||||
*value = data;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = *(unsigned short *) &machine->mainMemory[physicalAddress];
|
||||
*value = ShortToHost(data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
data = *(unsigned int *) &machine->mainMemory[physicalAddress];
|
||||
*value = WordToHost(data);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
DEBUG('a', "\tvalue read = %8.8x\n", *value);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool
|
||||
Machine::ReadMem(int addr, int size, int *value)
|
||||
{
|
||||
return ReadMem(addr, size, value, TRUE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Machine::WriteMem
|
||||
// Write "size" (1, 2, or 4) bytes of the contents of "value" into
|
||||
// virtual memory at location "addr".
|
||||
//
|
||||
// Returns FALSE if the translation step from virtual to physical memory
|
||||
// failed.
|
||||
//
|
||||
// "addr" -- the virtual address to write to
|
||||
// "size" -- the number of bytes to be written (1, 2, or 4)
|
||||
// "value" -- the data to be written
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
Machine::WriteMem(int addr, int size, int value)
|
||||
{
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
DEBUG('a', "Writing VA 0x%x, size %d, value 0x%x\n", addr, size, value);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, TRUE, TRUE);
|
||||
if (exception != NoException) {
|
||||
machine->RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
machine->mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*(unsigned short *) &machine->mainMemory[physicalAddress]
|
||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(unsigned int *) &machine->mainMemory[physicalAddress]
|
||||
= WordToMachine((unsigned int) value);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Machine::Translate
|
||||
// Translate a virtual address into a physical address, using
|
||||
// either a page table or a TLB. Check for alignment and all sorts
|
||||
// of other errors, and if everything is ok, set the use/dirty bits in
|
||||
// the translation table entry, and store the translated physical
|
||||
// address in "physAddr". If there was an error, returns the type
|
||||
// of the exception.
|
||||
//
|
||||
// "virtAddr" -- the virtual address to translate
|
||||
// "physAddr" -- the place to store the physical address
|
||||
// "size" -- the amount of memory being read or written
|
||||
// "writing" -- if TRUE, check the "read-only" bit in the TLB
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
ExceptionType
|
||||
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing, bool debug)
|
||||
{
|
||||
int i;
|
||||
unsigned int vpn, offset;
|
||||
TranslationEntry *entry;
|
||||
unsigned int pageFrame;
|
||||
|
||||
if (debug) DEBUG('a', "\tTranslate 0x%x, %s: ", virtAddr, writing ? "write" : "read");
|
||||
|
||||
// check for alignment errors
|
||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||
if (debug) DEBUG('a', "alignment problem at %d, size %d!\n", virtAddr, size);
|
||||
return AddressErrorException;
|
||||
}
|
||||
|
||||
// we must have either a TLB or a page table, but not both!
|
||||
ASSERT(tlb == NULL || currentPageTable == NULL);
|
||||
ASSERT(tlb != NULL || currentPageTable != NULL);
|
||||
|
||||
// calculate the virtual page number, and offset within the page,
|
||||
// from the virtual address
|
||||
vpn = (unsigned) virtAddr / PageSize;
|
||||
offset = (unsigned) virtAddr % PageSize;
|
||||
|
||||
if (tlb == NULL) { // => page table => vpn is index into table
|
||||
if (vpn >= currentPageTableSize) {
|
||||
if (debug) DEBUG('a', "virtual page # %d too large for page table size %d!\n",
|
||||
virtAddr, currentPageTableSize);
|
||||
return AddressErrorException;
|
||||
} else if (!currentPageTable[vpn].valid) {
|
||||
if (debug) DEBUG('a', "virtual page # %d : page %d is invalid !\n",
|
||||
virtAddr, vpn);
|
||||
return PageFaultException;
|
||||
}
|
||||
entry = ¤tPageTable[vpn];
|
||||
} else {
|
||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||
if (tlb[i].valid && (tlb[i].virtualPage == vpn)) {
|
||||
entry = &tlb[i]; // FOUND!
|
||||
break;
|
||||
}
|
||||
if (entry == NULL) { // not found
|
||||
if (debug) DEBUG('a', "*** no valid TLB entry found for this virtual page!\n");
|
||||
return PageFaultException; // really, this is a TLB fault,
|
||||
// the page may be in memory,
|
||||
// but not in the TLB
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||
if (tlb == NULL) {
|
||||
if (debug) DEBUG('a', "%d mapped read-only in page table!\n", virtAddr);
|
||||
} else {
|
||||
if (debug) DEBUG('a', "%d mapped read-only at %d in TLB!\n", virtAddr, i);
|
||||
}
|
||||
return ReadOnlyException;
|
||||
}
|
||||
pageFrame = entry->physicalPage;
|
||||
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pageFrame >= NumPhysPages) {
|
||||
if (debug) DEBUG('a', "*** frame %d > %d!\n", pageFrame, NumPhysPages);
|
||||
return BusErrorException;
|
||||
}
|
||||
entry->use = TRUE; // set the use, dirty bits
|
||||
if (writing)
|
||||
entry->dirty = TRUE;
|
||||
*physAddr = pageFrame * PageSize + offset;
|
||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||
if (debug) DEBUG('a', "phys addr = 0x%x\n", *physAddr);
|
||||
return NoException;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue