bool FPU::OnCompletion(unsigned int unit, const Result& res) const { const CycleNo now = GetKernel()->GetActiveClock()->GetCycleNo(); Source *source = m_sources[res.source]; if (source->m_last_write == now && source->m_last_unit != unit) { DeadlockWrite("Unable to write back result because another FPU pipe already wrote back this cycle"); return false; } source->m_last_write = now; source->m_last_unit = unit; // Calculate the address of this register RegAddr addr = res.address; addr.index += res.index; if (!source->client->CheckFPUOutputAvailability(addr)) { DeadlockWrite("Client not ready to accept result"); return false; } // Write new value unsigned int index = res.index; #ifdef ARCH_BIG_ENDIAN const unsigned int size = res.size / sizeof(Integer); index = size - 1 - index; #endif RegValue value; value.m_state = RST_FULL; value.m_float.integer = (Integer)(res.value.toint(res.size) >> (sizeof(Integer) * 8 * index)); if (!source->client->WriteFPUResult(addr, value)) { DeadlockWrite("Unable to write result to %s", addr.str().c_str()); return false; } DebugFPUWrite("unit %u completed %s %s <- %s", (unsigned)unit, source->client->GetName().c_str(), addr.str().c_str(), value.str(addr.type).c_str()); return true; }
bool Processor::Network::WriteRegister(LFID fid, RemoteRegType kind, const RegAddr& raddr, const RegValue& value) { RegAddr addr = m_allocator.GetRemoteRegisterAddress(fid, kind, raddr); if (addr != INVALID_REG) { // Write it if (!m_regFile.p_asyncW.Write(addr)) { DeadlockWrite("Unable to acquire port to write register response to %s", addr.str().c_str()); return false; } if (!m_regFile.WriteRegister(addr, value, false)) { DeadlockWrite("Unable to write register response to %s", addr.str().c_str()); return false; } DebugSimWrite("F%u write %s register %s (physical %s) <- %s", (unsigned)fid, GetRemoteRegisterTypeString(kind), raddr.str().c_str(), addr.str().c_str(), value.str(addr.type).c_str() ); } return true; }
bool Processor::Network::ReadRegister(LFID fid, RemoteRegType kind, const RegAddr& raddr, RegValue& value) { const RegAddr addr = m_allocator.GetRemoteRegisterAddress(fid, kind, raddr); assert(addr != INVALID_REG); // The thread of the register has been allocated, read it if (!m_regFile.p_asyncR.Read()) { return false; } if (!m_regFile.ReadRegister(addr, value)) { return false; } if (value.m_state != RST_FULL) { /* It's possible that the last shared in a family hasn't been written. Print a warning, and return a dummy value. */ DebugProgWrite("F%u request for unwritten %s register %s (physical %s)", (unsigned)fid, GetRemoteRegisterTypeString(kind), raddr.str().c_str(), addr.str().c_str() ); value.m_state = RST_FULL; switch (addr.type) { case RT_FLOAT: value.m_float.fromfloat(0.0f); break; case RT_INTEGER: value.m_integer = 0; break; default: assert(0); // should not be here } } else { DebugSimWrite("F%u read %s register %s (physical %s) -> %s", (unsigned)fid, GetRemoteRegisterTypeString(kind), raddr.str().c_str(), addr.str().c_str(), value.str(addr.type).c_str() ); } return true; }
void RegisterFile::Cmd_Read(std::ostream& out, const std::vector<std::string>& arguments) const { // Need to change this if the RF is not directly child of parent auto& cpu = GetDRISC(); // Find the RAUnit in the same processor auto& rau = cpu.GetRAUnit(); RegType type = RT_INTEGER; size_t ix = 0; if (!arguments.empty()) { if (arguments[ix] == "float") { type = RT_FLOAT; ix++; } else if (arguments[ix] == "integer") { // already initialized above ix++; } } auto& aliases = m_local_aliases[type]; auto regs = rau.GetBlockInfo(type); set<RegIndex> indices; if (ix < arguments.size()) { indices = parse_range<RegIndex>(arguments[ix], 0, regs.size()); } else { // Default: add all registers that are part of a family for (size_t i = 0; i < regs.size(); i++) { if (regs[i] != INVALID_LFID) { indices.insert(i); } } } auto& alloc = GetDRISC().GetAllocator(); out << "Phy | Fam | Thread | Name/Alias | State / Value" << endl << "------+-----+--------+------------+--------------------------------" << endl; for (set<RegIndex>::const_reverse_iterator p = indices.rbegin(); p != indices.rend(); ++p) { RegAddr addr = MAKE_REGADDR(type, *p); LFID fid = regs[*p]; RegValue value; ReadRegister(addr, value, true); out << addr << " | "; if (fid != INVALID_LFID) out << "F" << setw(2) << setfill('0') << dec << fid; else out << " "; out << " | "; RegClass group = RC_LOCAL; size_t rel = 0; TID tid = (fid != INVALID_LFID) ? alloc.GetRegisterType(fid, addr, &group, &rel) : INVALID_TID; if (tid != INVALID_TID) { out << "T" << setw(4) << setfill('0') << tid; } else { out << " - "; } out << " | " << setfill(' '); char groupc = '\0'; switch (group) { case RC_GLOBAL: groupc = 'g'; break; case RC_DEPENDENT: groupc = 'd'; break; case RC_SHARED: groupc = 's'; break; case RC_LOCAL: groupc = 'l'; break; case RC_RAZ: break; } if (tid != INVALID_TID) { if (type == RT_FLOAT) out << groupc << 'f' << setw(2) << left << rel << right; else out << ' ' << groupc << setw(2) << left << rel << right; out << ' '; if (group == RC_LOCAL && rel < aliases.size()) out << setw(5) << aliases[rel]; else out << " - "; } else out << " - - "; out << " | " << value.str(type) << endl; } }
bool RegisterFile::WriteRegister(const RegAddr& addr, const RegValue& data, bool from_memory) { auto& regs = m_files[addr.type]; auto sz = m_sizes[addr.type]; if (addr.index >= sz) { throw SimulationException("A component attempted to write to a non-existing register", *this); } assert(data.m_state == RST_EMPTY || data.m_state == RST_PENDING || data.m_state == RST_WAITING || data.m_state == RST_FULL); if (data.m_state == RST_EMPTY || data.m_state == RST_PENDING) { assert(data.m_waiting.head == INVALID_TID); } auto& value = regs[addr.index]; if (value.m_state != RST_FULL) { if (value.m_state == RST_WAITING && data.m_state == RST_EMPTY) { throw exceptf<SimulationException>(*this, "Invalid reset of %s: %s becomes %s", addr.str().c_str(), value.str(addr.type).c_str(), data.str(addr.type).c_str()); } if (value.m_memory.size != 0) { // Check that the memory information isn't changed if (data.m_state == RST_FULL || data.m_memory.fid != value.m_memory.fid || data.m_memory.offset != value.m_memory.offset || data.m_memory.size != value.m_memory.size || data.m_memory.sign_extend != value.m_memory.sign_extend || data.m_memory.next != value.m_memory.next) { if (!from_memory) { // Only the memory can change memory-pending registers throw exceptf<SimulationException>(*this, "Invalid reset of pending load %s: %s becomes %s", addr.str().c_str(), value.str(addr.type).c_str(), data.str(addr.type).c_str()); } } } if (data.m_state == RST_FULL) { if (value.m_state == RST_WAITING && value.m_waiting.head != INVALID_TID) { // This write caused a reschedule auto& alloc = GetDRISC().GetAllocator(); if (!alloc.ActivateThreads(value.m_waiting)) { DeadlockWrite("Unable to wake up threads after write of %s: %s becomes %s", addr.str().c_str(), value.str(addr.type).c_str(), data.str(addr.type).c_str()); return false; } } } } COMMIT { #ifndef NDEBUG // Paranoid sanity check: // We cannot have multiple writes to same register in a cycle for (unsigned int i = 0; i < m_nUpdates; ++i) { assert(m_updates[i].first != addr); } #endif // Queue the update assert(m_nUpdates < MAX_UPDATES); m_updates[m_nUpdates] = make_pair(addr, data); if (m_nUpdates == 0) { RegisterUpdate(); } m_nUpdates++; } return true; }
bool FPU::OnCompletion(unsigned int unit, const Result& res) const { const CycleNo now = GetCycleNo(); Source *source = m_sources[res.source]; if (source->last_write == now && source->last_unit != unit) { DeadlockWrite("Unable to write back result because another FPU pipe already wrote back this cycle"); return false; } source->last_write = now; source->last_unit = unit; // Calculate the address of this register RegAddr addr = res.address; addr.index += res.index; if (!source->regfile->p_asyncW.Write(addr)) { DeadlockWrite("Unable to acquire port to write back to %s", addr.str().c_str()); return false; } // Read the old value RegValue value; if (!source->regfile->ReadRegister(addr, value)) { DeadlockWrite("Unable to read register %s", addr.str().c_str()); return false; } if (value.m_state != RST_PENDING && value.m_state != RST_WAITING) { // We're too fast, wait! DeadlockWrite("FP operation completed before register %s was cleared", addr.str().c_str()); return false; } // Write new value unsigned int index = res.index; #ifdef ARCH_BIG_ENDIAN const unsigned int size = res.size / sizeof(Integer); index = size - 1 - index; #endif value.m_state = RST_FULL; value.m_float.integer = (Integer)(res.value.toint(res.size) >> (sizeof(Integer) * 8 * index)); if (!source->regfile->WriteRegister(addr, value, false)) { DeadlockWrite("Unable to write register %s", addr.str().c_str()); return false; } DebugFPUWrite("unit %u completed %s %s <- %s", (unsigned)unit, source->regfile->GetParent()->GetFQN().c_str(), addr.str().c_str(), value.str(addr.type).c_str()); return true; }