Пример #1
0
bool RegisterFile::CheckFPUOutputAvailability(RegAddr addr)
{
    if (!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 (!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;
    }

    return true;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
bool FPU::QueueOperation(size_t source, FPUOperation fop, int size, double Rav, double Rbv, const RegAddr& Rc)
{
    // The size must be a multiple of the arch's native integer size
    assert(source < m_sources.size());
    assert(m_sources[source]->regfile != NULL);
    assert(size > 0);
    assert(size % sizeof(Integer) == 0);
    assert(Rc.valid());

    Operation op;
    op.op   = fop;
    op.size = size;
    op.Rav  = Rav;
    op.Rbv  = Rbv;
    op.Rc   = Rc;

    if (!m_sources[source]->inputs.Push(op))
    {
        return false;
    }

    DebugFPUWrite("queued %s %s",
                  m_sources[source]->regfile->GetParent()->GetFQN().c_str(),
                  op.str().c_str());
    return true;
}
Пример #6
0
 bool Processor::IOInterface::WaitForNotification(IONotificationChannelID dev, const RegAddr& writeback)
 {
     if (!m_nmux.SetWriteBackAddress(dev, writeback))
     {
         DeadlockWrite("Unable to set the writeback address %s for wait on channel %u",
                       writeback.str().c_str(), (unsigned)dev);
         return false;
     }
     return true;
 }
Пример #7
0
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;
}
Пример #8
0
Processor::Pipeline::PipeAction Processor::Pipeline::WritebackStage::OnCycle()
{
    int  writebackOffset  = m_writebackOffset;
    int  size             = -1;
    bool allow_reschedule = true;
    bool suspend          = (m_input.suspend != SUSPEND_NONE);

    if (m_stall)
    {
        // We need to stall this cycle without doing *anything*.
        // Since we stall, we never commit.
        if (!IsAcquiring())
        {
            m_stall = false;
        }
        return PIPE_STALL;
    }

    if (m_input.Rrc.type != RemoteMessage::MSG_NONE)
    {
        // Network activity
        if (!m_network.SendMessage(m_input.Rrc))
        {
            DeadlockWrite("Unable to send network message");
            return PIPE_STALL;
        }
        DebugPipeWrite("F%u/T%u(%llu) %s sent network message %s",
                       (unsigned)m_input.fid, (unsigned)m_input.tid, (unsigned long long)m_input.logical_index, m_input.pc_sym,
                       m_input.Rrc.str().c_str());
    }

    if (m_input.Rcv.m_state != RST_INVALID)
    {
        // We have something to write back
        assert(m_input.Rcv.m_size % sizeof(Integer) == 0);
        size = m_input.Rcv.m_size / sizeof(Integer);

        if (writebackOffset == -1)
        {
            // New data write
            writebackOffset = 0;
        }

        if (writebackOffset < size)
        {
            // Take data from input
            RegValue value = MAKE_EMPTY_REG();
            value.m_state = m_input.Rcv.m_state;
            switch (value.m_state)
            {
            case RST_PENDING:
            case RST_WAITING:
            case RST_EMPTY:
                if (writebackOffset == 0)
                {
                    // Store the thread and memory information in the first register only
                    value.m_waiting = m_input.Rcv.m_waiting;
                    value.m_memory  = m_input.Rcv.m_memory;
                }
                break;

            case RST_FULL:
            {
                // Compose register value
                unsigned int index = writebackOffset;
#ifdef ARCH_BIG_ENDIAN
                index = size - 1 - index;
#endif
                const unsigned int shift = index * 8 * sizeof(Integer);

                switch (m_input.Rc.type)
                {
                    case RT_INTEGER: value.m_integer       = (Integer)(m_input.Rcv.m_integer.get(m_input.Rcv.m_size) >> shift); break;
                    case RT_FLOAT:   value.m_float.integer = (Integer)(m_input.Rcv.m_float.toint(m_input.Rcv.m_size) >> shift); break;
                }
                break;
            }

            default:
                // These states are never written from the pipeline
                UNREACHABLE;
            }

            if (m_input.Rc.valid())
            {
                // Get the address of the register we're writing.
                const RegAddr addr = MAKE_REGADDR(m_input.Rc.type, m_input.Rc.index + writebackOffset);

                // We have something to write back
                if (!m_regFile.p_pipelineW.Write(addr))
                {
                    DeadlockWrite("F%u/T%u(%llu) %s unable to acquire write port on RF",
                                  (unsigned)m_input.fid, (unsigned)m_input.tid, (unsigned long long)m_input.logical_index,
                                  m_input.pc_sym);

                    return PIPE_STALL;
                }

                // Read the old value
                RegValue old_value;
                if (!m_regFile.ReadRegister(addr, old_value))
                {
                    DeadlockWrite("F%u/T%u(%llu) %s unable to read prev %s",
                                  (unsigned)m_input.fid, (unsigned)m_input.tid, (unsigned long long)m_input.logical_index,
                                  m_input.pc_sym,
                                  addr.str().c_str());

                    return PIPE_STALL;
                }

                if (value.m_state == RST_WAITING)
                {
                    assert(suspend == true);

                    if (old_value.m_state == RST_FULL)
                    {
                        // The data we wanted to wait for has returned before we could write the register.
                        // Just reschedule the thread.
                        suspend = false;
                        value.m_state = RST_INVALID;

                        DebugPipeWrite("F%u/T%u(%llu) %s data arrived in %s since read, rescheduling",
                                      (unsigned)m_input.fid, (unsigned)m_input.tid, (unsigned long long)m_input.logical_index,
                                       m_input.pc_sym,
                                       addr.str().c_str());
                    }
                    else
                    {
                        assert(value.m_waiting.head == m_input.tid);

                        // The Read Stage will have setup the register to
                        // link this thread into the register's thread waiting list
                        if (old_value.m_state == RST_WAITING && old_value.m_waiting.head != INVALID_TID)
                        {
                            // Not the first thread waiting on the register
                            // Update the tail
                            assert(value.m_waiting.tail == old_value.m_waiting.tail);
                        }
                        else
                        {
                            assert(value.m_waiting.tail == m_input.tid);
                        }

                        COMMIT
                        {
                            // We're suspending because we're waiting on a non-full register.
                            // Since we support multiple threads waiting on a register, update the
                            // next field in the thread table to the next waiting thread.
                            m_threadTable[m_input.tid].next = old_value.m_waiting.head;
                        }
                    }
                }
                else if (value.m_state == RST_PENDING && old_value.m_state == RST_WAITING)
Пример #9
0
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;
}