home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / fish / system_utils / general / setcpu_400 / setcpu.c < prev    next >
C/C++ Source or Header  |  1990-11-03  |  24KB  |  754 lines

  1. /*
  2.     SetCPU V1.60
  3.     by Dave Haynie, April 13, 1990
  4.     Released to the Public Domain
  5.  
  6.     MAIN PROGRAM
  7.  
  8.     This program is a CPU identification and MMU support tool for the
  9.     Amiga operating system.  It will identify various CPU system 
  10.     elements, and allow decisions to be made based on those elements
  11.     in script files.  It will also use the MMU on systems so equipped
  12.     to translate system ROM, or alternate system ROMs, into system
  13.     memory, with preference given to any 32 bit memory it might be
  14.     able to detect.
  15.  
  16.     While this program does attempt to support the 68040, it hasn't
  17.     been tested on a 68040 yet.  It doesn't attempt to support any
  18.     of the MMU setups on a 68040 system just yet.
  19. */
  20.  
  21. #define MAIN_MODULE
  22.  
  23. #include "setcpu.h"
  24.  
  25. /* ====================================================================== */
  26.  
  27. /* Global options */
  28.  
  29. BOOL    tags[CHECKS],            /* Check system tags */
  30.     verbose     = FALSE,    /* Display lots of info? */
  31.     helpmode    = FALSE,    /* Do we just want help? */
  32.     handler        = TRUE,        /* Install trap handler? */
  33.     allochead    = FALSE,    /* Allocate from head of memory */
  34.     keepexec    = FALSE,    /* Preserve ExecBase on KICKROM? */
  35.     stack        = TRUE,        /* Try a stack translation? */
  36.     aliens        = FALSE;    /* MMU setup from space? */
  37.         
  38. short    fastrom     = 0,        /* Set up the FASTROM? */
  39.     wrapbits    = 8,        /* How does the MMU wrap addresses? */
  40.     forcewrap    = -1,        /* Forced addressing size */
  41.     quitcode    = 0;        /* Termination code */
  42.  
  43. char    *romfile    = NULL;        /* Where to look for a kick image */
  44.  
  45. ULONG     bootdelay    = 0x00400000,    /* Basic reboot-loop delay */
  46.     cpu,                /* CPU type */
  47.     fpu,                /* FPU type */
  48.     mmu,                /* MMU type */
  49.     oldCACR,            /* CACR when we start. */
  50.     newCACR;            /* New CACR value. */
  51.  
  52. /* Do we want autoconfig?  I think a default level 2 makes more sense. */
  53.  
  54. short    configlevel     = 2;        
  55. BOOL    configset    = FALSE;
  56.  
  57. /* ====================================================================== */
  58.  
  59. /* This is the termination routine, which also displays numbered errors. */
  60.  
  61. void quit(err)
  62. int err;
  63. {
  64.    if (err >= 10) printf("Error: ");
  65.    switch(err) { 
  66.       case 1:
  67.          printf("Usage: SetCPU [INST|DATA] [[NO]CACHE|[NO]BURST] [CONFIG n] [BITS n] [TRAP n]\n");
  68.          printf("              [KICKROM path|dfN: [DELAY n] [KEEPEXEC]] [CARDROM path] [VERBOSE]\n");
  69.          printf("              [[NO]FASTROM [path] [KEYPATCH n] [HEAD] [NOSTACK]] [ROMBOOT]\n");
  70.          printf("              [CHECK 680x0|68851|6888x|MMU|FPU|MMUON|MMUROM|MMUALIEN]\n");
  71.          break;   
  72.       case 11: printf("Invalid numeric parameter value\n");    break;
  73.       case 12: printf("Illegal Command Line Option\n");        break;
  74.       case 13: printf("KICKROM translation can't be removed\n");break;
  75.       case 14: printf("Can't get memory for FASTROM\n");    break;
  76.       case 15: printf("Can't locate specified file\n");        break;
  77.       case 16: printf("Invalid device specified\n");        break;
  78.       case 17: printf("KEYPATCH requires FASTROM\n");        break;
  79.       case 18: printf("Can't get memory for KICKROM\n");    break;
  80.       case 19: printf("Option requires a file name argument\n");break;
  81.       case 20: printf("System is already FASTKICKed\n");    break;
  82.       case 21: printf("File/ROM version mismatch, use KICKROM\n"); break;
  83.       case 22: printf("KICKROM file format invalid\n");        break;
  84.       case 23: printf("KICKROM file too short\n");        break;
  85.       case 24: printf("KICKROM file not found\n");        break;
  86.       case 25: printf("ROMBOOT can't be used with other options\n"); break;
  87.       case 26: printf("68040 MMU setups not supported\n");    break;
  88.       case 27: printf("Alien MMU setup prevents FASTROM\n");    break;
  89.       default:  break;
  90.    }
  91.  
  92.    if (ExpansionBase) CloseLibrary(ExpansionBase);
  93.  
  94.    if (cpu >= 68020L) SetCACR(((err>10)?oldCACR:newCACR) | CACR_FIXED);
  95.    exit((err>10)?10:err);
  96. }
  97.  
  98. /* ====================================================================== */
  99.  
  100. /* A bit of magic for the smart reset code. */
  101.  
  102. #define COLDREBOOTVECT -726L
  103.  
  104. /* This routine installs the given valid rom image as a fast ROM.  It will
  105.    install any I/O translations that are appropriate, and also apply the
  106.    system patch list to the ROM image, before engaging the MMU. */
  107.  
  108. static BOOL CreateFastROM(tag,wrapbits)
  109. struct systag *tag;
  110. short wrapbits;
  111. {
  112.    ULONG *VBR = GetVBR();
  113.    struct ExecBase *eb = *((struct ExecBase **)4L);
  114.  
  115.    if (!tag) return FALSE;
  116.  
  117.    tag->wrapup = (wrapbits < tag->wrapdown) ? wrapbits : tag->wrapdown;
  118.  
  119.   /* Here I'll add in subtables for any I/O devices that we've been told
  120.      about, that I can locate. */
  121.  
  122.    MakeExpTable(tag);
  123.  
  124.   /* Here I apply the patches to this ROM. */
  125.  
  126.    AddPatch((UWORD *)tag->romhi,SystemPatch,tag);
  127.    tag->patchlist = lastpatch;   
  128.  
  129.   /* How 'bout that exception handler.  I get the Vector Base Register,
  130.      save the old vector, allocate space for the new one if needed, copy it
  131.      from my SetCPU code, and assign it.  The tag keeps track of all of this
  132.      so that I can easily remove the whole thing if FASTROM is turned off. */
  133.   
  134.    if (handler) {
  135.       tag->OldBerr = (char *)VBR[2];
  136.       tag->BerrSize = BerrCodeSize;
  137.       tag->BerrHandler = (char *)AllocMem(tag->BerrSize,MEMF_PUBLIC);
  138.       MemCopy(BerrCode,tag->BerrHandler,tag->BerrSize);
  139.       VBR[2] = (ULONG)tag->BerrHandler;
  140.    }
  141.  
  142.   /* Should we have a smart reset bit? */
  143.  
  144.    if (eb->LibNode.lib_Version >= 36) {
  145.       tag->ResetCode = (char *)AllocMem(tag->ResetSize = ResetCodeSize,0L);
  146.       MemCopy((char *)ResetCode,tag->ResetCode,tag->ResetSize);
  147.       tag->OldReset = SetFunction(eb,COLDREBOOTVECT,tag->ResetCode);
  148.    } 
  149.  
  150.   /* Bang the MMU my way */
  151.  
  152.    SetMMURegs(tag);
  153.    Disable();
  154.    SetMMUTag(tag);
  155.  
  156.   /* How about that system stack. This is done here, since the MMU is already
  157.      on, and I need to do supervisor-mode stuff to turn it on, but no to set
  158.      up the fast stack. */
  159.  
  160.    if (stack) MakeFastStack(tag);
  161.  
  162.    Enable();
  163.    return TRUE;
  164. }
  165.  
  166. /* This routine creates a kickable ROM, based on the image in the systag.
  167.    If the Kick ROM can't be allocated, the routine returns FALSE, otherwise,
  168.    TRUE. */
  169.  
  170. static BOOL CreateKickROM(temptag,wrapbits) 
  171. struct systag *temptag;
  172. short wrapbits;
  173. {
  174.    struct systag *tag;
  175.    ULONG *VBR = GetVBR();
  176.  
  177.    if (!temptag || LoadErr) return FALSE;
  178.  
  179.   /* We disable so that nothing else is running; the RAMBoot() routine
  180.      counts on the instruction cache, so we might as well turn that on
  181.      now as well. */
  182.  
  183.    Forbid();
  184.    Disable();
  185.  
  186.   /* Now I need a new tag, based on safe memory.  Note that calling the safe
  187.      allocator will very likely crash the system if we're not disabled. */
  188.  
  189.    if (!(tag = AllocSAFEImage(temptag))) {
  190.       Enable(); 
  191.       return FALSE;
  192.    }
  193.  
  194.    tag->wrapup = (wrapbits < tag->wrapdown) ? wrapbits : tag->wrapdown;
  195.    
  196.    if (configlevel == 1 || configlevel == 0) {
  197.       tag->maintable[0xe80000L/ROMROUND] = PD_ADDR(0x800000)|PD_DT_PAGE;
  198.       tag->config = FALSE;
  199.    }
  200.  
  201.   /* How 'bout that exception handler.  I get the Vector Base Register,
  202.      save the old vector, allocate space for the new one if needed, copy it
  203.      from my SetCPU code, and assign it.  The tag keeps track of all of this
  204.      so that I can easily remove the whole thing if FASTROM is turned off. */
  205.  
  206.    if (handler) {
  207.       tag->BerrSize = BerrCodeSize;
  208.       MemCopy(BerrCode,tag->BerrHandler,tag->BerrSize);
  209.       VBR[2] = (ULONG)tag->BerrHandler;
  210.    }
  211.    SetMMURegs(tag);
  212.    RAMBoot(tag,(LONG)keepexec,bootdelay);
  213.    return FALSE;
  214. }
  215.  
  216. /* This routine removes the Fast ROM, and re-claims the memory previously
  217.    allocated.  We've already checked to make sure that the MMU was 
  218.    switched on. */
  219.  
  220. static void DeleteFastROM(tag)
  221. struct systag *tag;
  222. {
  223.    ULONG *VBR;
  224.    struct MemChunk *mem, *del;
  225.    struct ExecBase *eb = *((struct ExecBase **)4L);
  226.  
  227.   /* First off, turn off the MMU and caches.  This lets us muck with the table 
  228.      and reclaim memory without any trouble. */
  229.  
  230.    if (tag->romtype != ROM_FAST) quit(13);
  231.    if (tag->sysstack) FreeFastStack(tag);
  232.    SetTC(0L);
  233.  
  234.   /* First I free any subtable stuff that was allocated. */
  235.    FreeExpROM(tag->devs);
  236.  
  237.   /* Now I delete the patches for any patch lists I've got.  They only get
  238.      deleted if they've been applied. */
  239.    mem = tag->patchlist;
  240.    while (mem) {
  241.       del = mem;
  242.       mem = mem->mc_Next;
  243.       FreeMem(del,del->mc_Bytes);
  244.    }
  245.  
  246.   /* Remove the bus error handler, if there is one. */
  247.    if (tag->BerrHandler) {
  248.       VBR = GetVBR();
  249.       VBR[2] = (ULONG)tag->OldBerr;
  250.       if (tag->OldBerr) FreeMem(tag->BerrHandler,tag->BerrSize);
  251.    }
  252.  
  253.   /* Did we have a smart reset bit? */
  254.  
  255.    if (tag->ResetCode && tag->OldReset) {
  256.       SetFunction(eb,COLDREBOOTVECT,tag->OldReset);
  257.       FreeMem(tag->ResetCode,tag->ResetSize);
  258.    }
  259.  
  260.   /* Now I just free up table and ROM image memory, and I'm done!  I can free
  261.      the table I built for any subtable here, and then the main table and
  262.      image. */
  263.   
  264.    FreeMMUTable(tag);
  265.  
  266.    if (tag->tagsize <= 66L || !tag->romlo)
  267.       FreeMem(tag->romhi,SMALLROMSIZE);
  268.    else if (tag->romlo)
  269.       FreeMem(tag->romlo,tag->romsize);
  270.    FreeMem(tag,tag->tagsize);
  271. }
  272.  
  273. /* This routine displays the ROM image information. */
  274.  
  275. static void PrintFastROM() {
  276.    struct systag *tag;
  277.    struct ExpROMData *dev;
  278.    struct ExecBase *eb = *((struct ExecBase **)4L);
  279.  
  280.    if (!(tag = GetSysTag())) return;
  281.  
  282.    printf("TABLE : (PADDR: $%8lx) (SIZE: %ld) (WRAP: %d)\n",
  283.       tag->maintable,tag->tablesize/4,tag->wrapup);
  284.  
  285.    if (tag->romlo)
  286.       printf("KERNEL: (PADLO: $%8lx) (PADHI: $%8lx) (VADDR: $%8lx) (SIZE: %ldK)\n",
  287.          tag->romlo,tag->romhi,tag->romloc,tag->romsize/1024);
  288.    else
  289.       printf("KERNEL: (PADDR: $%8lx) (VADDR: $%8lx) (SIZE: %ldK)\n",
  290.          tag->romhi,tag->romloc,tag->romsize/1024);
  291.    if (tag->sysstack)
  292.       printf("SSTACK: (PADDR: $%8lx) (VADDR: $%8lx) (SIZE: %ldK)\n",
  293.          tag->sysstack,eb->SysStkLower,((ULONG)eb->SysStkUpper - (ULONG)eb->SysStkLower + 1)/1024);
  294.    if (tag->ResetCode)
  295.       printf("REBOOT: (NVECT: $%8lx) (OVECT: $%8lx) (SIZE: $%lx)\n",
  296.          tag->ResetCode,tag->OldReset,tag->ResetSize);
  297.  
  298.   /* Now we'll explain any device stuff that's here. */
  299.    for (dev = tag->devs; dev; dev = dev->next) {
  300.       printf("DEVICE: %sE\n",dev->name);
  301.       printf("        (PADDR: $%8lx) (TABLE: $%8lx) (SIZE: %ldK)\n",
  302.              dev->imagebase, dev->tablebase, dev->ROMsize/1024);
  303.    }
  304. }
  305.  
  306. /* Basic "Do I do configuration" logic */
  307.  
  308. void SetupConfig(tag)
  309. struct systag *tag;
  310. {
  311.    if (configlevel > 0) {
  312.       tag->maintable[0xe80000L/ROMROUND] = PD_ADDR(0xe80000L)|PD_DT_PAGE;
  313.       if (configlevel > 1) SafeConfigDevs();
  314.    }
  315. }
  316.  
  317. /* ====================================================================== */
  318.  
  319. /* This function scopes out the two key expansion devices, Bridge Card or
  320.    known-to-be-32-bit memory. */
  321.  
  322. void SnoopDevs() {
  323.    struct ConfigDev *cd;
  324.  
  325.    if ((cd = FindConfigDev(NULL,0x201L,0x01L)) || (cd = FindConfigDev(NULL,0x201L,0x02L))) {
  326.       Bridge.Addr = (ULONG)cd->cd_BoardAddr;
  327.       Bridge.Size = (ULONG)cd->cd_BoardSize;
  328.    }
  329.  
  330.    if ((cd = FindConfigDev(NULL,0x202L,0x50L)) || (cd = FindConfigDev(NULL,0x202L,0x51L))) {
  331.       A26x0.Addr = (ULONG)cd->cd_BoardAddr;
  332.       A26x0.Size = (ULONG)cd->cd_BoardSize;
  333.    }     
  334. }
  335.  
  336. /* ====================================================================== */
  337.  
  338. /* Codes for the FASTROM action. */
  339.  
  340. #define    FR_NO_ACTION    0
  341. #define    FR_DELETE    1
  342. #define    FR_MKFAST    ROM_FAST
  343. #define FR_MKKICK    ROM_KICK
  344.  
  345. /* Command line tokens */
  346.  
  347. static char *CLITokens[] = 
  348.    { "68000","68010","68020","68030","68040","68851","68881","68882","FPU",
  349.      "MMU","MMUON","MMUROM","MMUALIEN","CHECK", "FASTROM", "NOFASTROM",
  350.      "NOPATCH","KEYPATCH","TRAP", "DATA", "INST", "CACHE", "NOCACHE", "BURST",
  351.      "NOBURST","VERBOSE", "KICKROM", "CARDROM", "CONFIG", "HEAD", "DELAY",
  352.      "KEEPEXEC","ROMBOOT","NOSTACK","BITS","?" };
  353.    
  354. #define CT_CHECK    CHECKS+0
  355. #define CT_FASTROM    CHECKS+1
  356. #define CT_NOFROM    CHECKS+2
  357. #define CT_NOPATCH    CHECKS+3
  358. #define CT_KEYPAT    CHECKS+4
  359. #define CT_TRAP        CHECKS+5
  360. #define CT_DATA        CHECKS+6
  361. #define CT_INST        CHECKS+7
  362. #define CT_CACHE    CHECKS+8
  363. #define CT_NOCACHE    CHECKS+9
  364. #define CT_BURST    CHECKS+10
  365. #define CT_NOBURST    CHECKS+11
  366. #define CT_VERBOSE    CHECKS+12
  367. #define CT_KICKROM    CHECKS+13
  368. #define CT_CARDROM    CHECKS+14
  369. #define CT_CONFIG    CHECKS+15
  370. #define CT_HEAD        CHECKS+16
  371. #define CT_DELAY    CHECKS+17
  372. #define CT_KEEPEX    CHECKS+18
  373. #define CT_ROMBOOT    CHECKS+19
  374. #define CT_NOSTACK    CHECKS+20
  375. #define CT_BITS        CHECKS+21
  376. #define CT_HELP        CHECKS+22
  377.  
  378. /* This function fetches a bounded numeric value, or takes the error trap
  379.    for numeric arguments if things aren't right. */
  380.    
  381. short getnumber(arg,low,high)
  382. char *arg;
  383. short low, high;
  384. {
  385.    short num;
  386.  
  387.    if (!arg || !isdigit(*arg) || (num = atoi(arg)) < low || num > high) 
  388.       quit(11);
  389.    return num;
  390. }
  391.  
  392. /* This is basically the DiskSalv command-line parser re-written for the
  393.    SetCPU command set. */
  394.  
  395. static USHORT ParseCommandLine(argc,argv)
  396. int argc;
  397. char **argv;
  398. {
  399.    short i,j, trapmode = 0, bitcnt;
  400.    struct patch *p;
  401.    BPTR lock;
  402.    ULONG mode = CACR_INST | CACR_DATA;
  403.    char *file;
  404.    BOOL f_FASTROM = FALSE, f_KEYPAT = FALSE;
  405.    
  406.    for (i = 1; i < argc; i++) {
  407.       for (j = 0; CLITokens[j] && !striequ(argv[i],CLITokens[j]); ++j);
  408.       if (j < CHECKS) {
  409.          if (quitcode != WARNING) return 12;
  410.          tags[j] = TRUE;
  411.       } else switch (j) {
  412.          case CT_CHECK    : quitcode = WARNING;            break;
  413.          case CT_NOFROM    : fastrom = FR_DELETE;            break;
  414.          case CT_DATA    : mode = CACR_DATA;            break;
  415.          case CT_INST   : mode = CACR_INST;            break;
  416.          case CT_CACHE    : newCACR |=   mode << CACR_ENABLE;    break;
  417.          case CT_NOCACHE: newCACR &= ~(mode << CACR_ENABLE);    break;
  418.          case CT_BURST    : newCACR |=   mode << CACR_BURST;    break;
  419.          case CT_NOBURST: newCACR &= ~(mode << CACR_BURST);    break;
  420.          case CT_VERBOSE: verbose = TRUE;            break;
  421.          case CT_HEAD    : allochead = TRUE;            break;
  422.          case CT_KEEPEX    : keepexec = FALSE;            break;
  423.          case CT_HELP    : helpmode = TRUE;            break;
  424.          case CT_NOSTACK: stack = FALSE;            break;
  425.          case CT_ROMBOOT: 
  426.             if (argc != 2) 
  427.                quit(25);
  428.             else 
  429.                CleanBoot();
  430.          case CT_TRAP    : 
  431.             if (argv[i+1] && isdigit(argv[i+1][0]))
  432.                trapmode = getnumber(argv[++i],0,2);
  433.             if (trapmode == 0) wrapbits = 0;
  434.             handler = (trapmode == 2);
  435.             break;
  436.          case CT_BITS    :
  437.             if (argv[i+1] && isdigit(argv[i+1][0]))
  438.                bitcnt  = getnumber(argv[++i],24,32);
  439.             forcewrap = 32-bitcnt;
  440.             break;
  441.          case CT_CONFIG    : 
  442.             configset = TRUE;
  443.             configlevel = getnumber(argv[++i],0,2);
  444.             break;
  445.          case CT_DELAY:
  446.             bootdelay = 0x60000L*(ULONG)getnumber(argv[++i],0,100);
  447.             break;
  448.          case CT_KEYPAT    :
  449.              SetKeyDelay(100L * (ULONG)getnumber(argv[++i],1,100));
  450.              for (p = SystemPatch; p; p = p->next)
  451.                 if (p->list[KEYPATCH].Type == PT_KEYBOARD) {
  452.                    p->list[KEYPATCH].Length = KeyCodeSize;
  453.                    p->list[KEYPATCH].Code = (UWORD *)KeyCode;
  454.                    p->list[KEYPATCH].Type = PT_JSR;
  455.                 }
  456.             f_KEYPAT = TRUE;
  457.             break;
  458.          case CT_NOPATCH: 
  459.             for (p = SystemPatch; p; p = p->next) {
  460.                j = 0;
  461.                while (p->list[j].Type != PT_END) {
  462.                   if (j != KEYPATCH && p->list[j].Type < PT_END)
  463.                      p->list[j++].Type = PT_IGNORE;
  464.                   else
  465.                      ++j;                        
  466.                }
  467.             }
  468.             break;
  469.          case CT_FASTROM: 
  470.             fastrom = FR_MKFAST;
  471.             if (i+1 < argc && (lock = Lock(argv[i+1],ACCESS_READ))) {
  472.                UnLock(lock);
  473.                romfile = argv[++i];
  474.             }
  475.             f_FASTROM = TRUE;
  476.             break;
  477.          case CT_KICKROM:
  478.             fastrom = FR_MKKICK;
  479.             if (!(romfile = argv[++i])) return 19;
  480.             break;
  481.          case CT_CARDROM:
  482.             if (!(file = argv[++i])) return 19;
  483.             if (!ReadExpDevs(file)) return 15;
  484.             break;
  485.  
  486.          default: return 12;
  487.       }
  488.    }
  489.    if (f_KEYPAT && !f_FASTROM) return 17;
  490.  
  491.    return 0;
  492. }
  493.  
  494.  
  495. /* ====================================================================== */
  496.  
  497. /* This routine prints FPU codes and sets things accordingly. */
  498.  
  499. void PrintFPU()
  500. {
  501.    if (fpu == 68881L) {
  502.       printf("68881 ");
  503.       if (tags[CK68881]) quitcode = 0;
  504.    } else if (fpu == 68882L) {
  505.       printf("68882 ");
  506.       if (tags[CK68882]) quitcode = 0;
  507.    }
  508.    if (fpu && tags[CKFPU]) quitcode = 0;
  509. }
  510.  
  511. /* This program displays the system CPU setup and sets any appropriate check
  512.    flags. */
  513.  
  514. void PrintSystem() {
  515.    ULONG mmuon,dmask = CACR_DATA,imask = CACR_INST,shft = CACR_ENABLE;
  516.    struct systag *tag;
  517.  
  518.    printf("SYSTEM: ");
  519.  
  520.    /* If they're not on a 68020/68030, we can't set anything.  For 
  521.       compatibility across systems, I don't consider a cache setting 
  522.       request an error, just ignore it. */
  523.  
  524.    if (cpu <= 68010L) {
  525.       if (cpu == 68010L) {
  526.          printf("68010 ");
  527.          if (tags[CK68010]) quitcode = 0;
  528.       } else {
  529.          printf("68000 ");
  530.          if (tags[CK68000]) quitcode = 0;
  531.       }
  532.       PrintFPU();
  533.       printf("\n");
  534.       return;
  535.    }
  536.  
  537.    /* The 32 bit system might have ROMs and things... */
  538.  
  539.    if (cpu == 68040L) {
  540.       dmask = CACR_DATA40;
  541.       shft = CACR_ENABLE40;
  542.       printf("68040 ");
  543.       if (tags[CK68040]) quitcode = 0;
  544.    } else if (cpu == 68030L) {
  545.       printf("68030 ");
  546.       if (tags[CK68030]) quitcode = 0;
  547.    } else {
  548.       printf("68020 ");
  549.       if (tags[CK68020]) quitcode = 0;
  550.    }
  551.  
  552.    PrintFPU();
  553.  
  554.    if (mmu == 68851L) {
  555.       printf("68851 ");
  556.       if (tags[CK68851]) quitcode = 0;
  557.    }
  558.    if (mmu && mmu != BOGUSMMU && mmu != 68040) {
  559.       mmuon = (GetTC() & TC_ENB);
  560.       if (tags[CKMMU]) quitcode = 0;
  561.       if (tags[CKMMUON] && mmuon) quitcode = 0;
  562.       if (tag = GetSysTag()) {
  563.          if (tags[CKMMUROM]) quitcode = 0;
  564.          switch (tag->romtype) {
  565.             case ROM_FAST:
  566.                printf("FASTROM "); break;
  567.             case ROM_KICK:
  568.                printf("SLOWKICK "); break;
  569.             case ROM_FKICK:
  570.                printf("FASTKICK "); break;
  571.             default:
  572.                printf("NEWKICK? "); break;
  573.          }
  574.       } else if (mmuon) {
  575.          if (tags[CKMMUALIEN]) quitcode = 0;
  576.          printf("ALIENMMU ");
  577.       }
  578.    } else if (mmu == BOGUSMMU)
  579.       printf("(FPU LOGIC ERROR) ");
  580.  
  581.    /* We always print the results, even if nothing has changed. */
  582.  
  583.    SetCACR(newCACR | CACR_FIXED);
  584.    newCACR = GetCACR();
  585.    printf("(INST: ");
  586.    if (!(newCACR & (imask << shft))) printf("NO");
  587.    printf("CACHE");
  588.  
  589.    if (cpu >= 68030L) {
  590.       if (cpu == 68030) {
  591.          printf(" ");
  592.          if (!(newCACR & (CACR_INST << CACR_BURST))) printf("NO");
  593.          printf("BURST");
  594.       }
  595.       printf(") (DATA: ");
  596.       if (!(newCACR & (dmask << shft))) printf("NO");
  597.  
  598.       printf("CACHE");
  599.       if (cpu == 68030) {
  600.          printf(" ");
  601.          if (!(newCACR & (CACR_DATA << CACR_BURST))) printf("NO");
  602.          printf("BURST");
  603.       }
  604.    }
  605.    printf(")\n");
  606.  
  607. }
  608.  
  609. /* ====================================================================== */
  610.  
  611. /* This function returns TRUE is the tag ROM passed is the same version
  612.    as the actual ROM in use, FALSE otherwise. */
  613.    
  614. BOOL CheckVersion(tag)
  615. struct systag *tag;
  616. {
  617.    UWORD *tagver,*kickver = (UWORD *)(0x100000C - (*(ULONG *)0xFFFFEC));
  618.    ULONG *rom = (ULONG *)((ULONG)tag->romhi);
  619.    
  620.    tagver = (UWORD *)(((ULONG)rom + SMALLROMSIZE + 0x0C) - rom[0xfffb]);
  621.    return (BOOL) (kickver[0] == tagver[0] && kickver[1] == tagver[1]);
  622. }
  623.  
  624. /* This function deals with the FASTROM/KICKROM patches and the like. */
  625.  
  626. void DoROMStuff(tag)
  627. struct systag *tag;
  628. {
  629.    struct systag *newtag;
  630.  
  631.    switch (fastrom) {
  632.       case FR_MKFAST:
  633.          if (tag) switch (tag->romtype) {
  634.             case ROM_FAST:
  635.                DeleteFastROM(tag);
  636.                if (romfile) {
  637.                   if (!(newtag = AllocDISKImage(ROM_FAST,romfile))) 
  638.                      if (LoadErr) quit(LoadErr); else quit(14);
  639.                   if (!CheckVersion(newtag)) {
  640.                      DeleteFastROM(newtag);
  641.                      quit(21);
  642.                   }
  643.                } else
  644.                   newtag = AllocROMImage(ROM_FAST);
  645.                if (!CreateFastROM(newtag,wrapbits)) quit(14);
  646.                break;
  647.             case ROM_KICK:
  648.                SetupConfig(tag);
  649.                if (!CreateFastROM(AllocROMImage(ROM_FKICK),wrapbits)) quit(14);
  650.                FreeSAFEImage(tag);
  651.                break;
  652.             case ROM_FKICK:
  653.                quit(20);
  654.          } else {
  655.             if (cpu == 68040) quit(26);
  656.             if (aliens) quit(27);
  657.             if (romfile) {
  658.                if (!(newtag = AllocDISKImage(ROM_FAST,romfile))) 
  659.                   if (LoadErr) quit(LoadErr); else quit(14);
  660.                if (!CheckVersion(newtag)) {
  661.                   DeleteFastROM(newtag);
  662.                   quit(21);
  663.                }
  664.             } else
  665.                newtag = AllocROMImage(ROM_FAST);
  666.             if (!CreateFastROM(newtag,wrapbits)) quit(14);
  667.          }
  668.          break;
  669.       case FR_MKKICK:
  670.          if (tag) switch (tag->romtype) {
  671.             case ROM_FAST:
  672.                DeleteFastROM(tag);
  673.             case ROM_FKICK:
  674.                if (!CreateKickROM(AllocDISKImage(ROM_KICK,romfile),wrapbits)) 
  675.                   if (LoadErr) quit(LoadErr); else quit(18);
  676.             case ROM_KICK:
  677.                SetupConfig(tag);
  678.                if (!CreateFastROM(AllocROMImage(ROM_FKICK),wrapbits)) quit(14);
  679.                FreeSAFEImage(tag);
  680.                break;
  681.          } else {
  682.             if (cpu == 68040) quit(26);
  683.             if (!CreateKickROM(AllocDISKImage(ROM_KICK,romfile),wrapbits)) 
  684.                if (LoadErr) quit(LoadErr); else quit(18);
  685.          }
  686.          break;
  687.       case FR_DELETE:
  688.          if (fastrom == FR_DELETE && tag) {
  689.             if (tag->romtype != ROM_FAST) quit(13);
  690.             DeleteFastROM(tag);
  691.          }
  692.          break;
  693.       case FR_NO_ACTION:
  694.          if (configset && tag) SetupConfig(tag);
  695.          break;
  696.    }
  697. }
  698.  
  699. /* ====================================================================== */
  700.  
  701. /* This be the main program. */
  702.  
  703. int main(argc,argv)
  704. int argc;
  705. char *argv[];
  706. {
  707.    struct systag *tag;
  708.    USHORT i,err;
  709.  
  710.   /* First we parse the command line.  The default cache operation acts 
  711.      on both data and instruction caches.  The way all the cache control
  712.      functions are defined, they're just NOPs on machines without the
  713.      appropriate caches. */
  714.  
  715.    if ((cpu = GetCPUType()) >= 68020L) {
  716.       newCACR = oldCACR = GetCACR();
  717.       SetCACR(CACR_FIXED|(CACR_INST<<CACR_CLEAR)|(CACR_DATA<<CACR_CLEAR));
  718.    }
  719.    for (i = 0; i < CHECKS; ++i) tags[i] = FALSE;
  720.  
  721.    if (argc > 1 && (err = ParseCommandLine(argc,argv))) quit(err);
  722.  
  723.    /* If they're just asking for help */
  724.  
  725.    if (verbose || helpmode)
  726.       printf("\23333mSetCPU V%1.2f by Dave Haynie\2330m\n",
  727.              ((float)PROGRAM_VERSION)/100.0);
  728.  
  729.    if (helpmode) quit(1);
  730.  
  731.   /* The FastROM routine uses the expansion library.  It's possible to have
  732.      an old version of the OS without this, so I'll be careful to avoid
  733.      using any ExpansionBase function without checking for the base being
  734.      valid. */
  735.  
  736.    if (ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",0L))
  737.       SnoopDevs();
  738.    
  739.   /* Let's find out what we have, and perform the ROM translation, if it's
  740.      requested and hasn't been done already. */
  741.  
  742.    fpu = GetFPUType();
  743.    if ((mmu = GetMMUType()) && mmu != BOGUSMMU) {
  744.       tag = GetSysTag();
  745.       aliens = (GetTC() & TC_ENB) && !tag;
  746.    }
  747.  
  748.    if (mmu && mmu != BOGUSMMU) DoROMStuff(tag);
  749.    PrintSystem();
  750.    if (verbose && cpu >= 68020 && (GetTC() & TC_ENB)) PrintFastROM();
  751.    quit(quitcode);
  752. }
  753.  
  754.