home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 397.lha / SetCPU_V1.60 / memory.c < prev    next >
C/C++ Source or Header  |  1990-07-01  |  11KB  |  358 lines

  1. /*
  2.     SetCPU V1.60
  3.     by Dave Haynie, April 13, 1990
  4.     Released to the Public Domain
  5.  
  6.     MEMORY.C MODULE
  7.  
  8.     This module is responsible for ROM image allocation, MMU table
  9.     allocation and creation, and other functions based on memory.
  10. */
  11.  
  12. #include "setcpu.h"
  13.  
  14. /* ====================================================================== */
  15.  
  16. /* Local data types */
  17.  
  18. struct range {
  19.    ULONG first;
  20.    ULONG last;
  21. };
  22.  
  23. /* ====================================================================== */
  24.  
  25. /* This function copies from the source to the destination, by longword, with
  26.    BYTE length "length". */
  27.  
  28. void MemCopy(src,des,len)
  29. ULONG *src, *des;
  30. ULONG len;
  31. {
  32.    len = (len + 3)>>2;
  33.    while (len--) *des++ = *src++;
  34. }
  35.  
  36. /* ====================================================================== */
  37.  
  38. /* This section contains the memory allocation code.  There are two
  39.    problems here.  First of all, we'd like to use 32 bit FAST memory if 
  40.    at all possible.  Next, block translation and page tables must be on at
  41.    least a page sized boundary, if not a block boundary.  */
  42.    
  43. /* This routine finds the memory block for me to use in AllocAligned().
  44.    It takes into account either A2620 or A2630 systems, where I can snoop 
  45.    out the memory for that particular board, knowing it's the fastest.  I
  46.    can adjust for 1.4's automatic memory merging in this case too, to be
  47.    sure I have 32 bit RAM.  If I don't have one of my boards, I'll return 
  48.    a pointer to the first non-$C00000 memory list marked as FAST. */
  49.  
  50. static struct range SRange = { 0L, 0L };
  51. static ULONG MaxMem = 0;
  52.  
  53. LONG SmartlyGetRange() {
  54.    struct ExecBase *eb = *((struct ExecBase **)4L);
  55.    register struct MemHeader *mem;
  56.  
  57.    /* First try for either A2620 or A2630 */
  58.    
  59.    if (A26x0.Addr && A26x0.Size) {
  60.       SRange.first = A26x0.Addr;
  61.       SRange.last = A26x0.Size + SRange.first;
  62.    } 
  63.  
  64.    /* For another critters, but we go here to find MaxMem, even
  65.       if we know it's an A26x0. */
  66.  
  67.    for (mem = (struct MemHeader *)eb->MemList.lh_Head; mem->mh_Node.ln_Succ;
  68.         mem = (struct MemHeader *)mem->mh_Node.ln_Succ) {
  69.       if ((ULONG)(mem->mh_Upper) > MaxMem) MaxMem = (ULONG)mem->mh_Upper;
  70.       if (mem->mh_Attributes & MEMF_CHIP) continue;
  71.       if (((ULONG)mem >= 0xc00000 && (ULONG)mem <= 0xc80000)) continue;
  72.       if (!SRange.first) {
  73.          SRange.first = (ULONG)mem->mh_Lower;
  74.          SRange.last = (ULONG)mem->mh_Upper;
  75.       }
  76.    }
  77.    if (SRange.first) 
  78.       return TRUE;
  79.    return FALSE;
  80. }
  81.  
  82. /* This routine allocates such an aligned block of memory from a specified 
  83.    memory list. */
  84.    
  85. void *AllocAligned(size,bound)
  86. register ULONG size;
  87. register ULONG bound;
  88. {
  89.    register ULONG target;
  90.    void *mem = NULL;
  91.  
  92.    Forbid();
  93.    if (!allochead) {
  94.       target = (SRange.last-size) & ~(bound-1);
  95.       while (target > SRange.first && !(mem = AllocAbs(size,target)))
  96.          target -= bound;
  97.       SRange.last = (ULONG)mem;
  98.    } else {
  99.       target = (SRange.first+size+bound-1) & ~(bound-1);
  100.       while (target < SRange.last && !(mem = AllocAbs(size,target)))
  101.          target += bound;
  102.       SRange.first = (ULONG)mem+size;
  103.    }
  104.    Permit();
  105.    return mem;
  106. }
  107.  
  108. /* This routine finds the memory wrap and appropriate MMU table size for
  109.    the given configuration. It requires the value of MaxMem to have been
  110.    already calculated. */
  111.    
  112. void FindWrap(tag)
  113. struct systag *tag;
  114. {
  115.    ULONG test;
  116.      
  117.    if (forcewrap == -1) {
  118.       tag->wrapdown = 0;
  119.       for (test = MaxMem; !(test & 0x80000000) && tag->wrapdown < 8; test <<= 1)
  120.          tag->wrapdown++;
  121.    } else
  122.       tag->wrapdown = forcewrap;
  123.    tag->tablesize = (128 << (8 - tag->wrapdown)) * sizeof(ULONG);
  124. }
  125.  
  126. /* This routine computes the ROM size from the magic tag values. */
  127.  
  128. ULONG CalcROMSize(tagval)
  129. ULONG tagval;
  130. {
  131.    if (tagval == MAGIC_256) return SMALLROMSIZE;
  132.    if (tagval == MAGIC_512) return BIGROMSIZE;
  133.    return 0L;
  134. }
  135.  
  136. /* This function sizes the ROM based on its base value and correctly splits 
  137.  a base address between possible ROM halves. This routine uses the Commodore
  138.    ROM file format, which is like this:
  139.  
  140.     0:    00000000
  141.     4:    size
  142.     8:    start of ROM
  143.  
  144.    The ROM, in any case, begins with either "$11114ef9", for 256L ROMs, or
  145.    "$11144ef9", for 512K ROMs.  The next longword can be used to figure out
  146.    where the ROM actually goes, in memory. */
  147.  
  148. ULONG *SizeROM(tag,base,getram)
  149. struct systag *tag;
  150. ULONG *base, getram;
  151. {
  152.    ULONG *rom = NULL;
  153.  
  154.    if (!(tag->romsize = CalcROMSize(base[0]))) return NULL;
  155.  
  156.    if (getram) 
  157.       if (!(rom = (ULONG *)AllocAligned(tag->romsize,ROMROUND))) return NULL;
  158.  
  159.    if (tag->romsize == SMALLROMSIZE) {
  160.       tag->romstart = base[1];
  161.       tag->romloc = base[1] & 0xfffc0000;
  162.       tag->romlo = 0L;
  163.       tag->romhi = rom;
  164.    } else {
  165.       tag->romstart = base[1];
  166.       tag->romloc = base[1] & 0xfff80000;
  167.       tag->romlo = rom;
  168.       tag->romhi = (ULONG *)((ULONG)rom + SMALLROMSIZE);
  169.    }
  170.    return rom;
  171. }
  172.  
  173. /* ====================================================================== */
  174.  
  175. /* This section contains routines that manage different ROM image types. */
  176.  
  177. /* This function gets an aligned ROM image copied from system ROM. */
  178.  
  179. struct systag *AllocROMImage(type)
  180. UWORD type;
  181. {
  182.    struct systag *tag = NULL, *oldtag = NULL;
  183.    ULONG *rom = NULL, *table = NULL, *base;
  184.    
  185.   /* Let's make the allocations.  I allocate the ROM first, then the table,
  186.      then the tag; since we're coming from the end of memory, this should
  187.      result in the least fragging. */
  188.  
  189.    SmartlyGetRange();
  190.    if (!(tag = AllocAligned(SizeOf(struct systag),8L))) goto fail;
  191.    if (oldtag = GetSysTag())
  192.       base = (ULONG *)oldtag->romloc;
  193.    else {
  194.       if (*(base = (ULONG *)0x00f80000) != MAGIC_512)
  195.          base = (ULONG *)0x00fc0000;
  196.    }
  197.    rom = SizeROM(tag,base,TRUE);
  198.    FindWrap(tag);
  199.    if (!(table = AllocAligned(tag->tablesize+4,TABROUND))) goto fail;
  200.    tag->maintable = table;
  201.    tag->romtype = type;
  202.    MemCopy(tag->romloc,rom,tag->romsize);
  203.    FillBasicTable(tag,FALSE);
  204.    return tag;
  205.  
  206. fail:
  207.    if (rom)   FreeMem(rom,tag->romsize);
  208.    if (table) FreeMem(table,tag->tablesize+4);
  209.    if (tag)   FreeMem(tag,SizeOf(struct systag));
  210.    return NULL;
  211. }
  212.  
  213. /* This function gets an aligned, reset-safe image in either $00C00000 or 
  214.    CHIP memory, copies the ROM code from the passed temporary image, and 
  215.    then sets up it's MMU table such that the memory used for the safe image
  216.    will be missed by the Amiga's memory-sizing logic on reboot. */
  217.  
  218. struct systag *AllocSAFEImage(temp)
  219. struct systag *temp;
  220. {
  221.    struct ExecBase *eb = *((struct ExecBase **)4L);
  222.    struct MemHeader *safe, *safeC000 = NULL, *safeCHIP = NULL, *tmem;
  223.    struct systag *tag;
  224.    ULONG upper, base, *table;
  225.  
  226.    for (safe = (struct MemHeader *)eb->MemList.lh_Head; safe->mh_Node.ln_Succ; 
  227.         safe = (struct MemHeader *)safe->mh_Node.ln_Succ) {
  228.       tmem = (struct MemHeader *)safe;
  229.       if ((ULONG)(tmem->mh_Upper) > MaxMem) MaxMem = (ULONG)tmem->mh_Upper;      
  230.       if (tmem->mh_Attributes & MEMF_CHIP) {
  231.          if (!safeCHIP || safeCHIP->mh_Upper < tmem->mh_Upper)
  232.             safeCHIP = tmem;
  233.       } else if ((ULONG)safe >= 0xc00000 && (ULONG)safe <= 0xc80000) {
  234.          if (!safeC000 || safeC000->mh_Upper < tmem->mh_Upper)
  235.             safeC000 = tmem;
  236.       }
  237.    }
  238.  
  239.   /* Will it fit?  You need at least 1 meg of memory. */
  240.  
  241.    if (!safeC000 && safeCHIP->mh_Upper < 0x080000L) return NULL;
  242.  
  243.   /* Now, where should it go. */
  244.  
  245.    if (safeC000)
  246.       upper = ((ULONG)safeC000->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
  247.    else if (safeCHIP)
  248.       upper = ((ULONG)safeCHIP->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
  249.  
  250.    FindWrap(temp);
  251.    table = (ULONG *)(base = upper-ROMROUND);
  252.    tag = (struct systag *)(base = (base + temp->tablesize + 36L) & ~7L);
  253.    *tag = *temp;
  254.    tag->maintable = table;
  255.    
  256.    if (temp->romlo) {
  257.       tag->romlo = (ULONG *)(upper - SMALLROMSIZE - ROMROUND);
  258.       if (safeC000) {
  259.          upper = ((ULONG)safeCHIP->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
  260.          tag->romhi = (ULONG *)(upper - SMALLROMSIZE);
  261.       } else
  262.          tag->romhi = (ULONG *)(upper - SMALLROMSIZE*2 - ROMROUND);
  263.    } else {
  264.       tag->romhi = (ULONG *)(upper - temp->romsize - ROMROUND);
  265.       tag->romlo = 0L;
  266.    }
  267.  
  268.   /* Other tag initializations. */
  269.  
  270.    tag->romtype = ROM_KICK;
  271.    FillBasicTable(tag,TRUE);
  272.  
  273.    base = (base + SizeOf(struct systag) + 32L) & ~7L;
  274.  
  275.    tag->BerrHandler = (char *)(base = (base + SizeOf(struct systag)+32L) & ~7L);
  276.    tag->BerrSize = (BerrCodeSize + 4) & ~3L;
  277.  
  278.    if (tag->romlo) MemCopy(temp->romlo,tag->romlo,SMALLROMSIZE);
  279.    MemCopy(temp->romhi,tag->romhi,SMALLROMSIZE);
  280.  
  281.    tag->ResetCode = (char *)(base = (base + BerrCodeSize + 32L) & ~7L);
  282.    tag->ResetSize = BerrCodeSize;
  283.    MemCopy(BootCode,tag->ResetCode,BootCodeSize);
  284.  
  285.    return tag;
  286. }
  287.  
  288. /* This function returns memory to the system, automatically setting the
  289.    appropriate memory flags. */
  290.  
  291. void ReturnMem(size,mem)
  292. ULONG size;
  293. ULONG mem;
  294. {
  295.    if (mem < 0x00200000)
  296.       AddMemList(size,MEMF_CHIP|MEMF_PUBLIC,-15L,(char *)mem,NULL);
  297.    else if (mem >= 0x00c00000 && mem < 0x00c80000)
  298.       AddMemList(size,MEMF_FAST|MEMF_PUBLIC,-15L,(char *)mem,NULL);
  299.    else
  300.       AddMemList(size,MEMF_FAST|MEMF_PUBLIC,0L,(char *)mem,NULL);
  301. }
  302.  
  303. /* This function can be used after rebooting to remove the specially allocated
  304.    SAFE image.  This is normally used after copying the safe image into a 
  305.    standard FASTROM image and adjusting the MMU accordingly.  The SAFE RAM
  306.    at this point isn't in any memory list, so we aren't really freeing it,
  307.    just linking it into a list. */
  308.  
  309. void FreeSAFEImage(kick)
  310. struct systag *kick;
  311. {
  312.    if (kick->romlo == 0 || (ULONG)kick->romhi+SMALLROMSIZE == (ULONG)kick->romlo)
  313.       ReturnMem(ROMROUND+kick->romsize,kick->romhi);
  314.    else {
  315.       ReturnMem(ROMROUND+SMALLROMSIZE,kick->romlo);
  316.       ReturnMem(SMALLROMSIZE,kick->romhi);
  317.    }
  318. }
  319.  
  320. /* ====================================================================== */
  321.  
  322. /* This routine gets the system tag from the patched system, if it's
  323.    there.  This tag is stored in an invalid table entry that's within the
  324.    physical ROM image.  If the MMU isn't on, there's no system tag, by
  325.    definition.  This has been enhanced to perform a sanity check on the
  326.    tag encountered -- the systag contains a pointer to the table, this
  327.    can be checked. */
  328.    
  329. struct systag *GetSysTag() {
  330.    struct systag *maybetag;
  331.    ULONG i, myCRP[2], *table = NULL,size;
  332.    APTR oldTrap;
  333.    struct Task *task;
  334.  
  335.    if (cpu == 68040 || !(GetTC() & TC_ENB) || aliens) return NULL;
  336.  
  337.    GetCRP(myCRP);
  338.    table = (ULONG *)myCRP[1];
  339.  
  340.   /* In case the MMU is alien and has some of this memory read protected... */
  341.    task = FindTask(0L);
  342.    oldTrap = task->tc_TrapCode;
  343.    task->tc_TrapCode = (APTR)BerrCode;
  344.  
  345.   /* The tag is now in an easier-to-locate place. This isn't SetCPU V1.5
  346.      compatible; SetCPU V1.5 FASTROM will appear alien to SetCPU V1.6. But
  347.      this is much better for modern systems and modern software. */
  348.    size = (myCRP[0]>>16)+1;
  349.    maybetag = (struct systag *)IV_ADDR(table[size]);
  350.    if (!maybetag || maybetag->maintable != table || maybetag->tablesize != size<<2) 
  351.       maybetag = NULL;
  352.  
  353.   /* Restore the trap vector */
  354.    task->tc_TrapCode = oldTrap;
  355.    return maybetag;
  356. }
  357.  
  358.