/// <summary> /// Get an instruction block from the cache at address. If not present then call getInstanceFunc and add to the cache. /// </summary> /// <param name="address"></param> /// <param name="getInstanceFunc"></param> /// <returns></returns> public IInstructionBlock GetOrSet(ushort address, Func <IInstructionBlock> getInstanceFunc) { ICachedInstructionBlock cachedInstructionBlock; if (_cache.TryGetValue(address, out cachedInstructionBlock)) { cachedInstructionBlock.AccessedCount++; } else { var block = getInstanceFunc(); var ranges = AddressRange.GetRanges(block.Address, block.Length).ToArray(); if (ranges.Length == 1) { cachedInstructionBlock = new NormalCachedInstructionBlock(ranges[0], block); } else { cachedInstructionBlock = new CachedInstructionBlock(ranges, block); } _cache.TryAdd(block.Address, cachedInstructionBlock); AddCachedRanges(cachedInstructionBlock.AddressRanges); } return(cachedInstructionBlock.InstructionBlock); }
/// <summary> /// Invalidates all cache from address for length /// </summary> /// <param name="address"></param> /// <param name="length"></param> public void InvalidateCache(ushort address, ushort length) { var ranges = AddressRange.GetRanges(address, length).ToArray(); if (ranges.Length == 1) { var range = ranges[0]; // Lightweight check first. if (!_cachedRanges.Any(x => x.Intersects(range))) { return; } foreach (var kvp in _cache.Where(x => x.Value.Intersects(range)).ToArray()) { ICachedInstructionBlock dummy; _cache.TryRemove(kvp.Key, out dummy); UpdateCachedRanges(); } } else { var range0 = ranges[0]; var range1 = ranges[1]; // Lightweight check first. if (!_cachedRanges.Any(x => x.Intersects(range0) || x.Intersects(range1))) { return; } foreach (var key in _cache.Keys) { var cacheItem = _cache[key]; if (ranges.Any(range => cacheItem.Intersects(range))) { _cache.TryRemove(key, out cacheItem); UpdateCachedRanges(); } } } }