mmup.cc

//*************************************************************************
//  MODULE : MMUP - A very simple Memory Manager of the Partitioned type  *
//  AUTHOR : Ron Chernich                                                 *
//  PURPOSE: An RCOS Memory Management Unit device driver which simply	  *
//	     partitions main store into fixed size blocks.  Since all	  *
//	     calls to the MMU are messages, the strategy is totally up to *
//	     the driver which can be as simple or complex as you like!	  *
//  HISTORY:                                                              *
//    22-APR-93	First version						  *
//*************************************************************************


#include 
#include 
#include "mmu.hh"		    // related header for MMU driver


//////////////////////////////////////////////////////////////////////////
// Class constructor must run base class constructor first, then allocate
// enough memory to act as main store.	Note: This is a really simple
// minded implementation.  There is no error reporting and minimal safe
// guards - if we did not get any memory, all blocks are set "In Use"!
//
Mmu::Mmu (UINT16 id, UINT16 cls, Knl *pK) : port(id, cls, pK)
{
  INT16  i;
  UINT16 k;

  pMemBlk = new UINT16[PART_SIZE * MAX_PARTS];
  for (i = 0, k = 0; i < MAX_PARTS; i++, k += PART_SIZE) {
    arrPgTbl[i].pMem = (pMemBlk + k);
    arrPgTbl[i].bInUse = (BOOL)(pMemBlk == NULL);
  }
}

////////////////////
// Destructor must release memory block
//
Mmu::~Mmu (void)
{
  if (pMemBlk)
    DELETE_ARRAY pMemBlk;
}

////////////////////
// Memory for this driver is a simple block of fixed RAM, partitioned into
// equal size chunks.  When allocated (or duplicated from an existing MCB)
// a new MCB struct is created and the next free partition assigned.
// In all cases (except Open - see below), the message void pointer
// references a MCB. Valid Actions are:
//
// Open:  Allocate next free partition with size atleast  words,
//	  marking it "InUse".  Return handle to Table entry in  of
//	  message, or zero if no mem available.
// Close:  is the handle to an allocated page. Release the partition
//	  allocated to it by clearing the flag.
// Dup:   If a partition is available, allocate it to a new MCB, then do a
//	  bitwise copy of partition referenced by  to it, returning
//	  the handle to the new partition.
// Read:  Get the word at offset  from the partition  and
//	  write it to .
// Write: Store the word at  to offset  of the partition
//	  .
// *Blk:  Transfer  words to/from  beginning at  of
//	  partition 
// Resize: 
//
// By convention (what i tell thee three times is true), all messages to
// the MMU will be SENT from the Kernel (or the PCI), so replies can be
// simply placed in the passed message.	If you doubt this, use the MM_Sync
// bit and respond to Posted messages by Post.
//
void Mmu::RxPort (PMSG pM)
{
  switch (pM->wMsgType & ~MM_Sync) {
    case KM_Open :
      if (pM->wParam = (UINT16)FindFree(&arrPgTbl[0]))
	memset(arrPgTbl[pM->wParam-1].pMem, 0, (PART_SIZE << 1));
      break;
    case KM_Close :
      if (pM->wParam)
	arrPgTbl[pM->wParam - 1].bInUse = FALSE;
      break;
    case MMU_Duplicate:
      if (pM->wParam) {
	HANDLE hTemp = (HANDLE)pM->wParam - 1;
	if ((HANDLE)pM->wParam = FindFree(&arrPgTbl[0]))
	  memcpy(arrPgTbl[pM->wParam - 1].pMem,
	    arrPgTbl[hTemp].pMem, (PART_SIZE << 1));
      }
      break;
    case KM_Read :
      if (pM->wParam && pM->pBody) {
	PMMU_MSG pT = (PMMU_MSG)pM->pBody;
	if (pT->uOffset < PART_SIZE)
	  *(pT->pData) = *(arrPgTbl[pM->wParam - 1].pMem + pT->uOffset);
      }
      break;
    case KM_Write :
      if (pM->wParam && pM->pBody) {
	PMMU_MSG pT = (PMMU_MSG)pM->pBody;
	if (pT->uOffset < PART_SIZE)
	  *(arrPgTbl[pM->wParam - 1].pMem + pT->uOffset) = *(pT->pData);
      }
      break;
    case KM_ReadBlk :
      if (pM->wParam && pM->pBody) {
	PMMU_MSG pT = (PMMU_MSG)pM->pBody;
	if (PART_SIZE > (pT->uOffset + pT->uLen))
	  memcpy(pT->pData, (arrPgTbl[pM->wParam - 1].pMem + pT->uOffset),
		(pT->uLen << 1));
      }
      break;
    case KM_WriteBlk :
      if (pM->wParam && pM->pBody) {
	PMMU_MSG pT = (PMMU_MSG)pM->pBody;
	if (PART_SIZE > (pT->uOffset + pT->uLen))
	  memcpy((arrPgTbl[pM->wParam - 1].pMem + pT->uOffset),
		  pT->pData, (pT->uLen << 1));
      }
      break;
    case MMU_Resize:
      break;
  default:
    DevError(ET_NoSupport, FALSE);
  }
}

////////////
// scan the page table for an unused partition
// RETURNS: Zero if no free handles, or a valid handle
//
HANDLE Mmu::FindFree (PPGTBL pPt)
{
  for (INT16 idx = 0; idx < MAX_PARTS; ++idx, ++pPt)
    if (pPt->bInUse == FALSE) {
      pPt->bInUse = TRUE;
      return (idx + 1);
    }
  return 0;
}


/////////////////////////////////// eof ////////////////////////////////////