/*							=====> SBIGMEM.C     */
/* TIPC Scheme '84 Runtime Support - Memory Allocation Routines
   (C) Copyright 1984, 1985 by Texas Instruments Incorporated.
   All rights reserved.

   Author:  John C. Jensen
   Installation:  Texas Instruments Incorporated, Dallas, Texas
   Division:  Central Research Laboratories
   Cost Center:  Computer Science Laboratory
   Project:  Computer Architecture Branch
   Date Written:  3 December 1984
   Last Modification:
	4 June 1986 (TC) - Turn off assertion processing for better
			   performance.
*/
#include "scheme.h"

/* Turn off assertions in SBIGMEM.C for performance reasons */
#define ASSERT(arg) /* do nothing */
#define ENTER(xyz)  /* do nothing */

extern unsigned first_page; /* paragraph address of first physical page */

/************************************************************************/
/*		Allocate a Large BLock in Scheme's Memory               */
/************************************************************************/
alloc_big_block(reg, type, size)
int reg[2];		/* register to receive pointer to allocated block */
int type;		/* type code of block to be allocated */
unsigned size;		/* size of block in bytes (including block header) */
 {
  int number_of_pages;	/* number of pages required to satisy request */
  int page;		/* page number where large block can be allocated */

#ifdef PROMEM
  if (PAGESIZE == MAX_PAGESIZE)
   number_of_pages = 1;
  else
#endif
   number_of_pages = ((size + (PAGESIZE - 1)) / PAGESIZE);
  if ((page = find_big_block(number_of_pages)) == -1)
   {
    garbage();	/* Invoke Garbage Collector to reclaim memory */
    if ((page = find_big_block(number_of_pages)) == -1)
     {
      gcsquish();  /* Try compacting memory */
      if ((page = find_big_block(number_of_pages)) == -1)
       {
	out_of_memory();		/* attempt to execute SCHEME-RESET */
	/* Note:  The above procedure returns control elsewhere */
       }
     }
   }
  zero_page(page);
  put_ptr(page, 0, type, size);
  nextcell[page] = END_LIST;
  if (size <= psize[page] - BLK_OVHD)
   {
    put_ptr(page, size, FREETYPE, psize[page] - size);
    nextcell[page] = size;
   }
  ptype[page] = type + type;
  w_attrib[page] = pageattr[type];
  pagelink[page] = pagelist[type];
  pagelist[type] = page;

  reg[C_PAGE] = ADJPAGE(page);
  reg[C_DISP] = 0;
 } /* end of function:	alloc_big_block(reg, type, size) */


find_big_block(number_of_pages)
int number_of_pages;	/* number of contiguous pages required */
 {
  int free_pages[NUMPAGES+1]; /* free page table */
  int i,j;		/* our old favorite index variables */
  int page;		/* working page number */
  int page_found = -1;	/* page number of first page in big block */

ENTER(find_big_block);

  /* Initialize free_pages table */
  for (i = 0; i <= NUMPAGES; i++)
    free_pages[i] = -1;

  /* Record the number of all free pages */
  page = freepage;
  while (page != END_LIST)
   {
ASSERT(page >= 0 && page < NUMPAGES /* subchk? */);
ASSERT(free_pages[page] == -1 /* infinite loop? */);
    free_pages[page] = page;
    page = pagelink[page];
   }

  /* Search for a contiguous group of pages to satisfy request */
  for (i = 0; i < NUMPAGES - DEDPAGES - number_of_pages; i++)
   {
    if (free_pages[i] != -1)
     {
      j = 1;
      while (free_pages[i+j] != -1)
       {
	j++;
	if (j >= number_of_pages)
	 {
	  /* required number of pages found-- adjust page table */
	  page_found = free_pages[i];
	  #ifdef PROMEM
	  if (PAGESIZE != MAX_PAGESIZE)		/* pro version test */
	  #endif
	    psize[page_found] = PAGESIZE * number_of_pages;
	  free_pages[i] = -1;

	  for (j = 1; j < number_of_pages; j++)
	   {
	    page = free_pages[i+j];
	    psize[page] = 0;
	    attrib[page].nomemory = 1;
	    free_pages[i+j] = -1;
	   }

	  /* update list of free pages */
	  freepage = END_LIST;
	  for (i = NUMPAGES; i > DEDPAGES; i--)
	   {
	    if (free_pages[i] != -1)
	     {
	      pagelink[(j = free_pages[i])] = freepage;
	      freepage = j;
	     }
	   }
	  return(page_found);
	 }
       }
      i += j;
     }
   }
  return(-1);		/* no pages found */
 } /* end of function:	find_big_block(number_of_pages) */
