/*
	CacheCard V1.0
	Copyright 1989 by Dave Haynie

	MAIN PROGRAM

	This program is a simple cache manager for use with SetCPU V1.5.
	It allows the cachability of various autoconfig cards to be
	adjusted.
	
	The current MMU table used by SetCPU establishes 128K pages using
	the short form of the early termination descriptor.  Except for
	any CardROMs that are translated, the table is only 1 level.  In
	systems with more than 16meg of address space, the MMU table will
	be accordingly adjusted, though it's unlikely that any program
	will need adjust table parameters beyond the first 16 megabytes.
*/

#include "cachecard.h"

#define max(a,b)	((a>b)?a:b)
#define PAGESIZE	0x00020000L

struct ExpansionBase *ExpansionBase = NULL;	/* The expansion library */
struct systag *tag;				/* The SetCPU system tag */

/* ====================================================================== */

/* A simple string comparison. */

BOOL striequ(s1,s2)
char *s1,*s2;
{
   BOOL aok = FALSE;
   
   while (*s1 && *s2 && (aok = (*s1++ & 0xdf) == (*s2++ & 0xdf)));
   return (BOOL) (!*s1 && !*s2 && aok);
}

/* This routine gets the system tag from the patched system, if it's
   there.  This tag is stored in an invalid table entry that's within the
   physical ROM image.  If the MMU isn't on, I assume there's no system
   tag. */
   
struct systag *GetSysTag() {
   ULONG i, myCRP[2], *table = NULL;

   if (!(GetTC() & TC_ENB)) return NULL;

   GetCRP(myCRP);
   table = (ULONG *)myCRP[1];
   for (i = 0; i < 4096; ++i)
      if ((table[i] & PD_DT_TYPE) == PD_DT_INVALID && IV_ADDR(table[i]))
         return (struct systag *)IV_ADDR(table[i]);

   return NULL;
}

/* This function prints a list of active devices and their associated
   cache status. */
   
void PrintDevs() {
   struct ConfigDev *cd = NULL;
   ULONG page;

   if (!(cd = FindConfigDev(NULL,-1L,-1L))) {
      printf("No Amiga Devices present\n");
      return;
   }

   printf("DEVICE             ADDRESS     LENGTH    CACHE\n");

   do {
      printf("(%4x,%4x)      ",cd->cd_Rom.er_Manufacturer,cd->cd_Rom.er_Product);
      printf("%8lx    %8lx    ",cd->cd_BoardAddr,cd->cd_BoardSize);
      
      page = (ULONG)cd->cd_BoardAddr/PAGESIZE;
      if (tag->maintable[page] & PD_CI)
         printf("DISABLED\n");
      else
         printf("ENABLED\n");
   
   } while (cd = FindConfigDev(cd,-1L,-1L));
}


/* The main thing */

int main(argc,argv)
int argc;
char *argv[];
{
   ULONG mmu = 0, page, size, manuf, prod;
   BOOL ever;
   struct ConfigDev *cd;
   
   printf("\23333mCacheCard V%1.2f Copyright 1989 by Dave Haynie\2330m\n",
             ((float)PROGRAM_VERSION)/100.0);

   if (argc == 2 && argv[1][0] == '?') {
      printf("Usage: CacheCard [ENABLE|DISABLE manuf# prod#]\n");
      exit(0);
   }
   if ((mmu = GetMMUType()) != 68851 && mmu != 68030) {
      printf("Error: System does not contain an MMU\n");
      exit(10);
   }
   if (!(tag = GetSysTag())) {
      printf("Error: SetCPU FASTROM or KICKROM must be installed\n");
      exit(10);
   }
   if (tag->tagsize >= SizeOf(struct systag) && tag->tablerev != TABLE_REV) {
      printf("Error: Version of SetCPU is incompatible, use newer CacheCard program\n");
      exit(0);
   }
   if (!(ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",33L))) {
      printf("Error: Can't find \"expansion.library\"\n");
      exit(10);
   }

   if (argc > 1) {
      sscanf(argv[2],"%lx",&manuf);
      sscanf(argv[3],"%lx",&prod);
   
      if (striequ(argv[1],"DISABLE"))
         ever = FALSE;
      else if (striequ(argv[1],"ENABLE"))
         ever = TRUE;
      else {
         printf("Error: Illegal option\n");
         exit(10);
      }

      if (!(cd = FindConfigDev(NULL,manuf,prod))) {
         printf("Error: Device (%lx,%lx) Not Found\n",manuf,prod);
         CloseLibrary(ExpansionBase);
         exit(10);
      }
      
      page = (ULONG)cd->cd_BoardAddr/PAGESIZE;
      size = max((ULONG)cd->cd_BoardSize/PAGESIZE,1);

      while (size-- && page < tag->tablesize)
         if ((tag->maintable[page] & PD_DT_TYPE) != PD_DT_INVALID) {
            if (ever)
               tag->maintable[page++] &= ~PD_CI;
            else 
               tag->maintable[page++] |=  PD_CI;
         }
   }
   
   PrintDevs();

   CloseLibrary(ExpansionBase);
   exit(0);
}
