RubyPort.cc (7035:b78b3a9e205f) RubyPort.cc (7039:bc0b6ea676b5)
1
2/*
3 * Copyright (c) 2009 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;

--- 12 unchanged lines hidden (view full) ---

22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
1/*
2 * Copyright (c) 2009 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
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;

--- 12 unchanged lines hidden (view full) ---

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.
27 */
28
29#include "cpu/rubytest/RubyTester.hh"
30#include "mem/physical.hh"
30#include "mem/physical.hh"
31#include "mem/ruby/system/RubyPort.hh"
32#include "mem/ruby/slicc_interface/AbstractController.hh"
31#include "mem/ruby/slicc_interface/AbstractController.hh"
33#include "cpu/rubytest/RubyTester.hh"
32#include "mem/ruby/system/RubyPort.hh"
34
35RubyPort::RubyPort(const Params *p)
36 : MemObject(p)
37{
38 m_version = p->version;
39 assert(m_version != -1);
40
41 physmem = p->physmem;
33
34RubyPort::RubyPort(const Params *p)
35 : MemObject(p)
36{
37 m_version = p->version;
38 assert(m_version != -1);
39
40 physmem = p->physmem;
42
41
43 m_controller = NULL;
44 m_mandatory_q_ptr = NULL;
45
46 m_request_cnt = 0;
47 pio_port = NULL;
48 physMemPort = NULL;
49}
50
42 m_controller = NULL;
43 m_mandatory_q_ptr = NULL;
44
45 m_request_cnt = 0;
46 pio_port = NULL;
47 physMemPort = NULL;
48}
49
51void RubyPort::init()
50void
51RubyPort::init()
52{
53 assert(m_controller != NULL);
54 m_mandatory_q_ptr = m_controller->getMandatoryQueue();
55}
56
57Port *
58RubyPort::getPort(const std::string &if_name, int idx)
59{
60 if (if_name == "port") {
61 return new M5Port(csprintf("%s-port%d", name(), idx), this);
52{
53 assert(m_controller != NULL);
54 m_mandatory_q_ptr = m_controller->getMandatoryQueue();
55}
56
57Port *
58RubyPort::getPort(const std::string &if_name, int idx)
59{
60 if (if_name == "port") {
61 return new M5Port(csprintf("%s-port%d", name(), idx), this);
62 } else if (if_name == "pio_port") {
63 //
62 }
63
64 if (if_name == "pio_port") {
64 // ensure there is only one pio port
65 // ensure there is only one pio port
65 //
66 assert(pio_port == NULL);
67
66 assert(pio_port == NULL);
67
68 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx),
69 this);
68 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);
70
71 return pio_port;
69
70 return pio_port;
72 } else if (if_name == "physMemPort") {
73 //
71 }
72
73 if (if_name == "physMemPort") {
74 // RubyPort should only have one port to physical memory
74 // RubyPort should only have one port to physical memory
75 //
76 assert (physMemPort == NULL);
77
75 assert (physMemPort == NULL);
76
78 physMemPort = new M5Port(csprintf("%s-physMemPort", name()),
79 this);
80
77 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this);
78
81 return physMemPort;
79 return physMemPort;
82 } else if (if_name == "functional") {
83 //
84 // Calls for the functional port only want to access functional memory.
85 // Therefore, directly pass these calls ports to physmem.
86 //
80 }
81
82 if (if_name == "functional") {
83 // Calls for the functional port only want to access
84 // functional memory. Therefore, directly pass these calls
85 // ports to physmem.
87 assert(physmem != NULL);
88 return physmem->getPort(if_name, idx);
89 }
86 assert(physmem != NULL);
87 return physmem->getPort(if_name, idx);
88 }
89
90 return NULL;
91}
92
90 return NULL;
91}
92
93RubyPort::PioPort::PioPort(const std::string &_name,
93RubyPort::PioPort::PioPort(const std::string &_name,
94 RubyPort *_port)
95 : SimpleTimingPort(_name, _port)
96{
97 DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name);
98 ruby_port = _port;
99}
100
94 RubyPort *_port)
95 : SimpleTimingPort(_name, _port)
96{
97 DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name);
98 ruby_port = _port;
99}
100
101RubyPort::M5Port::M5Port(const std::string &_name,
101RubyPort::M5Port::M5Port(const std::string &_name,
102 RubyPort *_port)
103 : SimpleTimingPort(_name, _port)
104{
105 DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name);
106 ruby_port = _port;
107}
108
109Tick
110RubyPort::PioPort::recvAtomic(PacketPtr pkt)
111{
112 panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
113 return 0;
114}
115
102 RubyPort *_port)
103 : SimpleTimingPort(_name, _port)
104{
105 DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name);
106 ruby_port = _port;
107}
108
109Tick
110RubyPort::PioPort::recvAtomic(PacketPtr pkt)
111{
112 panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
113 return 0;
114}
115
116
117Tick
118RubyPort::M5Port::recvAtomic(PacketPtr pkt)
119{
120 panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
121 return 0;
122}
123
124
125bool
126RubyPort::PioPort::recvTiming(PacketPtr pkt)
127{
116Tick
117RubyPort::M5Port::recvAtomic(PacketPtr pkt)
118{
119 panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
120 return 0;
121}
122
123
124bool
125RubyPort::PioPort::recvTiming(PacketPtr pkt)
126{
128 //
129 // In FS mode, ruby memory will receive pio responses from devices and
130 // it must forward these responses back to the particular CPU.
131 //
132 DPRINTF(MemoryAccess,
133 "Pio response for address %#x\n",
134 pkt->getAddr());
127 // In FS mode, ruby memory will receive pio responses from devices
128 // and it must forward these responses back to the particular CPU.
129 DPRINTF(MemoryAccess, "Pio response for address %#x\n", pkt->getAddr());
135
136 assert(pkt->isResponse());
137
130
131 assert(pkt->isResponse());
132
138 //
139 // First we must retrieve the request port from the sender State
133 // First we must retrieve the request port from the sender State
140 //
141 RubyPort::SenderState *senderState =
134 RubyPort::SenderState *senderState =
142 safe_cast<RubyPort::SenderState *>(pkt->senderState);
143 M5Port *port = senderState->port;
144 assert(port != NULL);
135 safe_cast<RubyPort::SenderState *>(pkt->senderState);
136 M5Port *port = senderState->port;
137 assert(port != NULL);
145
138
146 // pop the sender state from the packet
147 pkt->senderState = senderState->saved;
148 delete senderState;
139 // pop the sender state from the packet
140 pkt->senderState = senderState->saved;
141 delete senderState;
149
142
150 port->sendTiming(pkt);
143 port->sendTiming(pkt);
151
144
152 return true;
153}
154
155bool
156RubyPort::M5Port::recvTiming(PacketPtr pkt)
157{
145 return true;
146}
147
148bool
149RubyPort::M5Port::recvTiming(PacketPtr pkt)
150{
158 DPRINTF(MemoryAccess,
159 "Timing access caught for address %#x\n",
160 pkt->getAddr());
151 DPRINTF(MemoryAccess,
152 "Timing access caught for address %#x\n", pkt->getAddr());
161
162 //dsm: based on SimpleTimingPort::recvTiming(pkt);
163
153
154 //dsm: based on SimpleTimingPort::recvTiming(pkt);
155
164 //
165 // The received packets should only be M5 requests, which should never
166 // get nacked. There used to be code to hanldle nacks here, but
167 // I'm pretty sure it didn't work correctly with the drain code,
156 // The received packets should only be M5 requests, which should never
157 // get nacked. There used to be code to hanldle nacks here, but
158 // I'm pretty sure it didn't work correctly with the drain code,
168 // so that would need to be fixed if we ever added it back.
159 // so that would need to be fixed if we ever added it back.
169 //
170 assert(pkt->isRequest());
171
172 if (pkt->memInhibitAsserted()) {
173 warn("memInhibitAsserted???");
174 // snooper will supply based on copy of packet
175 // still target's responsibility to delete packet
176 delete pkt;
177 return true;
178 }
179
160 assert(pkt->isRequest());
161
162 if (pkt->memInhibitAsserted()) {
163 warn("memInhibitAsserted???");
164 // snooper will supply based on copy of packet
165 // still target's responsibility to delete packet
166 delete pkt;
167 return true;
168 }
169
180 //
181 // Save the port in the sender state object to be used later to
182 // route the response
170 // Save the port in the sender state object to be used later to
171 // route the response
183 //
184 pkt->senderState = new SenderState(this, pkt->senderState);
185
172 pkt->senderState = new SenderState(this, pkt->senderState);
173
186 //
187 // Check for pio requests and directly send them to the dedicated
188 // pio port.
174 // Check for pio requests and directly send them to the dedicated
175 // pio port.
189 //
190 if (!isPhysMemAddress(pkt->getAddr())) {
191 assert(ruby_port->pio_port != NULL);
176 if (!isPhysMemAddress(pkt->getAddr())) {
177 assert(ruby_port->pio_port != NULL);
192 DPRINTF(MemoryAccess,
178 DPRINTF(MemoryAccess,
193 "Request for address 0x%#x is assumed to be a pio request\n",
194 pkt->getAddr());
195
196 return ruby_port->pio_port->sendTiming(pkt);
197 }
198
179 "Request for address 0x%#x is assumed to be a pio request\n",
180 pkt->getAddr());
181
182 return ruby_port->pio_port->sendTiming(pkt);
183 }
184
199 //
200 // For DMA and CPU requests, translate them to ruby requests before
201 // sending them to our assigned ruby port.
185 // For DMA and CPU requests, translate them to ruby requests before
186 // sending them to our assigned ruby port.
202 //
203 RubyRequestType type = RubyRequestType_NULL;
204
187 RubyRequestType type = RubyRequestType_NULL;
188
205 //
206 // If valid, copy the pc to the ruby request
189 // If valid, copy the pc to the ruby request
207 //
208 Addr pc = 0;
209 if (pkt->req->hasPC()) {
210 pc = pkt->req->getPC();
211 }
212
213 if (pkt->isLLSC()) {
214 if (pkt->isWrite()) {
215 DPRINTF(MemoryAccess, "Issuing SC\n");
216 type = RubyRequestType_Locked_Write;
217 } else {
218 DPRINTF(MemoryAccess, "Issuing LL\n");
219 assert(pkt->isRead());
220 type = RubyRequestType_Locked_Read;
221 }
222 } else {
223 if (pkt->isRead()) {
224 if (pkt->req->isInstFetch()) {
225 type = RubyRequestType_IFETCH;
226 } else {
190 Addr pc = 0;
191 if (pkt->req->hasPC()) {
192 pc = pkt->req->getPC();
193 }
194
195 if (pkt->isLLSC()) {
196 if (pkt->isWrite()) {
197 DPRINTF(MemoryAccess, "Issuing SC\n");
198 type = RubyRequestType_Locked_Write;
199 } else {
200 DPRINTF(MemoryAccess, "Issuing LL\n");
201 assert(pkt->isRead());
202 type = RubyRequestType_Locked_Read;
203 }
204 } else {
205 if (pkt->isRead()) {
206 if (pkt->req->isInstFetch()) {
207 type = RubyRequestType_IFETCH;
208 } else {
227 type = RubyRequestType_LD;
209 type = RubyRequestType_LD;
228 }
229 } else if (pkt->isWrite()) {
230 type = RubyRequestType_ST;
231 } else if (pkt->isReadWrite()) {
210 }
211 } else if (pkt->isWrite()) {
212 type = RubyRequestType_ST;
213 } else if (pkt->isReadWrite()) {
232 //
233 // Fix me. This conditional will never be executed because
234 // isReadWrite() is just an OR of isRead() and isWrite().
235 // Furthermore, just because the packet is a read/write request does
236 // not necessary mean it is a read-modify-write atomic operation.
237 //
214 // Fix me. This conditional will never be executed
215 // because isReadWrite() is just an OR of isRead() and
216 // isWrite(). Furthermore, just because the packet is a
217 // read/write request does not necessary mean it is a
218 // read-modify-write atomic operation.
238 type = RubyRequestType_RMW_Write;
239 } else {
240 panic("Unsupported ruby packet type\n");
241 }
242 }
243
219 type = RubyRequestType_RMW_Write;
220 } else {
221 panic("Unsupported ruby packet type\n");
222 }
223 }
224
244 RubyRequest ruby_request(pkt->getAddr(),
245 pkt->getPtr<uint8_t>(),
246 pkt->getSize(),
247 pc,
248 type,
249 RubyAccessMode_Supervisor,
250 pkt);
225 RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
226 pkt->getSize(), pc, type,
227 RubyAccessMode_Supervisor, pkt);
251
252 // Submit the ruby request
253 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
254
228
229 // Submit the ruby request
230 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
231
255 //
256 // If the request successfully issued or the SC request completed because
257 // exclusive permission was lost, then we should return true.
258 // Otherwise, we need to delete the senderStatus we just created and return
259 // false.
232 // If the request successfully issued or the SC request completed because
233 // exclusive permission was lost, then we should return true.
234 // Otherwise, we need to delete the senderStatus we just created and return
235 // false.
260 //
261 if ((requestStatus == RequestStatus_Issued) ||
262 (requestStatus == RequestStatus_LlscFailed)) {
263
236 if ((requestStatus == RequestStatus_Issued) ||
237 (requestStatus == RequestStatus_LlscFailed)) {
238
264 //
265 // The communicate to M5 whether the SC command succeeded by seting the
266 // packet's extra data.
239 // The communicate to M5 whether the SC command succeeded by seting the
240 // packet's extra data.
267 //
268 if (pkt->isLLSC() && pkt->isWrite()) {
269 if (requestStatus == RequestStatus_LlscFailed) {
270 DPRINTF(MemoryAccess, "SC failed and request completed\n");
271 pkt->req->setExtraData(0);
272 } else {
273 pkt->req->setExtraData(1);
274 }
275 }
276 return true;
277 }
278
241 if (pkt->isLLSC() && pkt->isWrite()) {
242 if (requestStatus == RequestStatus_LlscFailed) {
243 DPRINTF(MemoryAccess, "SC failed and request completed\n");
244 pkt->req->setExtraData(0);
245 } else {
246 pkt->req->setExtraData(1);
247 }
248 }
249 return true;
250 }
251
279 DPRINTF(MemoryAccess,
252 DPRINTF(MemoryAccess,
280 "Request for address #x did not issue because %s\n",
253 "Request for address #x did not issue because %s\n",
281 pkt->getAddr(),
282 RequestStatus_to_string(requestStatus));
283
254 pkt->getAddr(), RequestStatus_to_string(requestStatus));
255
284 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
285 pkt->senderState = senderState->saved;
286 delete senderState;
287 return false;
288}
289
290void
291RubyPort::ruby_hit_callback(PacketPtr pkt)
292{
256 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
257 pkt->senderState = senderState->saved;
258 delete senderState;
259 return false;
260}
261
262void
263RubyPort::ruby_hit_callback(PacketPtr pkt)
264{
293 //
294 // Retrieve the request port from the sender State
265 // Retrieve the request port from the sender State
295 //
296 RubyPort::SenderState *senderState =
266 RubyPort::SenderState *senderState =
297 safe_cast<RubyPort::SenderState *>(pkt->senderState);
298 M5Port *port = senderState->port;
299 assert(port != NULL);
267 safe_cast<RubyPort::SenderState *>(pkt->senderState);
268 M5Port *port = senderState->port;
269 assert(port != NULL);
300
270
301 // pop the sender state from the packet
302 pkt->senderState = senderState->saved;
303 delete senderState;
304
305 port->hitCallback(pkt);
306}
307
308void
309RubyPort::M5Port::hitCallback(PacketPtr pkt)
310{
271 // pop the sender state from the packet
272 pkt->senderState = senderState->saved;
273 delete senderState;
274
275 port->hitCallback(pkt);
276}
277
278void
279RubyPort::M5Port::hitCallback(PacketPtr pkt)
280{
311
312 bool needsResponse = pkt->needsResponse();
313
281 bool needsResponse = pkt->needsResponse();
282
314 DPRINTF(MemoryAccess, "Hit callback needs response %d\n",
315 needsResponse);
283 DPRINTF(MemoryAccess, "Hit callback needs response %d\n", needsResponse);
316
317 ruby_port->physMemPort->sendAtomic(pkt);
318
319 // turn packet around to go back to requester if response expected
320 if (needsResponse) {
321 // sendAtomic() should already have turned packet into
322 // atomic response
323 assert(pkt->isResponse());

--- 20 unchanged lines hidden (view full) ---

344}
345
346bool
347RubyPort::M5Port::isPhysMemAddress(Addr addr)
348{
349 AddrRangeList physMemAddrList;
350 bool snoop = false;
351 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
284
285 ruby_port->physMemPort->sendAtomic(pkt);
286
287 // turn packet around to go back to requester if response expected
288 if (needsResponse) {
289 // sendAtomic() should already have turned packet into
290 // atomic response
291 assert(pkt->isResponse());

--- 20 unchanged lines hidden (view full) ---

312}
313
314bool
315RubyPort::M5Port::isPhysMemAddress(Addr addr)
316{
317 AddrRangeList physMemAddrList;
318 bool snoop = false;
319 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
352 for(AddrRangeIter iter = physMemAddrList.begin();
353 iter != physMemAddrList.end();
354 iter++) {
320 for (AddrRangeIter iter = physMemAddrList.begin();
321 iter != physMemAddrList.end();
322 iter++) {
355 if (addr >= iter->start && addr <= iter->end) {
356 DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n",
357 iter->start, iter->end);
358 return true;
359 }
360 }
361 return false;
362}
323 if (addr >= iter->start && addr <= iter->end) {
324 DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n",
325 iter->start, iter->end);
326 return true;
327 }
328 }
329 return false;
330}