gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
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
51namespace gem5
52{
53
54namespace ruby
55{
56
65
68 m_max_outstanding_requests(p.max_outstanding_requests)
69{
70}
71
72void
74{
76 m_data_block_mask = mask(m_ruby_system->getBlockSizeBits());
77}
78
79RequestStatus
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 %#llx, len %d\n", line_addr, len);
112
113 int blk_size = m_ruby_system->getBlockSizeBytes();
114
115 std::shared_ptr<SequencerMsg> msg =
116 std::make_shared<SequencerMsg>(clockEdge(), blk_size, m_ruby_system);
117 msg->getPhysicalAddress() = paddr;
118 msg->getLineAddress() = line_addr;
119
120 if (pkt->req->isAtomic()) {
121 msg->setType(SequencerRequestType_ATOMIC);
122
123 // While regular LD/ST can support DMAs spanning multiple cache lines,
124 // atomic requests are only supported within a single cache line. The
125 // atomic request will end upon atomicCallback and not call issueNext.
126 int block_size = m_ruby_system->getBlockSizeBytes();
127 int atomic_offset = pkt->getAddr() - line_addr;
128 std::vector<bool> access_mask(block_size, false);
129 assert(atomic_offset + pkt->getSize() <= block_size);
130
131 for (int idx = 0; idx < pkt->getSize(); ++idx) {
132 access_mask[atomic_offset + idx] = true;
133 }
134
137 atomic_op(atomic_offset, pkt->getAtomicOp());
138
139 atomic_ops.emplace_back(atomic_op);
140 msg->getwriteMask().setAtomicOps(atomic_ops);
141 } else if (write) {
142 msg->setType(SequencerRequestType_ST);
143 } else {
144 assert(pkt->isRead());
145 msg->setType(SequencerRequestType_LD);
146 }
147
148 int offset = paddr & m_data_block_mask;
149
150 msg->getLen() = (offset + len) <= m_ruby_system->getBlockSizeBytes() ?
151 len : m_ruby_system->getBlockSizeBytes() - offset;
152
153 if (write && (data != NULL)) {
154 if (active_request.data != NULL) {
155 msg->getDataBlk().setData(data, offset, msg->getLen());
156 }
157 }
158
160
161 assert(m_mandatory_q_ptr != NULL);
162 m_mandatory_q_ptr->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)),
163 m_ruby_system->getRandomization(), m_ruby_system->getWarmupEnabled());
164 active_request.bytes_issued += msg->getLen();
165
166 return RequestStatus_Issued;
167}
168
169void
171{
172 RequestTable::iterator i = m_RequestTable.find(address);
173 assert(i != m_RequestTable.end());
174
175 DMARequest &active_request = i->second;
176
178 active_request.bytes_completed = active_request.bytes_issued;
179 if (active_request.len == active_request.bytes_completed) {
180 DPRINTF(RubyDma, "DMA request completed: addr %p, size %d\n",
181 address, active_request.len);
183 PacketPtr pkt = active_request.pkt;
184 m_RequestTable.erase(i);
186 return;
187 }
188
189 int blk_size = m_ruby_system->getBlockSizeBytes();
190
191 std::shared_ptr<SequencerMsg> msg =
192 std::make_shared<SequencerMsg>(clockEdge(), blk_size, m_ruby_system);
193 msg->getPhysicalAddress() = active_request.start_paddr +
194 active_request.bytes_completed;
195
196 assert((msg->getPhysicalAddress() & m_data_block_mask) == 0);
197 Addr new_line_addr = makeLineAddress(msg->getPhysicalAddress());
198 msg->getLineAddress() = new_line_addr;
199
200 // Add mapping from block address to original line address
201 // Only add if the new line address is different from the original
202 if (new_line_addr != address) {
203 m_blockToLineMap[new_line_addr] = address;
204 }
205
206 msg->getType() = (active_request.write ? SequencerRequestType_ST :
207 SequencerRequestType_LD);
208
209 msg->getLen() =
210 (active_request.len -
211 active_request.bytes_completed < m_ruby_system->getBlockSizeBytes() ?
212 active_request.len - active_request.bytes_completed :
213 m_ruby_system->getBlockSizeBytes());
214
215 if (active_request.write) {
216 msg->getDataBlk().
217 setData(&active_request.data[active_request.bytes_completed],
218 0, msg->getLen());
219 }
220
221 assert(m_mandatory_q_ptr != NULL);
222 m_mandatory_q_ptr->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)),
223 m_ruby_system->getRandomization(), m_ruby_system->getWarmupEnabled());
224 active_request.bytes_issued += msg->getLen();
225 DPRINTF(RubyDma,
226 "DMA request bytes issued %d, bytes completed %d, total len %d, "
227 "addr %#llx\n",
228 active_request.bytes_issued, active_request.bytes_completed,
229 active_request.len, msg->getPhysicalAddress());
230}
231
232void
233DMASequencer::dataCallback(const DataBlock & dblk, const Addr& address)
234{
235 DPRINTF(RubyDma, "DMA data callback: addr %#x\n", address);
236
237 // Find the original request by looking in the block to line map
238 Addr lookup_addr = address;
239 auto map_it = m_blockToLineMap.find(address);
240 // Note that if the address is the original address, we will not
241 // find it in the map
242 if (map_it != m_blockToLineMap.end()) {
243 lookup_addr = map_it->second;
244 m_blockToLineMap.erase(address);
245 }
246
247 RequestTable::iterator i = m_RequestTable.find(lookup_addr);
248 assert(i != m_RequestTable.end());
249
250 DMARequest &active_request = i->second;
251 int len = active_request.bytes_issued - active_request.bytes_completed;
252 int offset = 0;
253 if (active_request.bytes_completed == 0)
254 offset = active_request.start_paddr & m_data_block_mask;
255 assert(!active_request.write);
256 if (active_request.data != NULL) {
257 memcpy(&active_request.data[active_request.bytes_completed],
258 dblk.getData(offset, len), len);
259 }
260 issueNext(lookup_addr);
261}
262
263void
265{
266 // Find the original request by looking in the block to line map
267 Addr lookup_addr = address;
268 auto map_it = m_blockToLineMap.find(address);
269 if (map_it != m_blockToLineMap.end()) {
270 lookup_addr = map_it->second;
271 m_blockToLineMap.erase(address);
272 }
273
274 assert(m_RequestTable.find(lookup_addr) != m_RequestTable.end());
275 issueNext(lookup_addr);
276}
277
278void
279DMASequencer::atomicCallback(const DataBlock& dblk, const Addr& address)
280{
281 // Find the original request by looking in the block to line map
282 Addr lookup_addr = address;
283 auto map_it = m_blockToLineMap.find(address);
284 if (map_it != m_blockToLineMap.end()) {
285 lookup_addr = map_it->second;
286 m_blockToLineMap.erase(address);
287 }
288
289 RequestTable::iterator i = m_RequestTable.find(lookup_addr);
290 assert(i != m_RequestTable.end());
291
292 DMARequest &active_request = i->second;
293 PacketPtr pkt = active_request.pkt;
294
295 int offset = active_request.start_paddr & m_data_block_mask;
296 memcpy(pkt->getPtr<uint8_t>(), dblk.getData(offset, pkt->getSize()),
297 pkt->getSize());
298
300
302 m_RequestTable.erase(i);
303}
304
305void
306DMASequencer::recordRequestType(DMASequencerRequestType requestType)
307{
308 DPRINTF(RubyStats, "Recorded statistic: %s\n",
309 DMASequencerRequestType_to_string(requestType));
310}
311
312} // namespace ruby
313} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
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
bool isRead() const
Definition packet.hh:593
Addr getAddr() const
Definition packet.hh:807
T * getPtr()
get a pointer to the data ptr.
Definition packet.hh:1225
bool isWrite() const
Definition packet.hh:594
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
AtomicOpFunctor * getAtomicOp() const
Accessor function to atomic op.
Definition packet.hh:845
bool isMaskedWrite() const
Definition packet.hh:1450
void dataCallback(const DataBlock &dblk, const Addr &addr)
DMASequencerParams Params
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
void issueNext(const Addr &addr)
DMASequencer(const Params &)
std::unordered_map< Addr, Addr > m_blockToLineMap
RequestStatus makeRequest(PacketPtr pkt) override
void ackCallback(const Addr &addr)
void atomicCallback(const DataBlock &dblk, const Addr &addr)
void recordRequestType(DMASequencerRequestType requestType)
const uint8_t * getData(int offset, int len) const
Definition DataBlock.cc:191
void ruby_hit_callback(PacketPtr pkt)
Definition RubyPort.cc:462
Addr makeLineAddress(Addr addr) const
Definition RubyPort.cc:759
RubySystem * m_ruby_system
Definition RubyPort.hh:207
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition RubyPort.cc:92
RubyPort(const Params &p)
Definition RubyPort.cc:61
MessageBuffer * m_mandatory_q_ptr
Definition RubyPort.hh:210
STL pair class.
Definition stl.hh:58
STL vector class.
Definition stl.hh:37
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 18, 16 > len
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 0 > p
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
Packet * PacketPtr
DMARequest(uint64_t start_paddr, int len, bool write, int bytes_completed, int bytes_issued, uint8_t *data, PacketPtr pkt)

Generated on Mon May 26 2025 09:19:12 for gem5 by doxygen 1.13.2