209 lines
7.7 KiB
C++
209 lines
7.7 KiB
C++
// machine.h
|
|
// Data structures for simulating the execution of user programs
|
|
// running on top of Nachos.
|
|
//
|
|
// User programs are loaded into "mainMemory"; to Nachos,
|
|
// this looks just like an array of bytes. Of course, the Nachos
|
|
// kernel is in memory too -- but as in most machines these days,
|
|
// the kernel is loaded into a separate memory region from user
|
|
// programs, and accesses to kernel memory are not translated or paged.
|
|
//
|
|
// In Nachos, user programs are executed one instruction at a time,
|
|
// by the simulator. Each memory reference is translated, checked
|
|
// for errors, etc.
|
|
//
|
|
// DO NOT CHANGE EXCEPT AS NOTED BELOW -- part of the machine emulation
|
|
//
|
|
// Copyright (c) 1992-1996 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.
|
|
|
|
#ifndef MACHINE_H
|
|
#define MACHINE_H
|
|
|
|
#include "copyright.h"
|
|
#include "utility.h"
|
|
#include "translate.h"
|
|
|
|
// Definitions related to the size, and format of user memory
|
|
|
|
const int PageSize = 128; // set the page size equal to
|
|
// the disk sector size, for simplicity
|
|
|
|
//
|
|
// You are allowed to change this value.
|
|
// Doing so will change the number of pages of physical memory
|
|
// available on the simulated machine.
|
|
//
|
|
const int NumPhysPages = 128;
|
|
|
|
const int MemorySize = (NumPhysPages * PageSize);
|
|
const int TLBSize = 4; // if there is a TLB, make it small
|
|
|
|
enum ExceptionType { NoException, // Everything ok!
|
|
SyscallException, // A program executed a system call.
|
|
PageFaultException, // No valid translation found
|
|
ReadOnlyException, // Write attempted to page marked
|
|
// "read-only"
|
|
BusErrorException, // Translation resulted in an
|
|
// invalid physical address
|
|
AddressErrorException, // Unaligned reference or one that
|
|
// was beyond the end of the
|
|
// address space
|
|
OverflowException, // Integer overflow in add or sub.
|
|
IllegalInstrException, // Unimplemented or reserved instr.
|
|
|
|
MemoryLimitException, // Insufficient memory
|
|
|
|
NumExceptionTypes
|
|
};
|
|
|
|
// User program CPU state. The full set of MIPS registers, plus a few
|
|
// more because we need to be able to start/stop a user program between
|
|
// any two instructions (thus we need to keep track of things like load
|
|
// delay slots, etc.)
|
|
|
|
#define StackReg 29 // User's stack pointer
|
|
#define RetAddrReg 31 // Holds return address for procedure calls
|
|
#define NumGPRegs 32 // 32 general purpose registers on MIPS
|
|
#define HiReg 32 // Double register to hold multiply result
|
|
#define LoReg 33
|
|
#define PCReg 34 // Current program counter
|
|
#define NextPCReg 35 // Next program counter (for branch delay)
|
|
#define PrevPCReg 36 // Previous program counter (for debugging)
|
|
#define LoadReg 37 // The register target of a delayed load.
|
|
#define LoadValueReg 38 // The value to be loaded by a delayed load.
|
|
#define BadVAddrReg 39 // The failing virtual address on an exception
|
|
|
|
#define NumTotalRegs 40
|
|
|
|
// The following class defines the simulated host workstation hardware, as
|
|
// seen by user programs -- the CPU registers, main memory, etc.
|
|
// User programs shouldn't be able to tell that they are running on our
|
|
// simulator or on the real hardware, except
|
|
// we don't support floating point instructions
|
|
// the system call interface to Nachos is not the same as UNIX
|
|
// (10 system calls in Nachos vs. 200 in UNIX!)
|
|
// If we were to implement more of the UNIX system calls, we ought to be
|
|
// able to run Nachos on top of Nachos!
|
|
//
|
|
// The procedures in this class are defined in machine.cc, mipssim.cc, and
|
|
// translate.cc.
|
|
|
|
class Instruction;
|
|
class Interrupt;
|
|
|
|
class Machine {
|
|
public:
|
|
Machine(bool debug); // Initialize the simulation of the hardware
|
|
// for running user programs
|
|
~Machine(); // De-allocate the data structures
|
|
|
|
// Routines callable by the Nachos kernel
|
|
void Run(); // Run a user program
|
|
|
|
int ReadRegister(int num); // read the contents of a CPU register
|
|
|
|
void WriteRegister(int num, int value);
|
|
// store a value into a CPU register
|
|
|
|
// Data structures accessible to the Nachos kernel -- main memory and the
|
|
// page table/TLB.
|
|
//
|
|
// Note that *all* communication between the user program and the kernel
|
|
// are in terms of these data structures (plus the CPU registers).
|
|
|
|
char *mainMemory; // physical memory to store user program,
|
|
// code and data, while executing
|
|
|
|
// NOTE: the hardware translation of virtual addresses in the user program
|
|
// to physical addresses (relative to the beginning of "mainMemory")
|
|
// can be controlled by one of:
|
|
// a traditional linear page table
|
|
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
|
// mappings of virtual page #'s to physical page #'s
|
|
//
|
|
// If "tlb" is NULL, the linear page table is used
|
|
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
|
// the contents of the TLB. But the kernel can use any data structure
|
|
// it wants (eg, segmented paging) for handling TLB cache misses.
|
|
//
|
|
// For simplicity, both the page table pointer and the TLB pointer are
|
|
// public. However, while there can be multiple page tables (one per address
|
|
// space, stored in memory), there is only one TLB (implemented in hardware).
|
|
// Thus the TLB pointer should be considered as *read-only*, although
|
|
// the contents of the TLB are free to be modified by the kernel software.
|
|
|
|
TranslationEntry *tlb; // this pointer should be considered
|
|
// "read-only" to Nachos kernel code
|
|
|
|
TranslationEntry *pageTable;
|
|
unsigned int pageTableSize;
|
|
|
|
bool ReadMem(int addr, int size, int* value);
|
|
bool WriteMem(int addr, int size, int value);
|
|
// Read or write 1, 2, or 4 bytes of virtual
|
|
// memory (at addr). Return FALSE if a
|
|
// correct translation couldn't be found.
|
|
private:
|
|
|
|
// Routines internal to the machine simulation -- DO NOT call these directly
|
|
void DelayedLoad(int nextReg, int nextVal);
|
|
// Do a pending delayed load (modifying a reg)
|
|
|
|
void OneInstruction(Instruction *instr);
|
|
// Run one instruction of a user program.
|
|
|
|
|
|
|
|
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
|
// Translate an address, and check for
|
|
// alignment. Set the use and dirty bits in
|
|
// the translation entry appropriately,
|
|
// and return an exception code if the
|
|
// translation couldn't be completed.
|
|
|
|
void RaiseException(ExceptionType which, int badVAddr);
|
|
// Trap to the Nachos kernel, because of a
|
|
// system call or other exception.
|
|
|
|
void Debugger(); // invoke the user program debugger
|
|
void DumpState(); // print the user CPU and memory state
|
|
|
|
|
|
// Internal data structures
|
|
|
|
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
|
|
|
bool singleStep; // drop back into the debugger after each
|
|
// simulated instruction
|
|
int runUntilTime; // drop back into the debugger when simulated
|
|
// time reaches this value
|
|
|
|
friend class Interrupt; // calls DelayedLoad()
|
|
};
|
|
|
|
extern void ExceptionHandler(ExceptionType which);
|
|
// Entry point into Nachos for handling
|
|
// user system calls and exceptions
|
|
// Defined in exception.cc
|
|
|
|
|
|
// Routines for converting Words and Short Words to and from the
|
|
// simulated machine's format of little endian. If the host machine
|
|
// is little endian (DEC and Intel), these end up being NOPs.
|
|
//
|
|
// What is stored in each format:
|
|
// host byte ordering:
|
|
// kernel data structures
|
|
// user registers
|
|
// simulated machine byte ordering:
|
|
// contents of main memory
|
|
|
|
unsigned int WordToHost(unsigned int word);
|
|
unsigned short ShortToHost(unsigned short shortword);
|
|
unsigned int WordToMachine(unsigned int word);
|
|
unsigned short ShortToMachine(unsigned short shortword);
|
|
|
|
#endif // MACHINE_H
|