home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
toy_os
/
part02
/
memory.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-05
|
11KB
|
364 lines
// This may look like C code, but it is really -*- C++ -*-
/*
************************************************************************
*
* UNT Virtual Machine
* Handle real and virtual memory requests and the "drum"
*
* One part of the present file implements the Mememory Management Unit,
* a piece of hardware located between the CPU and the bus and responsible
* for translation of virtual addresses into the "real" ones.
* The other part of the present file emulates the physical memory,
* which is connected to the bus and responds to read/write word
* requests posted on the bus. The drum is a secondary memory device
* which is hooked to the physical memory and can transmit sectors
* of the drum to/from pages of the memory. The drum is assummed to be
* very fast, so all the drum operations can be thought of as "instant"
* ones.
*
************************************************************************
*/
#pragma implementation
#include "hardware.h"
#include "myenv.h"
#include <std.h>
#include <sys/file.h>
/*
*========================================================================
* Virtual memory handling
*/
MMUContext::MMUContext(void)
{
page_table_addr = 0;
page_table_len = 0;
enabled_address_translation = 0;
}
MemoryManagementUnit::MemoryManagementUnit(Memory& phys_memory)
: memory(phys_memory)
{
*(Word *)¤t_VA = 0;
clear_error();
};
// Perform dump of the translation tables
void MemoryManagementUnit::dump(void) const
{
if(!enabled_address_translation)
{
message("\nVirtual memory is disabled\n");
return;
}
message("\nProcess virtual space is %d pages long\n",page_table_len);
message("\nAddress range\tAccess\tMapped to \tWritten\tReferenced\n");
register int i;
for(i=0; i<page_table_len; i++)
{
const PageTableEntry& pte =
*(PageTableEntry*)&memory[page_table_addr+i].contents;
if( !(pte.any_access || pte.read_only || pte.exec_only) )
continue; // Page isn't allocated
message("%06o-%06o \t %s\t",Memory::pagesize*i,Memory::pagesize*(i+1)-1,
pte.exec_only ? "Exec" : pte.read_only ? "Read" : "Any");
if( pte.valid )
message("%06o ",pte.phys_page_no*Memory::pagesize);
else
message("Not Mapped ");
message("\t %s\t %s\n",pte.was_written ? "Y" : "N",
pte.was_ref ? "Y" : "N");
}
message("\n");
}
Word MemoryManagementUnit::fetch(const Address addr)
{
Address phys_addr;
if(enabled_address_translation)
{
*(Address *)¤t_VA = addr;
if(current_VA.page_no >= page_table_len)
mem_error = WrongVPageNo;
else if( memory[page_table_addr+current_VA.page_no].out_of_range )
mem_error = WrongPageTable;
if( mem_error )
return 0;
PageTableEntry& pte = *(PageTableEntry *)&memory[
page_table_addr+current_VA.page_no].contents;
if(!pte.any_access && !pte.read_only && !pte.exec_only )
mem_error = NoAccess;
else if( !pte.valid )
mem_error = PageInvalidated;
else
current_VA.page_no = pte.phys_page_no,
pte.was_ref = 1;
if( mem_error )
return 0;
phys_addr = *(Address *)¤t_VA;
}
else
phys_addr = addr;
Memory::MemoryAnswer result = memory[phys_addr];
if(result.out_of_range)
{
mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
return 0;
}
return result.contents;
}
Word MemoryManagementUnit::get(const Address addr)
{
Address phys_addr;
if(enabled_address_translation)
{
*(Address *)¤t_VA = addr;
if(current_VA.page_no >= page_table_len)
mem_error = WrongVPageNo;
else if( memory[page_table_addr+current_VA.page_no].out_of_range )
mem_error = WrongPageTable;
if( mem_error )
return 0;
PageTableEntry& pte = *(PageTableEntry *)&memory[
page_table_addr+current_VA.page_no].contents;
if(!pte.any_access && !pte.read_only && !pte.exec_only )
mem_error = NoAccess;
else if( pte.exec_only )
mem_error = ExecOnly;
else if( !pte.valid )
mem_error = PageInvalidated;
else
current_VA.page_no = pte.phys_page_no,
pte.was_ref = 1;
if( mem_error )
return 0;
phys_addr = *(Address *)¤t_VA;
}
else
phys_addr = addr;
Memory::MemoryAnswer result = memory[phys_addr];
if(result.out_of_range)
{
mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
return 0;
}
return result.contents;
}
void MemoryManagementUnit::put(const Address addr,const Word data)
{
Address phys_addr;
if(enabled_address_translation)
{
*(Address *)¤t_VA = addr;
if(current_VA.page_no >= page_table_len)
mem_error = WrongVPageNo;
else if( memory[page_table_addr+current_VA.page_no].out_of_range )
mem_error = WrongPageTable;
if( mem_error )
return;
PageTableEntry& pte = *(PageTableEntry *)&memory[
page_table_addr+current_VA.page_no].contents;
if(!pte.any_access && !pte.read_only && !pte.exec_only )
mem_error = NoAccess;
else if( pte.read_only )
mem_error = ReadOnly;
else if( pte.exec_only )
mem_error = ExecOnly;
else if( !pte.valid )
mem_error = PageInvalidated;
else
current_VA.page_no = pte.phys_page_no,
pte.was_ref = 1,
pte.was_written = 1;
if( mem_error )
return;
phys_addr = *(Address *)¤t_VA;
}
else
phys_addr = addr;
Memory::MemoryAnswer result = memory[phys_addr];
if(result.out_of_range)
mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
else
result.contents = data;
}
/*
*========================================================================
* Physical Memory handling
*/
/*
*------------------------------------------------------------------------
* Initialization
*/
Memory::Memory(void)
: no_pages((hiaddr+1)/pagesize)
{
memset(array,0,sizeof(array)); // Clear the memory
drum_fh = -1;
}
/*
*------------------------------------------------------------------------
* Basic memory handling functions
*/
#if 0
struct MemoryAnswer Memory::operator [] (const Address addr) //return ans
{
if( addr > hiaddr )
ans.out_of_range = 1, contents = array[0];
else
ans.out_of_range = 0, contents = array[addr];
}
#endif
/*
*------------------------------------------------------------------------
* Memory Dump
* Memory contents is printed in rows of 8 words in each.
* Rows of zeros are skipped. Contents of a memory word is printed in octal.
*/
void Memory::dump(const Address from_addr,const Address to_addr)
{
register Address first_addr = from_addr & ~7; // Adjust to the 8 word
register Address last_addr = to_addr & ~7 + 8;// boundary
if( last_addr == 0 || last_addr > hiaddr+1 )
last_addr = hiaddr+1;
begin_printing();
message("\n\n%s\n\n\t\t\tVM UNT Memory Dump\n\n",_Minuses);
for(; first_addr < last_addr; first_addr += 8)
{
register int i;
int skip = 1;
for(i=first_addr; skip && i<first_addr+8; i++)
if( array[i] != 0 )
skip = 0;
if( skip )
continue; // Skip a line of zeros
message("%4o: ",first_addr);
for(i=first_addr; i<first_addr+8; i++)
message(" %06o ",array[i]);
message("\n");
}
end_printing();
}
/*
*------------------------------------------------------------------------
* Drum operations
* Note, that the program to be loaded from the drum into the main memory
* is written started from the 1st drum sector. The 0th drum sector contains
* the header, starting address of the program, VM memory page to load
* the program at, and the size of the program in pages (i.e. in drum sectors).
*/
void Memory::drum_open(const char * file_name)
{
drum_fh = open(file_name,O_RDWR,0);
if( drum_fh < 0 )
perror("Drum file opening error"),
_error("Failure to open the drum due to the reason above");
single_message("Drum file '%s' has been opened",file_name);
}
// Read one 32 word page from drum
// sector to memory physical page
// 'pageframeno'
void Memory::drum_read(const int sector_addr, const int pageframeno)
{
single_message("DRUM: reading from sector %d in memory page %d",
sector_addr,pageframeno);
if( sector_addr < 0 || sector_addr >= no_drum_sectors )
_error("FATAL: drum sector %d is out of range [0,%d]",
sector_addr,no_drum_sectors-1);
if( pageframeno < 0 || pageframeno >= no_pages )
_error("FATAL on drum operation: page frame no %d is out of range [0,%d]",
pageframeno,no_pages-1);
if( lseek(drum_fh,sector_addr*pagesize*sizeof(Word),0) < 0 )
perror("FATAL: drum seek failed"),
_error("System crashes due to the reason above");
if( read(drum_fh,&array[pageframeno*pagesize],pagesize*sizeof(Word))
!= pagesize*sizeof(Word) )
perror("FATAL: drum read failed"),
_error("System crashes due to the reason above");
}
// Write a page of physical memory into
// the drum
void Memory::drum_write(const int pageframeno,const int sector_addr)
{
single_message("DRUM: writing to sector %d from memory page %d",
sector_addr,pageframeno);
if( sector_addr < 0 || sector_addr >= no_drum_sectors )
_error("FATAL: drum sector %d is out of range [0,%d]",
sector_addr,no_drum_sectors-1);
if( pageframeno < 0 || pageframeno >= no_pages )
_error("FATAL on drum operation: page frame no %d is out of range [0,%d]",
pageframeno,no_pages-1);
if( lseek(drum_fh,sector_addr*pagesize*sizeof(Word),0) < 0 )
perror("FATAL: drum seek failed"),
_error("System crashes due to the reason above");
if( write(drum_fh,&array[pageframeno*pagesize],pagesize*sizeof(Word))
!= pagesize*sizeof(Word) )
perror("FATAL: drum write failed"),
_error("System crashes due to the reason above");
}
// Load a program from a drum to
// memory starting at physical page
// 'pageframeno'
Address Memory::drum_load(const int pageframeno)
{
if( pageframeno < 0 || pageframeno >= no_pages )
_error("FATAL on loading operation: "
"page frame no %d is out of range [0,%d]",
pageframeno,no_pages-1);
struct AbsExecHeader { // Header of the executable abs file
Word start_addr; // Starting address
Word load_page_no; // VM page to load the program
Word size; // in pages
} header;
if( lseek(drum_fh,0,0) < 0 ) // Read the drum header
perror("FATAL: drum seek failed"),
_error("System crashes due to the reason above");
if( read(drum_fh,&header,sizeof(header)) != sizeof(header) )
perror("FATAL: drum read failed"),
_error("System crashes due to the reason above");
single_message("Loading a program (size %d, start addr %06o) on %d-th page",
header.size*pagesize,header.start_addr,header.load_page_no);
register int i;
for(i=0; i<header.size; i++)
drum_read(1+i,header.load_page_no+i);
return header.start_addr;
}