ruby: Fix RubyMemory to work with the newer ruby.
[gem5.git] / src / mem / rubymem.cc
1 /*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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;
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.
15 *
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.
27 *
28 * Authors: Daniel Sanchez
29 */
30
31 #include <iostream>
32 #include <fstream>
33
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"
46
47 using namespace std;
48 using namespace TheISA;
49
50 map<int64_t, PacketPtr> RubyMemory::pending_requests;
51
52 RubyMemory::RubyMemory(const Params *p)
53 : PhysicalMemory(p)
54 {
55 ruby_clock = p->clock;
56 ruby_phase = p->phase;
57
58 ifstream config(p->config_file.c_str());
59
60 vector<RubyObjConf> sys_conf;
61 while (!config.eof()) {
62 char buffer[4096];
63 config.getline(buffer, sizeof(buffer));
64 string line = buffer;
65 if (line.empty())
66 continue;
67 vector<string> tokens;
68 tokenize(tokens, line, ' ');
69 assert(tokens.size() >= 2);
70 vector<string> argv;
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]);
75 }
76 sys_conf.push_back(RubyObjConf(tokens[0], tokens[1], argv));
77 tokens.clear();
78 argv.clear();
79 }
80
81 RubySystem::create(sys_conf);
82
83 for (int i = 0; i < params()->num_cpus; i++) {
84 RubyPort *p = RubySystem::getPort(csprintf("Sequencer_%d", i),
85 ruby_hit_callback);
86 ruby_ports.push_back(p);
87 }
88 }
89
90 void
91 RubyMemory::init()
92 {
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());
98 }
99 }
100
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");
107
108
109 g_system_ptr->clearStats();
110
111 if (ports.size() == 0) {
112 fatal("RubyMemory object %s is unconnected!", name());
113 }
114
115 for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
116 if (*pi)
117 (*pi)->sendStatusChange(Port::RangeChange);
118 }
119
120 //Print stats at exit
121 RubyExitCallback* rc = new RubyExitCallback(this);
122 registerExitCallback(rc);
123
124 //Sched RubyEvent, automatically reschedules to advance ruby cycles
125 rubyTickEvent = new RubyEvent(this);
126 schedule(rubyTickEvent, curTick + ruby_clock + ruby_phase);
127 }
128
129 //called by rubyTickEvent
130 void
131 RubyMemory::tick()
132 {
133 RubyEventQueue *eq = RubySystem::getEventQueue();
134 eq->triggerEvents(eq->getTime() + 1);
135 schedule(rubyTickEvent, curTick + ruby_clock);
136 }
137
138 RubyMemory::~RubyMemory()
139 {
140 }
141
142 void
143 RubyMemory::hitCallback(PacketPtr pkt, Port *port)
144 {
145 DPRINTF(MemoryAccess, "Hit callback\n");
146
147 bool needsResponse = pkt->needsResponse();
148 doAtomicAccess(pkt);
149
150 // turn packet around to go back to requester if response expected
151 if (needsResponse) {
152 // recvAtomic() should already have turned packet into
153 // atomic response
154 assert(pkt->isResponse());
155 DPRINTF(MemoryAccess, "Sending packet back over port\n");
156 port->sendTiming(pkt);
157 } else {
158 delete pkt;
159 }
160 DPRINTF(MemoryAccess, "Hit callback done!\n");
161 }
162
163 Port *
164 RubyMemory::getPort(const std::string &if_name, int idx)
165 {
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);
171 }
172
173 if (if_name != "port") {
174 panic("RubyMemory::getPort: unknown port %s requested", if_name);
175 }
176
177 if (idx >= (int)ports.size()) {
178 ports.resize(idx+1);
179 }
180
181 if (ports[idx] != NULL) {
182 panic("RubyMemory::getPort: port %d already assigned", idx);
183 }
184
185 Port *port = new Port(csprintf("%s-port%d", name(), idx), this);
186
187 ports[idx] = port;
188 return port;
189 }
190
191 RubyMemory::Port::Port(const std::string &_name, RubyMemory *_memory)
192 : PhysicalMemory::MemoryPort::MemoryPort(_name, _memory)
193 {
194 ruby_mem = _memory;
195 }
196
197 bool
198 RubyMemory::Port::recvTiming(PacketPtr pkt)
199 {
200 DPRINTF(MemoryAccess, "Timing access caught\n");
201
202 //dsm: based on SimpleTimingPort::recvTiming(pkt);
203
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());
210
211 if (pkt->memInhibitAsserted()) {
212 warn("memInhibitAsserted???");
213 // snooper will supply based on copy of packet
214 // still target's responsibility to delete packet
215 delete pkt;
216 return true;
217 }
218
219 // Save the port in the sender state object
220 pkt->senderState = new SenderState(this, pkt->senderState);
221
222 RubyRequestType type = RubyRequestType_NULL;
223 Addr pc = 0;
224 if (pkt->isRead()) {
225 if (pkt->req->isInstFetch()) {
226 type = RubyRequestType_IFETCH;
227 pc = pkt->req->getPC();
228 } else {
229 type = RubyRequestType_LD;
230 }
231 } else if (pkt->isWrite()) {
232 type = RubyRequestType_ST;
233 } else if (pkt->isReadWrite()) {
234 type = RubyRequestType_RMW;
235 }
236
237 RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
238 pkt->getSize(), pc, type,
239 RubyAccessMode_Supervisor);
240
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);
244 if (req_id == -1) {
245 RubyMemory::SenderState *senderState =
246 safe_cast<RubyMemory::SenderState *>(pkt->senderState);
247
248 // pop the sender state from the packet
249 pkt->senderState = senderState->saved;
250 delete senderState;
251 return false;
252 }
253
254 // Save the request for the callback
255 RubyMemory::pending_requests[req_id] = pkt;
256
257 return true;
258 }
259
260 void
261 ruby_hit_callback(int64_t req_id)
262 {
263 typedef map<int64_t, PacketPtr> map_t;
264 map_t &prm = RubyMemory::pending_requests;
265
266 map_t::iterator i = prm.find(req_id);
267 if (i == prm.end())
268 panic("could not find pending request %d\n", req_id);
269
270 PacketPtr pkt = i->second;
271 prm.erase(i);
272
273 RubyMemory::SenderState *senderState =
274 safe_cast<RubyMemory::SenderState *>(pkt->senderState);
275 RubyMemory::Port *port = senderState->port;
276
277 // pop the sender state from the packet
278 pkt->senderState = senderState->saved;
279 delete senderState;
280
281 port->ruby_mem->hitCallback(pkt, port);
282 }
283
284 void
285 RubyMemory::Port::sendTiming(PacketPtr pkt)
286 {
287 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
288 }
289
290 void RubyMemory::printConfigStats()
291 {
292 std::ostream *os = simout.create(params()->stats_file);
293 RubySystem::printConfig(*os);
294 *os << endl;
295 RubySystem::printStats(*os);
296 }
297
298
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);
304 }
305
306 void RubyMemory::clearStats() {
307 //g_system_ptr->clearStats();
308 }
309
310 void RubyMemory::printConfig(std::ostream & out) const {
311 //g_system_ptr->printConfig(out);
312 }
313
314
315 //Python-interface code
316 RubyMemory *
317 RubyMemoryParams::create()
318 {
319 return new RubyMemory(this);
320 }
321