2 * Copyright (c) 2006 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Definition of the Packet Class, a packet is a transaction occuring
35 * between a single level of the memory heirarchy (ie L1->L2).
40 #include "base/misc.hh"
41 #include "base/trace.hh"
42 #include "mem/packet.hh"
44 // The one downside to bitsets is that static initializers can get ugly.
45 #define SET1(a1) (1 << (a1))
46 #define SET2(a1, a2) (SET1(a1) | SET1(a2))
47 #define SET3(a1, a2, a3) (SET2(a1, a2) | SET1(a3))
48 #define SET4(a1, a2, a3, a4) (SET3(a1, a2, a3) | SET1(a4))
49 #define SET5(a1, a2, a3, a4, a5) (SET4(a1, a2, a3, a4) | SET1(a5))
50 #define SET6(a1, a2, a3, a4, a5, a6) (SET5(a1, a2, a3, a4, a5) | SET1(a6))
52 const MemCmd::CommandInfo
53 MemCmd::commandInfo
[] =
56 { 0, InvalidCmd
, "InvalidCmd" },
58 { SET3(IsRead
, IsRequest
, NeedsResponse
), ReadResp
, "ReadReq" },
60 { SET4(IsWrite
, IsRequest
, NeedsResponse
, HasData
),
61 WriteResp
, "WriteReq" },
63 { SET3(IsWrite
, IsRequest
, HasData
), InvalidCmd
, "WriteReqNoAck" },
65 { SET3(IsRead
, IsResponse
, HasData
), InvalidCmd
, "ReadResp" },
67 { SET2(IsWrite
, IsResponse
), InvalidCmd
, "WriteResp" },
69 { SET3(IsWrite
, IsRequest
, HasData
), InvalidCmd
, "Writeback" },
71 { SET4(IsRead
, IsRequest
, IsSWPrefetch
, NeedsResponse
),
72 SoftPFResp
, "SoftPFReq" },
74 { SET4(IsRead
, IsRequest
, IsHWPrefetch
, NeedsResponse
),
75 HardPFResp
, "HardPFReq" },
77 { SET4(IsRead
, IsResponse
, IsSWPrefetch
, HasData
),
78 InvalidCmd
, "SoftPFResp" },
80 { SET4(IsRead
, IsResponse
, IsHWPrefetch
, HasData
),
81 InvalidCmd
, "HardPFResp" },
83 { SET2(IsInvalidate
, IsRequest
), InvalidCmd
, "InvalidateReq" },
84 /* WriteInvalidateReq */
85 { SET5(IsWrite
, IsInvalidate
, IsRequest
, HasData
, NeedsResponse
),
86 WriteInvalidateResp
, "WriteInvalidateReq" },
87 /* WriteInvalidateResp */
88 { SET5(IsWrite
, IsInvalidate
, IsRequest
, NeedsResponse
, IsResponse
),
89 InvalidCmd
, "WriteInvalidateResp" },
91 { SET3(IsInvalidate
, IsRequest
, IsUpgrade
), InvalidCmd
, "UpgradeReq" },
93 { SET4(IsRead
, IsInvalidate
, IsRequest
, NeedsResponse
),
94 ReadExResp
, "ReadExReq" },
96 { SET4(IsRead
, IsInvalidate
, IsResponse
, HasData
),
97 InvalidCmd
, "ReadExResp" },
98 /* SwapReq -- for Swap ldstub type operations */
99 { SET4(IsReadWrite
, IsRequest
, HasData
, NeedsResponse
),
100 SwapResp
, "SwapReq" },
101 /* SwapResp -- for Swap ldstub type operations */
102 { SET3(IsReadWrite
, IsResponse
, HasData
),
103 InvalidCmd
, "SwapResp" }
107 /** delete the data pointed to in the data pointer. Ok to call to matter how
108 * data was allocted. */
112 assert(staticData
|| dynamicData
);
122 /** If there isn't data in the packet, allocate some. */
131 data
= new uint8_t[getSize()];
134 /** Do the packet modify the same addresses. */
136 Packet::intersect(PacketPtr p
)
139 Addr e1
= getAddr() + getSize() - 1;
140 Addr s2
= p
->getAddr();
141 Addr e2
= p
->getAddr() + p
->getSize() - 1;
143 return !(s1
> e2
|| e1
< s2
);
147 fixDelayedResponsePacket(PacketPtr func
, PacketPtr timing
)
151 if (timing
->isRead() || timing
->isWrite()) {
152 // Ugly hack to deal with the fact that we queue the requests
153 // and don't convert them to responses until we issue them on
154 // the bus. I tried to avoid this by converting packets to
155 // responses right away, but this breaks during snoops where a
156 // responder may do the conversion before other caches have
157 // done the snoop. Would work if we copied the packet instead
158 // of just hanging on to a pointer.
159 MemCmd oldCmd
= timing
->cmd
;
160 timing
->cmd
= timing
->cmd
.responseCommand();
161 result
= fixPacket(func
, timing
);
162 timing
->cmd
= oldCmd
;
165 //Don't toggle if it isn't a read/write response
166 result
= fixPacket(func
, timing
);
173 fixPacket(PacketPtr func
, PacketPtr timing
)
175 Addr funcStart
= func
->getAddr();
176 Addr funcEnd
= func
->getAddr() + func
->getSize() - 1;
177 Addr timingStart
= timing
->getAddr();
178 Addr timingEnd
= timing
->getAddr() + timing
->getSize() - 1;
180 assert(!(funcStart
> timingEnd
|| timingStart
> funcEnd
));
182 // this packet can't solve our problem, continue on
183 if (!timing
->hasData())
186 if (func
->isRead()) {
187 if (funcStart
>= timingStart
&& funcEnd
<= timingEnd
) {
189 std::memcpy(func
->getPtr
<uint8_t>(), timing
->getPtr
<uint8_t>() +
190 funcStart
- timingStart
, func
->getSize());
191 func
->result
= Packet::Success
;
192 func
->flags
|= SATISFIED
;
195 // In this case the timing packet only partially satisfies the
196 // requset, so we would need more information to make this work.
197 // Like bytes valid in the packet or something, so the request could
198 // continue and get this bit of possibly newer data along with the
199 // older data not written to yet.
200 panic("Timing packet only partially satisfies the functional"
201 "request. Now what?");
203 } else if (func
->isWrite()) {
204 if (funcStart
>= timingStart
) {
205 std::memcpy(timing
->getPtr
<uint8_t>() + (funcStart
- timingStart
),
206 func
->getPtr
<uint8_t>(),
207 (std::min(funcEnd
, timingEnd
) - funcStart
) + 1);
208 } else { // timingStart > funcStart
209 std::memcpy(timing
->getPtr
<uint8_t>(),
210 func
->getPtr
<uint8_t>() + (timingStart
- funcStart
),
211 (std::min(funcEnd
, timingEnd
) - timingStart
) + 1);
213 // we always want to keep going with a write
216 panic("Don't know how to handle command type %#x\n",
223 operator<<(std::ostream
&o
, const Packet
&p
)
227 o
.setf(std::ios_base::hex
, std::ios_base::showbase
);
229 o
.unsetf(std::ios_base::hex
| std::ios_base::showbase
);
231 o
.setf(std::ios_base::hex
, std::ios_base::showbase
);
232 o
<< p
.getAddr() + p
.getSize() - 1 << "] ";
233 o
.unsetf(std::ios_base::hex
| std::ios_base::showbase
);
235 if (p
.result
== Packet::Success
)
237 if (p
.result
== Packet::BadAddress
)
239 if (p
.result
== Packet::Nacked
)
241 if (p
.result
== Packet::Unknown
)
250 if (p
.isInvalidate())