2 * Copyright (c) 2001-2005 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.
28 * Authors: Daniel Sanchez
34 #include "arch/isa_traits.hh"
35 #include "base/output.hh"
36 #include "base/str.hh"
37 #include "base/types.hh"
38 #include "mem/ruby/common/Debug.hh"
39 #include "mem/ruby/libruby.hh"
40 #include "mem/ruby/system/RubyPort.hh"
41 #include "mem/ruby/system/Sequencer.hh"
42 #include "mem/ruby/system/System.hh"
43 #include "mem/rubymem.hh"
44 #include "sim/eventq.hh"
45 #include "sim/sim_exit.hh"
48 using namespace TheISA
;
50 map
<int64_t, PacketPtr
> RubyMemory::pending_requests
;
52 RubyMemory::RubyMemory(const Params
*p
)
55 ruby_clock
= p
->clock
;
56 ruby_phase
= p
->phase
;
58 ifstream
config(p
->config_file
.c_str());
60 vector
<RubyObjConf
> sys_conf
;
61 while (!config
.eof()) {
63 config
.getline(buffer
, sizeof(buffer
));
67 vector
<string
> tokens
;
68 tokenize(tokens
, line
, ' ');
69 assert(tokens
.size() >= 2);
71 for (size_t i
=2; i
<tokens
.size(); i
++) {
72 std::replace(tokens
[i
].begin(), tokens
[i
].end(), '%', ' ');
73 std::replace(tokens
[i
].begin(), tokens
[i
].end(), '#', '\n');
74 argv
.push_back(tokens
[i
]);
76 sys_conf
.push_back(RubyObjConf(tokens
[0], tokens
[1], argv
));
81 RubySystem::create(sys_conf
);
83 for (int i
= 0; i
< params()->num_cpus
; i
++) {
84 RubyPort
*p
= RubySystem::getPort(csprintf("Sequencer_%d", i
),
86 ruby_ports
.push_back(p
);
93 if (params()->debug
) {
94 g_debug_ptr
->setVerbosityString("high");
95 g_debug_ptr
->setDebugTime(1);
96 if (!params()->debug_file
.empty()) {
97 g_debug_ptr
->setDebugOutputFile(params()->debug_file
.c_str());
101 //You may want to set some other options...
102 //g_debug_ptr->setVerbosityString("med");
103 //g_debug_ptr->setFilterString("lsNqST");
104 //g_debug_ptr->setFilterString("lsNST");
105 //g_debug_ptr->setDebugTime(1);
106 //g_debug_ptr->setDebugOutputFile("ruby.debug");
109 g_system_ptr
->clearStats();
111 if (ports
.size() == 0) {
112 fatal("RubyMemory object %s is unconnected!", name());
115 for (PortIterator pi
= ports
.begin(); pi
!= ports
.end(); ++pi
) {
117 (*pi
)->sendStatusChange(Port::RangeChange
);
120 //Print stats at exit
121 RubyExitCallback
* rc
= new RubyExitCallback(this);
122 registerExitCallback(rc
);
124 //Sched RubyEvent, automatically reschedules to advance ruby cycles
125 rubyTickEvent
= new RubyEvent(this);
126 schedule(rubyTickEvent
, curTick
+ ruby_clock
+ ruby_phase
);
129 //called by rubyTickEvent
133 RubyEventQueue
*eq
= RubySystem::getEventQueue();
134 eq
->triggerEvents(eq
->getTime() + 1);
135 schedule(rubyTickEvent
, curTick
+ ruby_clock
);
138 RubyMemory::~RubyMemory()
143 RubyMemory::hitCallback(PacketPtr pkt
, Port
*port
)
145 DPRINTF(MemoryAccess
, "Hit callback\n");
147 bool needsResponse
= pkt
->needsResponse();
150 // turn packet around to go back to requester if response expected
152 // recvAtomic() should already have turned packet into
154 assert(pkt
->isResponse());
155 DPRINTF(MemoryAccess
, "Sending packet back over port\n");
156 port
->sendTiming(pkt
);
160 DPRINTF(MemoryAccess
, "Hit callback done!\n");
164 RubyMemory::getPort(const std::string
&if_name
, int idx
)
166 // Accept request for "functional" port for backwards compatibility
167 // with places where this function is called from C++. I'd prefer
168 // to move all these into Python someday.
169 if (if_name
== "functional") {
170 return new Port(csprintf("%s-functional", name()), this);
173 if (if_name
!= "port") {
174 panic("RubyMemory::getPort: unknown port %s requested", if_name
);
177 if (idx
>= (int)ports
.size()) {
181 if (ports
[idx
] != NULL
) {
182 panic("RubyMemory::getPort: port %d already assigned", idx
);
185 Port
*port
= new Port(csprintf("%s-port%d", name(), idx
), this);
191 RubyMemory::Port::Port(const std::string
&_name
, RubyMemory
*_memory
)
192 : PhysicalMemory::MemoryPort::MemoryPort(_name
, _memory
)
198 RubyMemory::Port::recvTiming(PacketPtr pkt
)
200 DPRINTF(MemoryAccess
, "Timing access caught\n");
202 //dsm: based on SimpleTimingPort::recvTiming(pkt);
204 // If the device is only a slave, it should only be sending
205 // responses, which should never get nacked. There used to be
206 // code to hanldle nacks here, but I'm pretty sure it didn't work
207 // correctly with the drain code, so that would need to be fixed
208 // if we ever added it back.
209 assert(pkt
->isRequest());
211 if (pkt
->memInhibitAsserted()) {
212 warn("memInhibitAsserted???");
213 // snooper will supply based on copy of packet
214 // still target's responsibility to delete packet
219 // Save the port in the sender state object
220 pkt
->senderState
= new SenderState(this, pkt
->senderState
);
222 RubyRequestType type
= RubyRequestType_NULL
;
225 if (pkt
->req
->isInstFetch()) {
226 type
= RubyRequestType_IFETCH
;
227 pc
= pkt
->req
->getPC();
229 type
= RubyRequestType_LD
;
231 } else if (pkt
->isWrite()) {
232 type
= RubyRequestType_ST
;
233 } else if (pkt
->isReadWrite()) {
234 // type = RubyRequestType_RMW;
237 RubyRequest
ruby_request(pkt
->getAddr(), pkt
->getPtr
<uint8_t>(),
238 pkt
->getSize(), pc
, type
,
239 RubyAccessMode_Supervisor
);
241 // Submit the ruby request
242 RubyPort
*ruby_port
= ruby_mem
->ruby_ports
[pkt
->req
->contextId()];
243 int64_t req_id
= ruby_port
->makeRequest(ruby_request
);
245 RubyMemory::SenderState
*senderState
=
246 safe_cast
<RubyMemory::SenderState
*>(pkt
->senderState
);
248 // pop the sender state from the packet
249 pkt
->senderState
= senderState
->saved
;
254 // Save the request for the callback
255 RubyMemory::pending_requests
[req_id
] = pkt
;
261 ruby_hit_callback(int64_t req_id
)
263 typedef map
<int64_t, PacketPtr
> map_t
;
264 map_t
&prm
= RubyMemory::pending_requests
;
266 map_t::iterator i
= prm
.find(req_id
);
268 panic("could not find pending request %d\n", req_id
);
270 PacketPtr pkt
= i
->second
;
273 RubyMemory::SenderState
*senderState
=
274 safe_cast
<RubyMemory::SenderState
*>(pkt
->senderState
);
275 RubyMemory::Port
*port
= senderState
->port
;
277 // pop the sender state from the packet
278 pkt
->senderState
= senderState
->saved
;
281 port
->ruby_mem
->hitCallback(pkt
, port
);
285 RubyMemory::Port::sendTiming(PacketPtr pkt
)
287 schedSendTiming(pkt
, curTick
+ 1); //minimum latency, must be > 0
290 void RubyMemory::printConfigStats()
292 std::ostream
*os
= simout
.create(params()->stats_file
);
293 RubySystem::printConfig(*os
);
295 RubySystem::printStats(*os
);
299 //Right now these functions seem to be called by RubySystem. If they do calls
300 // to RubySystem perform it intended actions, you'll get into an inf loop
301 //FIXME what's the purpose of these here?
302 void RubyMemory::printStats(std::ostream
& out
) const {
303 //g_system_ptr->printConfig(out);
306 void RubyMemory::clearStats() {
307 //g_system_ptr->clearStats();
310 void RubyMemory::printConfig(std::ostream
& out
) const {
311 //g_system_ptr->printConfig(out);
315 //Python-interface code
317 RubyMemoryParams::create()
319 return new RubyMemory(this);