home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 2
/
crawlyvol2.bin
/
program
/
c
/
itf_src
/
page.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-22
|
5KB
|
228 lines
/*
** File: page.c
**
** (C)opyright 1987-1992 InfoTaskforce.
*/
#include "infocom.h"
/*
** Page Table Structure Definition ( see "infocom.h" ).
**
**
** typedef struct
** {
** word page ;
** long_word count ;
** word padding ;
** } page_table_t ;
**
** typedef page_table_t *page_table_ptr ;
**
**
** Field Usage:
**
** page : Number of the page occupying this page table block.
** count : Time stamp - used by the LRU algorithm.
** padding : This field was inserted to make the size of the
** page_table_t structure a power of 2 - thus easier
** for the compiler to optimise.
*/
/*
** Page Table Global Variables.
**
** Many of these variables must retain their values
** between invocations of the paging functions.
**
** These are:
**
** tick : Current Tick Count - used to timestamp new table
** entries.
** prog_page : Number of the page containing the currently
** executing opcode.
** MRU_page : Number of the "Most Recently Used" page.
** MRU_block_ptr : Pointer to the page table block containing the
** "Most Recently Used" page.
** page_strt : Pointer to the first page table block.
** MRU : Pointer to the page table entry of the
** "Most Recently Used" page.
** page_entry : Pointer to the page table entry of the page
** containing the currently executing opcode. This
** is a NULL pointer if the current opcode came
** from a resident block.
** strt_page_table : The Page Table Entry Array.
**
*/
long_word tick = 0 ;
word prog_page = EMPTY_PAGE ;
word MRU_page = EMPTY_PAGE ;
byte_ptr MRU_block_ptr = (byte_ptr)0 ;
byte_ptr page_strt = (byte_ptr)0 ;
page_table_ptr MRU = (page_table_ptr)0 ;
page_table_ptr page_entry = (page_table_ptr)0 ;
page_table_ptr strt_page_table = (page_table_ptr)0 ;
Void
init_page ( ptr,num_pages )
byte_ptr ptr ;
word num_pages ;
{
extern byte_ptr base_ptr ;
page_table_ptr page_ptr ;
page_strt = ptr ;
page_ptr = strt_page_table ;
while ( num_pages-- )
{
page_ptr -> page = EMPTY_PAGE ;
page_ptr -> count = 0 ;
++page_ptr ;
}
/*
** Mark end of Page Table
*/
page_ptr -> page = END_OF_TABLE ;
page_ptr -> count = 0 ;
}
byte_ptr
fetch_page ( new_page )
word new_page ;
{
page_table_ptr ptr ;
boolean found ;
if ( MRU_page != new_page )
{
found = FALSE ;
MRU_page = new_page ;
++tick ;
ptr = strt_page_table ;
while (( ptr -> page != END_OF_TABLE ) && ( found == FALSE ))
{
if ( ptr -> page == new_page )
{
if ( prog_page != new_page )
ptr -> count = tick ;
MRU = ptr ;
MRU_block_ptr = page_strt +
((signed_long)(MRU - strt_page_table) * BLOCK_SIZE) ;
found = TRUE ;
}
else
++ptr ;
}
if ( found == FALSE )
{
MRU = get_LRU_page () ;
MRU -> page = MRU_page ;
MRU -> count = tick ;
MRU_block_ptr = page_strt +
((signed_long)(MRU - strt_page_table) * BLOCK_SIZE) ;
load_page ( MRU_page,1,MRU_block_ptr ) ;
}
}
return ( MRU_block_ptr ) ;
}
page_table_ptr
get_LRU_page ()
{
long_word test ;
page_table_ptr LRU ;
page_table_ptr ptr ;
ptr = strt_page_table ;
test = MAX_COUNT ;
while ( ptr -> page != END_OF_TABLE )
{
if ( test >= ptr -> count )
{
test = ptr -> count ;
LRU = ptr ;
}
++ptr ;
}
return ( LRU ) ;
}
Void
fix_pc ()
{
extern word pc_page ;
extern word pc_offset ;
extern word resident_blocks ;
extern byte_ptr prog_block_ptr ;
extern byte_ptr pc ;
extern byte_ptr base_ptr ;
/*
** Note:
** 'pc_page' is unsigned and can have any value from $0000 to $FFFF.
** The high bit of 'pc_offset' is actually a sign bit.
*/
/*
** The old way of generating pc_page and pc_offset (VERSIONS 1, 2 & 3):
**
** signed_long ipc ;
**
** ipc = ((signed_long)pc_page * BLOCK_SIZE) + (signed_word)pc_offset ;
** pc_page = ipc / BLOCK_SIZE ;
** pc_offset = ipc % BLOCK_SIZE ;
**
** The new way of generating pc_page and pc_offset (VERSIONS 4 & 5):
**
** signed_word offset ;
**
** offset = (signed_word)pc_offset / (int)BLOCK_SIZE ;
** if ((signed_word)pc_offset < 0 )
** --offset ;
** if ( offset )
** pc_page += offset ;
** pc_offset %= BLOCK_SIZE ;
**
** This is a bit messy. The old way is still being used because some
** compiler libraries do not correctly handle the modulo operation (%)
** if the arguments are negative.
**
** Note: In the line:
** offset = (signed_word)pc_offset / (int)BLOCK_SIZE ;
** ^
** |
** the above casting is required by the LSC Compiler in order for
** signed division to occur.
*/
signed_long ipc ;
ipc = ( (signed_long)pc_page * BLOCK_SIZE ) + (signed_word)pc_offset ;
pc_page = ipc / (int)BLOCK_SIZE ;
pc_offset = ipc % (int)BLOCK_SIZE ;
if ( prog_page != pc_page )
{
prog_page = pc_page ;
if ( page_entry != (page_table_ptr)0 )
page_entry -> count = tick ;
if ( pc_page < resident_blocks )
{
prog_block_ptr = base_ptr + ((signed_long)pc_page * BLOCK_SIZE) ;
page_entry = (page_table_ptr)0 ;
}
else
{
prog_block_ptr = fetch_page ( pc_page ) ;
page_entry = MRU ;
page_entry -> count = MAX_COUNT ;
}
}
pc = prog_block_ptr + (signed_word)pc_offset ;
}