DMASequencer.cc revision 11346:64e862d3758f
112854Sgabeblack@google.com/*
212854Sgabeblack@google.com * Copyright (c) 2008 Mark D. Hill and David A. Wood
312854Sgabeblack@google.com * All rights reserved.
412854Sgabeblack@google.com *
512854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612854Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112854Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412854Sgabeblack@google.com * this software without specific prior written permission.
1512854Sgabeblack@google.com *
1612854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712854Sgabeblack@google.com */
2812854Sgabeblack@google.com
2912854Sgabeblack@google.com#include <memory>
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com#include "debug/RubyDma.hh"
3212854Sgabeblack@google.com#include "debug/RubyStats.hh"
3312854Sgabeblack@google.com#include "mem/protocol/SequencerMsg.hh"
3412854Sgabeblack@google.com#include "mem/protocol/SequencerRequestType.hh"
3512854Sgabeblack@google.com#include "mem/ruby/system/DMASequencer.hh"
3612854Sgabeblack@google.com#include "mem/ruby/system/RubySystem.hh"
3712854Sgabeblack@google.com
3812854Sgabeblack@google.comDMASequencer::DMASequencer(const Params *p)
3912854Sgabeblack@google.com    : RubyPort(p)
4012854Sgabeblack@google.com{
4112854Sgabeblack@google.com}
4212854Sgabeblack@google.com
4312854Sgabeblack@google.comvoid
4412854Sgabeblack@google.comDMASequencer::init()
4512854Sgabeblack@google.com{
4612854Sgabeblack@google.com    RubyPort::init();
4712854Sgabeblack@google.com    m_is_busy = false;
4812854Sgabeblack@google.com    m_data_block_mask = ~ (~0 << RubySystem::getBlockSizeBits());
4912854Sgabeblack@google.com
5012854Sgabeblack@google.com    for (const auto &s_port : slave_ports)
5112854Sgabeblack@google.com        s_port->sendRangeChange();
5212854Sgabeblack@google.com}
5312854Sgabeblack@google.com
5412854Sgabeblack@google.comRequestStatus
5512854Sgabeblack@google.comDMASequencer::makeRequest(PacketPtr pkt)
5612854Sgabeblack@google.com{
5712854Sgabeblack@google.com    if (m_is_busy) {
5812854Sgabeblack@google.com        return RequestStatus_BufferFull;
5912854Sgabeblack@google.com    }
6012854Sgabeblack@google.com
6112854Sgabeblack@google.com    Addr paddr = pkt->getAddr();
6212854Sgabeblack@google.com    uint8_t* data =  pkt->getPtr<uint8_t>();
6312854Sgabeblack@google.com    int len = pkt->getSize();
6412854Sgabeblack@google.com    bool write = pkt->isWrite();
6512854Sgabeblack@google.com
6612854Sgabeblack@google.com    assert(!m_is_busy);  // only support one outstanding DMA request
6712854Sgabeblack@google.com    m_is_busy = true;
6812854Sgabeblack@google.com
6912854Sgabeblack@google.com    active_request.start_paddr = paddr;
7012854Sgabeblack@google.com    active_request.write = write;
7112854Sgabeblack@google.com    active_request.data = data;
7212854Sgabeblack@google.com    active_request.len = len;
7312854Sgabeblack@google.com    active_request.bytes_completed = 0;
7412854Sgabeblack@google.com    active_request.bytes_issued = 0;
7512854Sgabeblack@google.com    active_request.pkt = pkt;
7612854Sgabeblack@google.com
7712854Sgabeblack@google.com    std::shared_ptr<SequencerMsg> msg =
7812854Sgabeblack@google.com        std::make_shared<SequencerMsg>(clockEdge());
7912854Sgabeblack@google.com    msg->getPhysicalAddress() = paddr;
8012854Sgabeblack@google.com    msg->getLineAddress() = makeLineAddress(msg->getPhysicalAddress());
8112854Sgabeblack@google.com    msg->getType() = write ? SequencerRequestType_ST : SequencerRequestType_LD;
8212854Sgabeblack@google.com    int offset = paddr & m_data_block_mask;
8312854Sgabeblack@google.com
8412854Sgabeblack@google.com    msg->getLen() = (offset + len) <= RubySystem::getBlockSizeBytes() ?
8512854Sgabeblack@google.com        len : RubySystem::getBlockSizeBytes() - offset;
8612854Sgabeblack@google.com
8712854Sgabeblack@google.com    if (write && (data != NULL)) {
8812854Sgabeblack@google.com        if (active_request.data != NULL) {
8912854Sgabeblack@google.com            msg->getDataBlk().setData(data, offset, msg->getLen());
9012854Sgabeblack@google.com        }
9112854Sgabeblack@google.com    }
9212854Sgabeblack@google.com
9312854Sgabeblack@google.com    assert(m_mandatory_q_ptr != NULL);
9412854Sgabeblack@google.com    m_mandatory_q_ptr->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
9512854Sgabeblack@google.com    active_request.bytes_issued += msg->getLen();
9612854Sgabeblack@google.com
9712854Sgabeblack@google.com    return RequestStatus_Issued;
9812854Sgabeblack@google.com}
9912854Sgabeblack@google.com
10012854Sgabeblack@google.comvoid
10112854Sgabeblack@google.comDMASequencer::issueNext()
10212854Sgabeblack@google.com{
10312854Sgabeblack@google.com    assert(m_is_busy);
10412854Sgabeblack@google.com    active_request.bytes_completed = active_request.bytes_issued;
10512854Sgabeblack@google.com    if (active_request.len == active_request.bytes_completed) {
10612854Sgabeblack@google.com        //
10712854Sgabeblack@google.com        // Must unset the busy flag before calling back the dma port because
10812854Sgabeblack@google.com        // the callback may cause a previously nacked request to be reissued
10912854Sgabeblack@google.com        //
11012854Sgabeblack@google.com        DPRINTF(RubyDma, "DMA request completed\n");
11112854Sgabeblack@google.com        m_is_busy = false;
11212854Sgabeblack@google.com        ruby_hit_callback(active_request.pkt);
11312854Sgabeblack@google.com        return;
11412854Sgabeblack@google.com    }
11512854Sgabeblack@google.com
11612854Sgabeblack@google.com    std::shared_ptr<SequencerMsg> msg =
11712854Sgabeblack@google.com        std::make_shared<SequencerMsg>(clockEdge());
11812854Sgabeblack@google.com    msg->getPhysicalAddress() = active_request.start_paddr +
11912854Sgabeblack@google.com                                active_request.bytes_completed;
12012854Sgabeblack@google.com
12112854Sgabeblack@google.com    assert((msg->getPhysicalAddress() & m_data_block_mask) == 0);
12212854Sgabeblack@google.com    msg->getLineAddress() = makeLineAddress(msg->getPhysicalAddress());
12312854Sgabeblack@google.com
12412854Sgabeblack@google.com    msg->getType() = (active_request.write ? SequencerRequestType_ST :
12512854Sgabeblack@google.com                     SequencerRequestType_LD);
12612854Sgabeblack@google.com
12712854Sgabeblack@google.com    msg->getLen() =
12812854Sgabeblack@google.com        (active_request.len -
12912854Sgabeblack@google.com         active_request.bytes_completed < RubySystem::getBlockSizeBytes() ?
13012854Sgabeblack@google.com         active_request.len - active_request.bytes_completed :
13112854Sgabeblack@google.com         RubySystem::getBlockSizeBytes());
13212854Sgabeblack@google.com
13312854Sgabeblack@google.com    if (active_request.write) {
13412854Sgabeblack@google.com        msg->getDataBlk().
13512854Sgabeblack@google.com            setData(&active_request.data[active_request.bytes_completed],
13612854Sgabeblack@google.com                    0, msg->getLen());
13712854Sgabeblack@google.com    }
13812854Sgabeblack@google.com
13912854Sgabeblack@google.com    assert(m_mandatory_q_ptr != NULL);
14012854Sgabeblack@google.com    m_mandatory_q_ptr->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
14112854Sgabeblack@google.com    active_request.bytes_issued += msg->getLen();
14212854Sgabeblack@google.com    DPRINTF(RubyDma,
14312854Sgabeblack@google.com            "DMA request bytes issued %d, bytes completed %d, total len %d\n",
14412854Sgabeblack@google.com            active_request.bytes_issued, active_request.bytes_completed,
14512854Sgabeblack@google.com            active_request.len);
14612854Sgabeblack@google.com}
14712854Sgabeblack@google.com
14812854Sgabeblack@google.comvoid
14912854Sgabeblack@google.comDMASequencer::dataCallback(const DataBlock & dblk)
15013197Sgabeblack@google.com{
15112854Sgabeblack@google.com    assert(m_is_busy);
15212854Sgabeblack@google.com    int len = active_request.bytes_issued - active_request.bytes_completed;
15312854Sgabeblack@google.com    int offset = 0;
15412854Sgabeblack@google.com    if (active_request.bytes_completed == 0)
15512854Sgabeblack@google.com        offset = active_request.start_paddr & m_data_block_mask;
15612854Sgabeblack@google.com    assert(!active_request.write);
15712854Sgabeblack@google.com    if (active_request.data != NULL) {
15812854Sgabeblack@google.com        memcpy(&active_request.data[active_request.bytes_completed],
15912854Sgabeblack@google.com               dblk.getData(offset, len), len);
16012854Sgabeblack@google.com    }
16112854Sgabeblack@google.com    issueNext();
16212854Sgabeblack@google.com}
16312854Sgabeblack@google.com
16412854Sgabeblack@google.comvoid
16512854Sgabeblack@google.comDMASequencer::ackCallback()
16612854Sgabeblack@google.com{
16712854Sgabeblack@google.com    issueNext();
16812854Sgabeblack@google.com}
16912854Sgabeblack@google.com
17012854Sgabeblack@google.comvoid
17112854Sgabeblack@google.comDMASequencer::recordRequestType(DMASequencerRequestType requestType)
17212854Sgabeblack@google.com{
17312854Sgabeblack@google.com    DPRINTF(RubyStats, "Recorded statistic: %s\n",
17413197Sgabeblack@google.com            DMASequencerRequestType_to_string(requestType));
17512854Sgabeblack@google.com}
17612854Sgabeblack@google.com
17712854Sgabeblack@google.comDMASequencer *
17812854Sgabeblack@google.comDMASequencerParams::create()
17912854Sgabeblack@google.com{
18012854Sgabeblack@google.com    return new DMASequencer(this);
18112854Sgabeblack@google.com}
18212854Sgabeblack@google.com