// Called from the processor on a memory write (can be any size with write-through/around) // Just queues the request. bool CDMA::Cache::Write(MCID id, MemAddr address, const MemData& data, WClientID wid) { assert(address % m_lineSize == 0); // We need to arbitrate between the different processes on the cache, // and then between the different clients. There are 2 arbitrators for this. if (!p_bus.Invoke()) { // Arbitration failed DeadlockWrite("Unable to acquire bus for write"); return false; } Request req; req.address = address; req.write = true; req.client = id; req.wid = wid; COMMIT{ std::copy(data.data, data.data + m_lineSize, req.mdata.data); std::copy(data.mask, data.mask + m_lineSize, req.mdata.mask); } // Client should have been registered assert(m_clients[req.client] != NULL); if (!m_requests.Push(req)) { // Buffer was full DeadlockWrite("Unable to push write request into buffer"); return false; } // Snoop the write back to the other clients for (size_t i = 0; i < m_clients.size(); ++i) { IMemoryCallback* client = m_clients[i]; if (client != NULL && i != req.client) { if (!client->OnMemorySnooped(req.address, req.mdata.data, req.mdata.mask)) { DeadlockWrite("Unable to snoop data to cache clients"); return false; } } } return true; }
// Called from the processor on a memory write (can be any size with write-through/around) // Just queues the request. bool ZLCDMA::Cache::Write(MCID id, MemAddr address, const MemData& data, WClientID wid) { // This method can get called by several 'listeners', so we need // to arbitrate and store the request in a buffer to handle it. if (!p_bus.Invoke()) { // Arbitration failed DeadlockWrite("Unable to acquire bus for write"); return false; } Request req; req.address = address; req.write = true; req.client = id; req.wid = wid; COMMIT{ std::copy(data.data, data.data + m_lineSize, req.mdata.data); std::copy(data.mask, data.mask + m_lineSize, req.mdata.mask); } // Client should have been registered assert(m_clients[req.client] != NULL); if (!m_requests.Push(req)) { // Buffer was full DeadlockWrite("Unable to push write request into buffer"); return false; } // Snoop the write back to the other clients for (size_t i = 0; i < m_clients.size(); ++i) { IMemoryCallback* client = m_clients[i]; if (client != NULL && i != req.client) { if (!client->OnMemorySnooped(req.address, req.mdata.data, req.mdata.mask)) { DeadlockWrite("Unable to snoop data to cache clients"); return false; } } } return true; }
MCID TwoLevelCOMA::RegisterClient(IMemoryCallback& callback, Process& process, StorageTraceSet& traces, Storage& storage, bool grouped) { MCID id = m_clientMap.size(); m_clientMap.resize(id + 1); size_t abstract_id; if (grouped) { abstract_id = m_numClients - 1; } else { abstract_id = m_numClients++; } size_t cache_id = abstract_id / m_numClientsPerCache; if (cache_id == m_caches.size()) { // Add a cache if (m_caches.size() % m_numCachesPerLowRing == 0) { // First cache in a ring; add a directory CacheID firstCache = m_caches.size(); stringstream name; name << "dir" << m_directories.size(); Directory* dir = new Directory(name.str(), *this, GetClock(), firstCache, m_config); m_directories.push_back(dir); } stringstream name; name << "cache" << m_caches.size(); Cache* cache = new Cache(name.str(), *this, GetClock(), m_caches.size(), m_config); m_caches.push_back(cache); } // Forward the registration to the cache associated with the processor Cache *cache = m_caches[cache_id]; MCID id_in_cache = cache->RegisterClient(callback, process, traces, storage); m_clientMap[id] = make_pair(cache, id_in_cache); if (!grouped) m_registry.registerBidiRelation(callback.GetMemoryPeer(), *cache, "mem"); return id; }