📄 excache.c
字号:
/* excache.c - Memory veneer that models a simple cache. * Copyright (C) Advanced RISC Machines Limited, 1997. * All rights reserved. */#include "armdefs.h"#include "armcnf.h"#define ModelName (tag_t)"ExampleCache"#define CACHELINES 128#define LINESIZE 4#define TAGMASK ( ~((LINESIZE-1) << 2) )typedef struct { unsigned int bigendSig; /* fetchingLine contains the line and current word * being fetched */ unsigned int fetchingLine;#define FETCHINGFLAG 0x80000000L struct { ARMword tag; ARMword word[LINESIZE]; } line[CACHELINES]; ARMul_MemInterface child;} cache_state;#define INVALIDTAG 0xffffffffL/* * ARMulator callbacks */static void ConfigChange(void *handle, ARMword old, ARMword new){ cache_state *cache = (cache_state *)handle; IGNORE(old); cache->bigendSig = ((new & MMU_B) != 0);}static void Interrupt(void *handle,unsigned int which){ cache_state *cache = (cache_state *)handle; if (which & ARMul_InterruptUpcallReset) { /* On reset, invalidate all the cache entries */ unsigned int i; for (i = 0; i < CACHELINES; i++) cache->line[i].tag = INVALIDTAG; /* Stop any pending line fetch */ cache->fetchingLine = 0; }}/* * Cache model functions */static int CacheLineReplace(cache_state *cache){ /* start/continue a line fetch */ unsigned int fetching = cache->fetchingLine; /* extract word/line from 'fetching' */ unsigned int word = fetching % LINESIZE; unsigned int line =(fetching / LINESIZE) % CACHELINES; ARMword addr, *ptr; ARMul_acc acc; /* construct address from cache tag */ addr = cache->line[line].tag | (word << 2); /* first fetch is non-sequential */ if (word == 0) acc = acc_LoadWordN; else acc = acc_LoadWordS; /* Call the external memory system */ ptr = &cache->line[line].word[word]; switch (cache->child.x.basic.access(cache->child.handle, addr, ptr, acc)) { case 1: /* fetch successful */ if (word == LINESIZE-1) cache->fetchingLine = 0; else cache->fetchingLine = fetching+1; return 0; case 0: /* wait - try again next cycle */ return 0; case -1: default: /* abort line fetch, abort core */ cache->line[line].tag = INVALIDTAG; cache->fetchingLine = 0; return -1; }}/* Read and write to the cache *//* * Read a word from cache, doing an idle cycle on * the external bus */static int ReadFromCacheLine( cache_state *cache, ARMword addr, ARMword *word, ARMul_acc acc, unsigned int line){ /* addr has been found in line 'line' - perform access * and return */ ARMword *ptr; ptr = &(cache->line[line].word[(addr >> 2) % LINESIZE]); /* do an idle cycle on the external bus */ if (acc_ACCOUNT(acc)) cache->child.x.basic.access(cache->child.handle, addr, word, acc_Icycle); /* Standard read code [from armflat.c] */ switch (acc & WIDTH_MASK) { case BITS_8: /* read byte */ if (HostEndian != cache->bigendSig) addr ^= 3; *word = ((unsigned8 *)ptr)[addr & 3]; break; case BITS_16: { /* read half-word */ /* extract half-word */#ifndef HOST_HAS_NO_16BIT_TYPE /* * unsigned16 is always a 16-bit type, but if there is * no native 16-bit type (e.g. ARM!) then we can do * something a bit more cunning. */ if (HostEndian != cache->bigendSig) addr ^= 2; *word = *((unsigned16 *)(((char *)ptr)+(addr & 2)));#else unsigned32 datum; datum=*ptr; if (HostEndian != cache->bigendSig) addr ^= 2; if (addr & 2) datum <<= 16; *word = (datum >> 16);#endif } break; case BITS_32: /* read word */ *word = *ptr; break; default: return -1; } return 1;}/* * Write to data that's in the cache. * Update the cache entry, but don't do any external * activity (done at the higher level). */static int WriteToCacheLine( cache_state *cache, ARMword addr, ARMword *word, ARMul_acc acc, unsigned int line){ /* addr has been found in line 'line' - update cache * and return */ ARMword *ptr; ptr = &(cache->line[line].word[(addr >> 2) % LINESIZE]); /* Standard 'write' code [from armflat.c] */ switch (acc & WIDTH_MASK) { /* extract byte */ case BITS_8: /* write_byte */ if (HostEndian != cache->bigendSig) addr ^= 3; ((unsigned8 *)ptr)[addr & 3] = (unsigned8)(*word); break; case BITS_16: /* write half-word */ if (HostEndian != cache->bigendSig) addr ^= 2; *((unsigned16 *)(((char *)ptr) + (addr & 2))) = (unsigned16)(*word); break; case BITS_32: /* write word */ *ptr = *word; break; default: return -1; } return 1;}/* * Memory veneer functions */static int MemAccess(void *handle, ARMword addr, ARMword *word, ARMul_acc acc){ cache_state *cache = (cache_state *)handle; ARMword tag; unsigned int line; /* check if we're in the middle of a line fetch */ if (acc_ACCOUNT(acc) && cache->fetchingLine != 0) return CacheLineReplace(cache); if (acc_MREQ(acc)) { /* search through the cache tags */ tag = addr & TAGMASK; for (line = 0; line < CACHELINES; line++) if (cache->line[line].tag == tag) { /* cache hit! */ if (acc_READ(acc)) return ReadFromCacheLine( cache, addr, word, acc, line); else WriteToCacheLine(cache, addr, word, acc, line); /* and fall through to update external memory */ } /* fall through from searching cache */ if (acc_READ(acc)) { if (acc_ACCOUNT(acc)) { /* cache miss - choose a victim to replace */ /* Unix rand() has the bad property that * rand() % 4 is cyclic */ line = ((rand() >> 2) % CACHELINES); /* set up fetchingLine with the line number. * FETCHINGFLAG is used to ensure the result * is non-zero. start with word 0. */ cache->fetchingLine = ( (line * LINESIZE) + FETCHINGFLAG ); cache->line[line].tag = tag; /* start a line fetch */ return CacheLineReplace(cache); } /* else read from memory - fall through */ } /* else write to physical memory - cache already * updated */ /* fall through */ } /* else do idle cycle on external bus - fall through */ return cache->child.x.basic.access(cache->child.handle, addr, word, acc);}/* Dummy veneer functions *//* These functions pass on their calls directly to the * child model. We can't use the child functions directly, * as we need to lookup the child's handle */static unsigned long GetCycleLength(void *handle){ cache_state *cache = (cache_state *)handle; return cache->child.x.basic.get_cycle_length(cache->child.handle);}static unsigned long ReadClock(void *handle){ cache_state *cache = (cache_state *)handle; return cache->child.read_clock(cache->child.handle);}static const ARMul_Cycles *ReadCycles(void *handle){ cache_state *cache = (cache_state *)handle; return cache->child.read_cycles(cache->child.handle);}/* * Initialize the memory interface */static ARMul_Error MemInit( ARMul_State *state, ARMul_MemInterface *interf, ARMul_MemType type, toolconf config){ cache_state *cache; ARMul_MemInterface *child_interf; armul_MemInit *child_init = NULL; tag_t child_name; toolconf child_config; ARMul_Error err; /* Find the name of the child memory interface */ child_name = (tag_t)ToolConf_Lookup(config, ARMulCnf_Memory); /* Now locate it using ARMul_FindMemoryInterface. * This also locates it's config for us */ if (child_name) child_init = ARMul_FindMemoryInterface(state, child_name, &child_config); if (child_name == NULL || child_init == NULL || child_init == MemInit) return ARMul_RaiseError(state, ARMulErr_NoMemoryChild, ModelName); /* Allocate the cache state */ cache = (cache_state *)malloc(sizeof(cache_state)); if (cache == NULL) return ARMul_RaiseError(state,ARMulErr_OutOfMemory); /* Initialize the child model */ child_interf = &cache->child; err = child_init(state, child_interf, type, child_config); if (err != ARMulErr_NoError) { free(cache); return err; } /* Set up our interface with the ARMulator */ interf->handle = cache; interf->read_clock = (child_interf->read_clock != NULL) ? ReadClock : NULL; interf->read_cycles = (child_interf->read_cycles != NULL) ? ReadCycles : NULL; switch (type) { case ARMul_MemType_Basic: case ARMul_MemType_16Bit: case ARMul_MemType_Thumb: /* supported */ interf->x.basic.access=MemAccess; interf->x.basic.get_cycle_length = (child_interf->x.basic.get_cycle_length != NULL) ? GetCycleLength : NULL; break; default: *interf = *child_interf; free(cache); ARMul_ConsolePrint(state,"\Cannot use cache on this type of memory interface.\n"); return ARMulErr_NoError; } ARMul_PrettyPrint(state,", Simple cache"); /* Install callbacks */ ARMul_InstallExitHandler(state, free, cache); ARMul_InstallInterruptHandler(state, Interrupt, cache); ARMul_InstallConfigChangeHandler(state, ConfigChange, cache); /* Initialize the model - we should get a reset anyway, * but better safe than sorry */ Interrupt((void *)cache, ARMul_InterruptUpcallReset); return ARMulErr_NoError;}ARMul_MemStub ARMul_ExampleCache = { MemInit, ModelName};/* end of file excache.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -