gem5  v22.1.0.0
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 namespace gem5
52 {
53 
54 namespace ruby
55 {
56 
57 DMARequest::DMARequest(uint64_t start_paddr, int len, bool write,
58  int bytes_completed, int bytes_issued, uint8_t *data,
59  PacketPtr pkt)
60  : start_paddr(start_paddr), len(len), write(write),
61  bytes_completed(bytes_completed), bytes_issued(bytes_issued), data(data),
62  pkt(pkt)
63 {
64 }
65 
67  : RubyPort(p), m_outstanding_count(0),
68  m_max_outstanding_requests(p.max_outstanding_requests)
69 {
70 }
71 
72 void
74 {
77 }
78 
79 RequestStatus
81 {
83  return RequestStatus_BufferFull;
84  }
85 
86  Addr paddr = pkt->getAddr();
87  uint8_t* data = pkt->getPtr<uint8_t>();
88  int len = pkt->getSize();
89  bool write = pkt->isWrite();
90 
91  // Should DMA be allowed to generate this ?
92  assert(!pkt->isMaskedWrite());
93 
95  Addr line_addr = makeLineAddress(paddr);
96  auto emplace_pair =
97  m_RequestTable.emplace(std::piecewise_construct,
98  std::forward_as_tuple(line_addr),
99  std::forward_as_tuple(paddr, len, write, 0,
100  0, data, pkt));
101  DMARequest& active_request = emplace_pair.first->second;
102 
103  // This is pretty conservative. A regular Sequencer with a more beefy
104  // request table that can track multiple requests for a cache line should
105  // be used if a more aggressive policy is needed.
106  if (!emplace_pair.second) {
107  DPRINTF(RubyDma, "DMA aliased: addr %p, len %d\n", line_addr, len);
108  return RequestStatus_Aliased;
109  }
110 
111  DPRINTF(RubyDma, "DMA req created: addr %p, len %d\n", line_addr, len);
112 
113  std::shared_ptr<SequencerMsg> msg =
114  std::make_shared<SequencerMsg>(clockEdge());
115  msg->getPhysicalAddress() = paddr;
116  msg->getLineAddress() = line_addr;
117 
118  if (pkt->req->isAtomic()) {
119  msg->setType(SequencerRequestType_ATOMIC);
120 
121  // While regular LD/ST can support DMAs spanning multiple cache lines,
122  // atomic requests are only supported within a single cache line. The
123  // atomic request will end upon atomicCallback and not call issueNext.
124  int block_size = m_ruby_system->getBlockSizeBytes();
125  int atomic_offset = pkt->getAddr() - line_addr;
126  std::vector<bool> access_mask(block_size, false);
127  assert(atomic_offset + pkt->getSize() <= block_size);
128 
129  for (int idx = 0; idx < pkt->getSize(); ++idx) {
130  access_mask[atomic_offset + idx] = true;
131  }
132 
135  atomic_op(atomic_offset, pkt->getAtomicOp());
136 
137  atomic_ops.emplace_back(atomic_op);
138  msg->getwriteMask().setAtomicOps(atomic_ops);
139  } else if (write) {
140  msg->setType(SequencerRequestType_ST);
141  } else {
142  assert(pkt->isRead());
143  msg->setType(SequencerRequestType_LD);
144  }
145 
146  int offset = paddr & m_data_block_mask;
147 
148  msg->getLen() = (offset + len) <= RubySystem::getBlockSizeBytes() ?
150 
151  if (write && (data != NULL)) {
152  if (active_request.data != NULL) {
153  msg->getDataBlk().setData(data, offset, msg->getLen());
154  }
155  }
156 
158 
159  assert(m_mandatory_q_ptr != NULL);
161  active_request.bytes_issued += msg->getLen();
162 
163  return RequestStatus_Issued;
164 }
165 
166 void
168 {
169  RequestTable::iterator i = m_RequestTable.find(address);
170  assert(i != m_RequestTable.end());
171 
172  DMARequest &active_request = i->second;
173 
175  active_request.bytes_completed = active_request.bytes_issued;
176  if (active_request.len == active_request.bytes_completed) {
177  DPRINTF(RubyDma, "DMA request completed: addr %p, size %d\n",
178  address, active_request.len);
180  PacketPtr pkt = active_request.pkt;
181  m_RequestTable.erase(i);
182  ruby_hit_callback(pkt);
183  return;
184  }
185 
186  std::shared_ptr<SequencerMsg> msg =
187  std::make_shared<SequencerMsg>(clockEdge());
188  msg->getPhysicalAddress() = active_request.start_paddr +
189  active_request.bytes_completed;
190 
191  assert((msg->getPhysicalAddress() & m_data_block_mask) == 0);
192  msg->getLineAddress() = makeLineAddress(msg->getPhysicalAddress());
193 
194  msg->getType() = (active_request.write ? SequencerRequestType_ST :
195  SequencerRequestType_LD);
196 
197  msg->getLen() =
198  (active_request.len -
200  active_request.len - active_request.bytes_completed :
202 
203  if (active_request.write) {
204  msg->getDataBlk().
205  setData(&active_request.data[active_request.bytes_completed],
206  0, msg->getLen());
207  }
208 
209  assert(m_mandatory_q_ptr != NULL);
211  active_request.bytes_issued += msg->getLen();
212  DPRINTF(RubyDma,
213  "DMA request bytes issued %d, bytes completed %d, total len %d\n",
214  active_request.bytes_issued, active_request.bytes_completed,
215  active_request.len);
216 }
217 
218 void
219 DMASequencer::dataCallback(const DataBlock & dblk, const Addr& address)
220 {
221 
222  RequestTable::iterator i = m_RequestTable.find(address);
223  assert(i != m_RequestTable.end());
224 
225  DMARequest &active_request = i->second;
226  int len = active_request.bytes_issued - active_request.bytes_completed;
227  int offset = 0;
228  if (active_request.bytes_completed == 0)
229  offset = active_request.start_paddr & m_data_block_mask;
230  assert(!active_request.write);
231  if (active_request.data != NULL) {
232  memcpy(&active_request.data[active_request.bytes_completed],
233  dblk.getData(offset, len), len);
234  }
235  issueNext(address);
236 }
237 
238 void
240 {
241  assert(m_RequestTable.find(address) != m_RequestTable.end());
242  issueNext(address);
243 }
244 
245 void
246 DMASequencer::atomicCallback(const DataBlock& dblk, const Addr& address)
247 {
248  RequestTable::iterator i = m_RequestTable.find(address);
249  assert(i != m_RequestTable.end());
250 
251  DMARequest &active_request = i->second;
252  PacketPtr pkt = active_request.pkt;
253 
254  int offset = active_request.start_paddr & m_data_block_mask;
255  memcpy(pkt->getPtr<uint8_t>(), dblk.getData(offset, pkt->getSize()),
256  pkt->getSize());
257 
258  ruby_hit_callback(pkt);
259 
261  m_RequestTable.erase(i);
262 }
263 
264 void
265 DMASequencer::recordRequestType(DMASequencerRequestType requestType)
266 {
267  DPRINTF(RubyStats, "Recorded statistic: %s\n",
268  DMASequencerRequestType_to_string(requestType));
269 }
270 
271 } // namespace ruby
272 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
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...
Tick cyclesToTicks(Cycles c) const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isRead() const
Definition: packet.hh:592
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1212
Addr getAddr() const
Definition: packet.hh:805
AtomicOpFunctor * getAtomicOp() const
Accessor function to atomic op.
Definition: packet.hh:843
bool isWrite() const
Definition: packet.hh:593
RequestPtr req
A pointer to the original request.
Definition: packet.hh:376
unsigned getSize() const
Definition: packet.hh:815
bool isMaskedWrite() const
Definition: packet.hh:1428
void dataCallback(const DataBlock &dblk, const Addr &addr)
DMASequencerParams Params
Definition: DMASequencer.hh:65
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: DMASequencer.cc:73
void issueNext(const Addr &addr)
DMASequencer(const Params &)
Definition: DMASequencer.cc:66
RequestStatus makeRequest(PacketPtr pkt) override
Definition: DMASequencer.cc:80
void ackCallback(const Addr &addr)
void atomicCallback(const DataBlock &dblk, const Addr &addr)
RequestTable m_RequestTable
Definition: DMASequencer.hh:89
void recordRequestType(DMASequencerRequestType requestType)
const uint8_t * getData(int offset, int len) const
Definition: DataBlock.cc:111
void enqueue(MsgPtr message, Tick curTime, Tick delta)
void ruby_hit_callback(PacketPtr pkt)
Definition: RubyPort.cc:454
RubySystem * m_ruby_system
Definition: RubyPort.hh:197
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: RubyPort.cc:92
MessageBuffer * m_mandatory_q_ptr
Definition: RubyPort.hh:200
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:72
static uint32_t getBlockSizeBits()
Definition: RubySystem.hh:73
STL pair class.
Definition: stl.hh:58
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
uint16_t len
Definition: helpers.cc:62
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 54 > p
Definition: pagetable.hh:70
Addr makeLineAddress(Addr addr)
Definition: Address.cc:60
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
DMARequest(uint64_t start_paddr, int len, bool write, int bytes_completed, int bytes_issued, uint8_t *data, PacketPtr pkt)
Definition: DMASequencer.cc:57

Generated on Wed Dec 21 2022 10:22:38 for gem5 by doxygen 1.9.1