/* MergeMem.c v2 - by  Carolyn Scheppner  CBM  02/87
 *    modified:  07/87 to move printf's outside of Forbid
 *               (printf eventually Waits which breaks a Forbid)
 *               Now responsive from WB, linkage with TWstartup.obj
 * 
 *  Attempts to merge the memlists of sequentially configged ram boards
 *  which have the same Attributes (for contiguous expansion ram)
 *
 *  Note:  This program has been tested with an Alegra plugged into
 *         a Microbotics Starboard' pass-thru, and with an A2000
 *         with multiple 2-meg ram boards.  This program makes
 *         the assumption that sequentially configged ram boards
 *         have sequential entries in the MemHeader list.
 *         If ram boards are not installed largest to smallest,
 *         this may not be true and this program will not be able
 *         to merge them.
 *
 *  Alink with TWStartup.obj ... Amiga.lib, LC.lib
 *
 */

#include "exec/types.h"
#include "exec/exec.h" 
#include "exec/execbase.h" 

extern struct ExecBase *SysBase;
extern LONG   stdin;

char TWspec[] = {"CON:100/50/440/100/ MergeMem v2 "};
char auth[]   = {"cas/cbm"};

main(argc,argv)
int argc;
char **argv;
   {
   struct MemChunk *chunk;
   struct MemHeader *mem, *firstmem, *prevmem = 0;
   struct ExecBase *eb = SysBase;
   ULONG  memsize;

   ULONG  mems[32], ends[32], atts[32], prev[32], mrgs[32];
   ULONG  k, memCnt = 0, mrgCnt = 0;

   BOOL  FromWb;

   /* Temps */
   struct MemChunk *oldFirst;
   APTR   oldLower, oldUpper;
   ULONG  oldFree;

   FromWb = (argc==0) ? TRUE : FALSE;
   if((argc==2)&&(argv[1][0]=='?'))
      {
      printf("MergeMem v2  ---  Carolyn Scheppner   CBM   07/87\n");
      printf("Usage: MergeMem\n");
      printf("Attempts to merge sequentially config'd ram boards\n");
      exit(0);
      }

   Forbid();
   firstmem = (struct MemHeader *)eb->MemList.lh_Head;

   /* Go to end of MemHeader list */
   for (mem = firstmem;
           mem->mh_Node.ln_Succ;
              mem = (struct MemHeader *)mem->mh_Node.ln_Succ)
      {
      mems[memCnt] = (ULONG)mem;
      ends[memCnt] = (ULONG)mem->mh_Upper;
      atts[memCnt] = (ULONG)mem->mh_Attributes;
      memCnt++;
      }

   /* Back up from terminal node to point at last MemHeader */
   mem = (struct MemHeader *)mem->mh_Node.ln_Pred;

   /* Backwards, for each except first */
   for ( ; (ULONG)mem != (ULONG)firstmem; mem = prevmem)
      {
      prevmem = (struct MemHeader *)mem->mh_Node.ln_Pred;

      /* If prev MemHeader describes neighboring ram of same Attributes */
      if(((ULONG)prevmem->mh_Upper == (ULONG)mem->mh_Lower - 32)&&
           (prevmem->mh_Attributes == mem->mh_Attributes))
         {
         prev[mrgCnt] = (ULONG)prevmem;
         mrgs[mrgCnt] = (ULONG)mem;
         mrgCnt++;

         /* Save needed stuff from MemHeader before Remove()ing it */
         oldFirst = mem->mh_First;
         oldLower = mem->mh_Lower;
         oldUpper = mem->mh_Upper;
         oldFree  = mem->mh_Free;
         Remove(mem);

         /* Adjust Upper and Free in prev MemHeader to include this mem */
         memsize = (ULONG)oldUpper - (ULONG)oldLower +32L;
         prevmem->mh_Upper = (APTR)((ULONG)prevmem->mh_Upper + memsize);
         prevmem->mh_Free += oldFree;

         /* Link last free chunk of prevmem to first free of mem */
         for (chunk = prevmem->mh_First;
                  chunk->mc_Next; chunk = chunk->mc_Next);
         chunk->mc_Next = oldFirst;

         /* Now FreeMem() the old MemHeader as a 32 byte chunk */
         FreeMem(mem,32);
         }
      }
   Permit();

   if(stdin > 0)
      {
      printf("RAM configuration:\n");
      for(k=0; k<memCnt; k++)
         {
         printf("   Memory type $%lx from $%lx to $%lx\n",
            atts[k], mems[k], (ends[k]) - 1);
         }
     
      if(!mrgCnt)  printf("No merging possible.\n");
      else
         {
         printf("Merged:\n");
         for(k=0; k<mrgCnt; k++)
            {
            printf("   $%lx with $%lx\n",mrgs[k], prev[k]);
           }
         }
      }
   if(FromWb)
      {
      printf("\nPress RETURN to exit: ");
      while(getchar() != '\n');
      }
   }
