}//allocateLine /// <summary> /// Read from the CacheSet. /// Check each block in the set and compare the line tag with the address. If the address tag matches the /// line tag, then we have a cache block hit. Otherwise we need to get the requested block into the /// cache and this will depend on the allocate policy. /// </summary> /// <param name="address">address to read</param> /// <param name="ms">size to read</param> /// <param name="allocatePolicy">allocation policy to use</param> /// <returns>value read</returns> public uint GetMemory(uint address, ARMPluginInterfaces.MemorySize ms, AllocatePolicyEnum allocatePolicy) { //check each line in the cache set foreach (CacheBlock cb in Blocks) { //only check valid lines and look for a tag match if (cb.Valid && ((address & cb.Mask) == cb.Tag)) { //cache read hit ReadHits++; return(cb.GetMemory(address, ms)); } } //cache read miss ReadMisses++; if (allocatePolicy != AllocatePolicyEnum.Write) { //read or both policy return(allocateLine(address).GetMemory(address, ms)); } else { //write policy, do not allocate a new cache line return(memBlock.GetMemory(address, ms)); } }//GetMemory
} //computeSetNumber /// <summary> /// Get memory from the cache. If the cache is not enabled, pass the request to main memory. /// Otherwise pass request to computed cache set. /// </summary> /// <param name="address">address to read</param> /// <param name="ms">size to read</param> /// <returns>value read</returns> public virtual uint GetMemory(uint address, ARMPluginInterfaces.MemorySize ms) { if (!this.Enabled) { return(memBlock.GetMemory(address, ms)); } //force allocate policy to be read for an L1cache return(Sets[computeSetNumber(address)].GetMemory(address, ms, ARMPluginInterfaces.Preferences.AllocatePolicyEnum.Read)); }//GetMemory
}//SetMemory /// <summary> /// Load this line from main memory. Based on the line address, go to main memory and load /// this line with data. /// </summary> /// <param name="address">address to load from</param> public void LoadFromMainMemory(uint address) { //make sure any changed memory is purged back to main memory this.Purge(); uint thisAddress = address & Mask; Tag = thisAddress; //load the cache block from main memory for (uint ii = 0; ii < Data.Length; ii++, thisAddress += 4) { Data[ii] = memBlock.GetMemory(thisAddress, ARMPluginInterfaces.MemorySize.Word); } Dirty = false; Valid = true; }//loadFromMainMemory
/// <summary> /// Gets a region of memory that can be written to. /// </summary> /// <remarks> /// If the requested region is not contiguous in physical memory, /// this will perform an allocation, and flush the data (writing it /// back to guest memory) on disposal. /// </remarks> /// <param name="va">Virtual address of the data</param> /// <param name="size">Size of the data</param> /// <returns>A writable region of memory containing the data</returns> /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception> public WritableRegion GetWritableRegion(ulong va, int size) { if (size == 0) { return(new WritableRegion(null, va, Memory <byte> .Empty)); } if (IsContiguousAndMapped(va, size)) { return(new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size))); } else { Memory <byte> memory = new byte[size]; GetSpan(va, size).CopyTo(memory.Span); return(new WritableRegion(this, va, memory)); } }