gem5  v21.0.1.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
DMASequencer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 ARM Limited
3  * All rights reserved.
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2008 Mark D. Hill and David A. Wood
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
42 
43 #include <memory>
44 
45 #include "debug/RubyDma.hh"
46 #include "debug/RubyStats.hh"
47 #include "mem/ruby/protocol/SequencerMsg.hh"
48 #include "mem/ruby/protocol/SequencerRequestType.hh"
50 
51 DMARequest::DMARequest(uint64_t start_paddr, int len, bool write,
52  int bytes_completed, int bytes_issued, uint8_t *data,
53  PacketPtr pkt)
54  : start_paddr(start_paddr), len(len), write(write),
55  bytes_completed(bytes_completed), bytes_issued(bytes_issued), data(data),
56  pkt(pkt)
57 {
58 }
59 
61  : RubyPort(p), m_outstanding_count(0),
62  m_max_outstanding_requests(p.max_outstanding_requests)
63 {
64 }
65 
66 void
68 {
71 }
72 
73 RequestStatus
75 {
77  return RequestStatus_BufferFull;
78  }
79 
80  Addr paddr = pkt->getAddr();
81  uint8_t* data = pkt->getPtr<uint8_t>();
82  int len = pkt->getSize();
83  bool write = pkt->isWrite();
84 
85  // Should DMA be allowed to generate this ?
86  assert(!pkt->isMaskedWrite());
87 
89  Addr line_addr = makeLineAddress(paddr);
90  auto emplace_pair =
91  m_RequestTable.emplace(std::piecewise_construct,
92  std::forward_as_tuple(line_addr),
93  std::forward_as_tuple(paddr, len, write, 0,
94  0, data, pkt));
95  DMARequest& active_request = emplace_pair.first->second;
96 
97  // This is pretty conservative. A regular Sequencer with a more beefy
98  // request table that can track multiple requests for a cache line should
99  // be used if a more aggressive policy is needed.
100  if (!emplace_pair.second) {
101  DPRINTF(RubyDma, "DMA aliased: addr %p, len %d\n", line_addr, len);
102  return RequestStatus_Aliased;
103  }
104 
105  DPRINTF(RubyDma, "DMA req created: addr %p, len %d\n", line_addr, len);
106 
107  std::shared_ptr<SequencerMsg> msg =
108  std::make_shared<SequencerMsg>(clockEdge());
109  msg->getPhysicalAddress() = paddr;
110  msg->getLineAddress() = line_addr;
111 
112  if (pkt->req->isAtomic()) {
113  msg->setType(SequencerRequestType_ATOMIC);
114 
115  // While regular LD/ST can support DMAs spanning multiple cache lines,
116  // atomic requests are only supported within a single cache line. The
117  // atomic request will end upon atomicCallback and not call issueNext.
118  int block_size = m_ruby_system->getBlockSizeBytes();
119  int atomic_offset = pkt->getAddr() - line_addr;
120  std::vector<bool> access_mask(block_size, false);
121  assert(atomic_offset + pkt->getSize() <= block_size);
122 
123  for (int idx = 0; idx < pkt->getSize(); ++idx) {
124  access_mask[atomic_offset + idx] = true;
125  }
126 
129  atomic_op(atomic_offset, pkt->getAtomicOp());
130 
131  atomic_ops.emplace_back(atomic_op);
132  msg->getwriteMask().setAtomicOps(atomic_ops);
133  } else if (write) {
134  msg->setType(SequencerRequestType_ST);
135  } else {
136  assert(pkt->isRead());
137  msg->setType(SequencerRequestType_LD);
138  }
139 
140  int offset = paddr & m_data_block_mask;
141 
142  msg->getLen() = (offset + len) <= RubySystem::getBlockSizeBytes() ?
144 
145  if (write && (data != NULL)) {
146  if (active_request.data != NULL) {
147  msg->getDataBlk().setData(data, offset, msg->getLen());
148  }
149  }
150 
152 
153  assert(m_mandatory_q_ptr != NULL);
155  active_request.bytes_issued += msg->getLen();
156 
157  return RequestStatus_Issued;
158 }
159 
160 void
162 {
163  RequestTable::iterator i = m_RequestTable.find(address);
164  assert(i != m_RequestTable.end());
165 
166  DMARequest &active_request = i->second;
167 
169  active_request.bytes_completed = active_request.bytes_issued;
170  if (active_request.len == active_request.bytes_completed) {
171  DPRINTF(RubyDma, "DMA request completed: addr %p, size %d\n",
172  address, active_request.len);
174  PacketPtr pkt = active_request.pkt;
175  m_RequestTable.erase(i);
176  ruby_hit_callback(pkt);
177  return;
178  }
179 
180  std::shared_ptr<SequencerMsg> msg =
181  std::make_shared<SequencerMsg>(clockEdge());
182  msg->getPhysicalAddress() = active_request.start_paddr +
183  active_request.bytes_completed;
184 
185  assert((msg->getPhysicalAddress() & m_data_block_mask) == 0);
186  msg->getLineAddress() = makeLineAddress(msg->getPhysicalAddress());
187 
188  msg->getType() = (active_request.write ? SequencerRequestType_ST :
189  SequencerRequestType_LD);
190 
191  msg->getLen() =
192  (active_request.len -
194  active_request.len - active_request.bytes_completed :
196 
197  if (active_request.write) {
198  msg->getDataBlk().
199  setData(&active_request.data[active_request.bytes_completed],
200  0, msg->getLen());
201  }
202 
203  assert(m_mandatory_q_ptr != NULL);
205  active_request.bytes_issued += msg->getLen();
206  DPRINTF(RubyDma,
207  "DMA request bytes issued %d, bytes completed %d, total len %d\n",
208  active_request.bytes_issued, active_request.bytes_completed,
209  active_request.len);
210 }
211 
212 void
213 DMASequencer::dataCallback(const DataBlock & dblk, const Addr& address)
214 {
215 
216  RequestTable::iterator i = m_RequestTable.find(address);
217  assert(i != m_RequestTable.end());
218 
219  DMARequest &active_request = i->second;
220  int len = active_request.bytes_issued - active_request.bytes_completed;
221  int offset = 0;
222  if (active_request.bytes_completed == 0)
223  offset = active_request.start_paddr & m_data_block_mask;
224  assert(!active_request.write);
225  if (active_request.data != NULL) {
226  memcpy(&active_request.data[active_request.bytes_completed],
227  dblk.getData(offset, len), len);
228  }
229  issueNext(address);
230 }
231 
232 void
234 {
235  assert(m_RequestTable.find(address) != m_RequestTable.end());
236  issueNext(address);
237 }
238 
239 void
240 DMASequencer::atomicCallback(const DataBlock& dblk, const Addr& address)
241 {
242  RequestTable::iterator i = m_RequestTable.find(address);
243  assert(i != m_RequestTable.end());
244 
245  DMARequest &active_request = i->second;
246  PacketPtr pkt = active_request.pkt;
247 
248  int offset = active_request.start_paddr & m_data_block_mask;
249  memcpy(pkt->getPtr<uint8_t>(), dblk.getData(offset, pkt->getSize()),
250  pkt->getSize());
251 
252  ruby_hit_callback(pkt);
253 
255  m_RequestTable.erase(i);
256 }
257 
258 void
259 DMASequencer::recordRequestType(DMASequencerRequestType requestType)
260 {
261  DPRINTF(RubyStats, "Recorded statistic: %s\n",
262  DMASequencerRequestType_to_string(requestType));
263 }
DMARequest
Definition: DMASequencer.hh:42
RubyPort::ruby_hit_callback
void ruby_hit_callback(PacketPtr pkt)
Definition: RubyPort.cc:434
RubyPort::init
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: RubyPort.cc:85
RubySystem::getBlockSizeBytes
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:61
data
const char data[]
Definition: circlebuf.test.cc:47
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:755
makeLineAddress
Addr makeLineAddress(Addr addr)
Definition: Address.cc:54
DMARequest::bytes_issued
int bytes_issued
Definition: DMASequencer.hh:51
DMASequencer::m_max_outstanding_requests
int m_max_outstanding_requests
Definition: DMASequencer.hh:86
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
DMASequencer.hh
DMARequest::data
uint8_t * data
Definition: DMASequencer.hh:52
Packet::isRead
bool isRead() const
Definition: packet.hh:557
DMARequest::bytes_completed
int bytes_completed
Definition: DMASequencer.hh:50
DMASequencer::m_RequestTable
RequestTable m_RequestTable
Definition: DMASequencer.hh:83
Packet::req
RequestPtr req
A pointer to the original request.
Definition: packet.hh:341
std::vector< bool >
Packet::getSize
unsigned getSize() const
Definition: packet.hh:765
DMASequencer::m_outstanding_count
int m_outstanding_count
Definition: DMASequencer.hh:85
MessageBuffer::enqueue
void enqueue(MsgPtr message, Tick curTime, Tick delta)
Definition: MessageBuffer.cc:191
DMASequencer::init
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: DMASequencer.cc:67
DataBlock
Definition: DataBlock.hh:54
RubyPort::m_mandatory_q_ptr
MessageBuffer * m_mandatory_q_ptr
Definition: RubyPort.hh:191
DMARequest::pkt
PacketPtr pkt
Definition: DMASequencer.hh:53
DMASequencer::atomicCallback
void atomicCallback(const DataBlock &dblk, const Addr &addr)
Definition: DMASequencer.cc:240
DMASequencer::dataCallback
void dataCallback(const DataBlock &dblk, const Addr &addr)
Definition: DMASequencer.cc:213
DMASequencer::Params
DMASequencerParams Params
Definition: DMASequencer.hh:59
Clocked::cyclesToTicks
Tick cyclesToTicks(Cycles c) const
Definition: clocked_object.hh:224
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
DataBlock::getData
const uint8_t * getData(int offset, int len) const
Definition: DataBlock.cc:105
DMARequest::DMARequest
DMARequest(uint64_t start_paddr, int len, bool write, int bytes_completed, int bytes_issued, uint8_t *data, PacketPtr pkt)
Definition: DMASequencer.cc:51
RubyPort
Definition: RubyPort.hh:58
Clocked::clockEdge
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Definition: clocked_object.hh:174
Packet::getAtomicOp
AtomicOpFunctor * getAtomicOp() const
Accessor function to atomic op.
Definition: packet.hh:793
DMASequencer::DMASequencer
DMASequencer(const Params &)
Definition: DMASequencer.cc:60
std::pair< int, AtomicOpFunctor * >
RubySystem.hh
DMASequencer::recordRequestType
void recordRequestType(DMASequencerRequestType requestType)
Definition: DMASequencer.cc:259
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:148
DMARequest::len
int len
Definition: DMASequencer.hh:48
DMASequencer::issueNext
void issueNext(const Addr &addr)
Definition: DMASequencer.cc:161
DMASequencer::makeRequest
RequestStatus makeRequest(PacketPtr pkt) override
Definition: DMASequencer.cc:74
DMASequencer::m_data_block_mask
uint64_t m_data_block_mask
Definition: DMASequencer.hh:80
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:258
ArmISA::len
Bitfield< 18, 16 > len
Definition: miscregs_types.hh:439
Packet::isMaskedWrite
bool isMaskedWrite() const
Definition: packet.hh:1374
Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
Packet::isWrite
bool isWrite() const
Definition: packet.hh:558
Packet::getPtr
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1158
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
DMARequest::start_paddr
uint64_t start_paddr
Definition: DMASequencer.hh:47
DMASequencer::ackCallback
void ackCallback(const Addr &addr)
Definition: DMASequencer.cc:233
RubyPort::m_ruby_system
RubySystem * m_ruby_system
Definition: RubyPort.hh:188
DMARequest::write
bool write
Definition: DMASequencer.hh:49
RubySystem::getBlockSizeBits
static uint32_t getBlockSizeBits()
Definition: RubySystem.hh:62
ArmISA::mask
Bitfield< 28, 24 > mask
Definition: miscregs_types.hh:711
ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:153

Generated on Tue Jun 22 2021 15:28:30 for gem5 by doxygen 1.8.17