home *** CD-ROM | disk | FTP | other *** search
- /*
- SetCPU V1.60
- by Dave Haynie, April 13, 1990
- Released to the Public Domain
-
- MEMORY.C MODULE
-
- This module is responsible for ROM image allocation, MMU table
- allocation and creation, and other functions based on memory.
- */
-
- #include "setcpu.h"
-
- /* ====================================================================== */
-
- /* Local data types */
-
- struct range {
- ULONG first;
- ULONG last;
- };
-
- /* ====================================================================== */
-
- /* This function copies from the source to the destination, by longword, with
- BYTE length "length". */
-
- void MemCopy(src,des,len)
- ULONG *src, *des;
- ULONG len;
- {
- len = (len + 3)>>2;
- while (len--) *des++ = *src++;
- }
-
- /* ====================================================================== */
-
- /* This section contains the memory allocation code. There are two
- problems here. First of all, we'd like to use 32 bit FAST memory if
- at all possible. Next, block translation and page tables must be on at
- least a page sized boundary, if not a block boundary. */
-
- /* This routine finds the memory block for me to use in AllocAligned().
- It takes into account either A2620 or A2630 systems, where I can snoop
- out the memory for that particular board, knowing it's the fastest. I
- can adjust for 1.4's automatic memory merging in this case too, to be
- sure I have 32 bit RAM. If I don't have one of my boards, I'll return
- a pointer to the first non-$C00000 memory list marked as FAST. */
-
- static struct range SRange = { 0L, 0L };
- static ULONG MaxMem = 0;
-
- LONG SmartlyGetRange() {
- struct ExecBase *eb = *((struct ExecBase **)4L);
- register struct MemHeader *mem;
-
- /* First try for either A2620 or A2630 */
-
- if (A26x0.Addr && A26x0.Size) {
- SRange.first = A26x0.Addr;
- SRange.last = A26x0.Size + SRange.first;
- }
-
- /* For another critters, but we go here to find MaxMem, even
- if we know it's an A26x0. */
-
- for (mem = (struct MemHeader *)eb->MemList.lh_Head; mem->mh_Node.ln_Succ;
- mem = (struct MemHeader *)mem->mh_Node.ln_Succ) {
- if ((ULONG)(mem->mh_Upper) > MaxMem) MaxMem = (ULONG)mem->mh_Upper;
- if (mem->mh_Attributes & MEMF_CHIP) continue;
- if (((ULONG)mem >= 0xc00000 && (ULONG)mem <= 0xc80000)) continue;
- if (!SRange.first) {
- SRange.first = (ULONG)mem->mh_Lower;
- SRange.last = (ULONG)mem->mh_Upper;
- }
- }
- if (SRange.first)
- return TRUE;
- return FALSE;
- }
-
- /* This routine allocates such an aligned block of memory from a specified
- memory list. */
-
- void *AllocAligned(size,bound)
- register ULONG size;
- register ULONG bound;
- {
- register ULONG target;
- void *mem = NULL;
-
- Forbid();
- if (!allochead) {
- target = (SRange.last-size) & ~(bound-1);
- while (target > SRange.first && !(mem = AllocAbs(size,target)))
- target -= bound;
- SRange.last = (ULONG)mem;
- } else {
- target = (SRange.first+size+bound-1) & ~(bound-1);
- while (target < SRange.last && !(mem = AllocAbs(size,target)))
- target += bound;
- SRange.first = (ULONG)mem+size;
- }
- Permit();
- return mem;
- }
-
- /* This routine finds the memory wrap and appropriate MMU table size for
- the given configuration. It requires the value of MaxMem to have been
- already calculated. */
-
- void FindWrap(tag)
- struct systag *tag;
- {
- ULONG test;
-
- if (forcewrap == -1) {
- tag->wrapdown = 0;
- for (test = MaxMem; !(test & 0x80000000) && tag->wrapdown < 8; test <<= 1)
- tag->wrapdown++;
- } else
- tag->wrapdown = forcewrap;
- tag->tablesize = (128 << (8 - tag->wrapdown)) * sizeof(ULONG);
- }
-
- /* This routine computes the ROM size from the magic tag values. */
-
- ULONG CalcROMSize(tagval)
- ULONG tagval;
- {
- if (tagval == MAGIC_256) return SMALLROMSIZE;
- if (tagval == MAGIC_512) return BIGROMSIZE;
- return 0L;
- }
-
- /* This function sizes the ROM based on its base value and correctly splits
- a base address between possible ROM halves. This routine uses the Commodore
- ROM file format, which is like this:
-
- 0: 00000000
- 4: size
- 8: start of ROM
-
- The ROM, in any case, begins with either "$11114ef9", for 256L ROMs, or
- "$11144ef9", for 512K ROMs. The next longword can be used to figure out
- where the ROM actually goes, in memory. */
-
- ULONG *SizeROM(tag,base,getram)
- struct systag *tag;
- ULONG *base, getram;
- {
- ULONG *rom = NULL;
-
- if (!(tag->romsize = CalcROMSize(base[0]))) return NULL;
-
- if (getram)
- if (!(rom = (ULONG *)AllocAligned(tag->romsize,ROMROUND))) return NULL;
-
- if (tag->romsize == SMALLROMSIZE) {
- tag->romstart = base[1];
- tag->romloc = base[1] & 0xfffc0000;
- tag->romlo = 0L;
- tag->romhi = rom;
- } else {
- tag->romstart = base[1];
- tag->romloc = base[1] & 0xfff80000;
- tag->romlo = rom;
- tag->romhi = (ULONG *)((ULONG)rom + SMALLROMSIZE);
- }
- return rom;
- }
-
- /* ====================================================================== */
-
- /* This section contains routines that manage different ROM image types. */
-
- /* This function gets an aligned ROM image copied from system ROM. */
-
- struct systag *AllocROMImage(type)
- UWORD type;
- {
- struct systag *tag = NULL, *oldtag = NULL;
- ULONG *rom = NULL, *table = NULL, *base;
-
- /* Let's make the allocations. I allocate the ROM first, then the table,
- then the tag; since we're coming from the end of memory, this should
- result in the least fragging. */
-
- SmartlyGetRange();
- if (!(tag = AllocAligned(SizeOf(struct systag),8L))) goto fail;
- if (oldtag = GetSysTag())
- base = (ULONG *)oldtag->romloc;
- else {
- if (*(base = (ULONG *)0x00f80000) != MAGIC_512)
- base = (ULONG *)0x00fc0000;
- }
- rom = SizeROM(tag,base,TRUE);
- FindWrap(tag);
- if (!(table = AllocAligned(tag->tablesize+4,TABROUND))) goto fail;
- tag->maintable = table;
- tag->romtype = type;
- MemCopy(tag->romloc,rom,tag->romsize);
- FillBasicTable(tag,FALSE);
- return tag;
-
- fail:
- if (rom) FreeMem(rom,tag->romsize);
- if (table) FreeMem(table,tag->tablesize+4);
- if (tag) FreeMem(tag,SizeOf(struct systag));
- return NULL;
- }
-
- /* This function gets an aligned, reset-safe image in either $00C00000 or
- CHIP memory, copies the ROM code from the passed temporary image, and
- then sets up it's MMU table such that the memory used for the safe image
- will be missed by the Amiga's memory-sizing logic on reboot. */
-
- struct systag *AllocSAFEImage(temp)
- struct systag *temp;
- {
- struct ExecBase *eb = *((struct ExecBase **)4L);
- struct MemHeader *safe, *safeC000 = NULL, *safeCHIP = NULL, *tmem;
- struct systag *tag;
- ULONG upper, base, *table;
-
- for (safe = (struct MemHeader *)eb->MemList.lh_Head; safe->mh_Node.ln_Succ;
- safe = (struct MemHeader *)safe->mh_Node.ln_Succ) {
- tmem = (struct MemHeader *)safe;
- if ((ULONG)(tmem->mh_Upper) > MaxMem) MaxMem = (ULONG)tmem->mh_Upper;
- if (tmem->mh_Attributes & MEMF_CHIP) {
- if (!safeCHIP || safeCHIP->mh_Upper < tmem->mh_Upper)
- safeCHIP = tmem;
- } else if ((ULONG)safe >= 0xc00000 && (ULONG)safe <= 0xc80000) {
- if (!safeC000 || safeC000->mh_Upper < tmem->mh_Upper)
- safeC000 = tmem;
- }
- }
-
- /* Will it fit? You need at least 1 meg of memory. */
-
- if (!safeC000 && safeCHIP->mh_Upper < 0x080000L) return NULL;
-
- /* Now, where should it go. */
-
- if (safeC000)
- upper = ((ULONG)safeC000->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
- else if (safeCHIP)
- upper = ((ULONG)safeCHIP->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
-
- FindWrap(temp);
- table = (ULONG *)(base = upper-ROMROUND);
- tag = (struct systag *)(base = (base + temp->tablesize + 36L) & ~7L);
- *tag = *temp;
- tag->maintable = table;
-
- if (temp->romlo) {
- tag->romlo = (ULONG *)(upper - SMALLROMSIZE - ROMROUND);
- if (safeC000) {
- upper = ((ULONG)safeCHIP->mh_Upper+ROMROUND-1L) & ~(ROMROUND-1L);
- tag->romhi = (ULONG *)(upper - SMALLROMSIZE);
- } else
- tag->romhi = (ULONG *)(upper - SMALLROMSIZE*2 - ROMROUND);
- } else {
- tag->romhi = (ULONG *)(upper - temp->romsize - ROMROUND);
- tag->romlo = 0L;
- }
-
- /* Other tag initializations. */
-
- tag->romtype = ROM_KICK;
- FillBasicTable(tag,TRUE);
-
- base = (base + SizeOf(struct systag) + 32L) & ~7L;
-
- tag->BerrHandler = (char *)(base = (base + SizeOf(struct systag)+32L) & ~7L);
- tag->BerrSize = (BerrCodeSize + 4) & ~3L;
-
- if (tag->romlo) MemCopy(temp->romlo,tag->romlo,SMALLROMSIZE);
- MemCopy(temp->romhi,tag->romhi,SMALLROMSIZE);
-
- tag->ResetCode = (char *)(base = (base + BerrCodeSize + 32L) & ~7L);
- tag->ResetSize = BerrCodeSize;
- MemCopy(BootCode,tag->ResetCode,BootCodeSize);
-
- return tag;
- }
-
- /* This function returns memory to the system, automatically setting the
- appropriate memory flags. */
-
- void ReturnMem(size,mem)
- ULONG size;
- ULONG mem;
- {
- if (mem < 0x00200000)
- AddMemList(size,MEMF_CHIP|MEMF_PUBLIC,-15L,(char *)mem,NULL);
- else if (mem >= 0x00c00000 && mem < 0x00c80000)
- AddMemList(size,MEMF_FAST|MEMF_PUBLIC,-15L,(char *)mem,NULL);
- else
- AddMemList(size,MEMF_FAST|MEMF_PUBLIC,0L,(char *)mem,NULL);
- }
-
- /* This function can be used after rebooting to remove the specially allocated
- SAFE image. This is normally used after copying the safe image into a
- standard FASTROM image and adjusting the MMU accordingly. The SAFE RAM
- at this point isn't in any memory list, so we aren't really freeing it,
- just linking it into a list. */
-
- void FreeSAFEImage(kick)
- struct systag *kick;
- {
- if (kick->romlo == 0 || (ULONG)kick->romhi+SMALLROMSIZE == (ULONG)kick->romlo)
- ReturnMem(ROMROUND+kick->romsize,kick->romhi);
- else {
- ReturnMem(ROMROUND+SMALLROMSIZE,kick->romlo);
- ReturnMem(SMALLROMSIZE,kick->romhi);
- }
- }
-
- /* ====================================================================== */
-
- /* 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, there's no system tag, by
- definition. This has been enhanced to perform a sanity check on the
- tag encountered -- the systag contains a pointer to the table, this
- can be checked. */
-
- struct systag *GetSysTag() {
- struct systag *maybetag;
- ULONG i, myCRP[2], *table = NULL,size;
- APTR oldTrap;
- struct Task *task;
-
- if (cpu == 68040 || !(GetTC() & TC_ENB) || aliens) return NULL;
-
- GetCRP(myCRP);
- table = (ULONG *)myCRP[1];
-
- /* In case the MMU is alien and has some of this memory read protected... */
- task = FindTask(0L);
- oldTrap = task->tc_TrapCode;
- task->tc_TrapCode = (APTR)BerrCode;
-
- /* The tag is now in an easier-to-locate place. This isn't SetCPU V1.5
- compatible; SetCPU V1.5 FASTROM will appear alien to SetCPU V1.6. But
- this is much better for modern systems and modern software. */
- size = (myCRP[0]>>16)+1;
- maybetag = (struct systag *)IV_ADDR(table[size]);
- if (!maybetag || maybetag->maintable != table || maybetag->tablesize != size<<2)
- maybetag = NULL;
-
- /* Restore the trap vector */
- task->tc_TrapCode = oldTrap;
- return maybetag;
- }
-
-