includes: sort includes again
[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/types.hh"
37 #include "mem/ruby/common/Debug.hh"
38 #include "mem/ruby/init.hh"
39 #include "mem/ruby/system/Sequencer.hh"
40 #include "mem/ruby/system/System.hh"
41 #include "mem/rubymem.hh"
42 #include "sim/eventq.hh"
43 #include "sim/sim_exit.hh"
44
45 using namespace std;
46 using namespace TheISA;
47
48 RubyMemory::RubyMemory(const Params *p)
49 : PhysicalMemory(p)
50 {
51 config_file = p->config_file;
52 config_options = p->config_options;
53 stats_file = p->stats_file;
54 num_cpus = p->num_cpus;
55 ruby_clock = p->clock;
56 ruby_phase = p->phase;
57
58 debug = p->debug;
59 debug_file = p->debug_file;
60 }
61
62 void
63 RubyMemory::init()
64 {
65 init_variables();
66 g_NUM_PROCESSORS = num_cpus;
67
68 init_simulator(this);
69
70 if (debug) {
71 g_debug_ptr->setVerbosityString("high");
72 g_debug_ptr->setDebugTime(1);
73 if (debug_file != "") {
74 g_debug_ptr->setDebugOutputFile("ruby.debug");
75 }
76 }
77
78 //You may want to set some other options...
79 //g_debug_ptr->setVerbosityString("med");
80 //g_debug_ptr->setFilterString("lsNqST");
81 //g_debug_ptr->setFilterString("lsNST");
82 //g_debug_ptr->setDebugTime(1);
83 //g_debug_ptr->setDebugOutputFile("ruby.debug");
84
85
86 g_system_ptr->clearStats();
87
88 if (ports.size() == 0) {
89 fatal("RubyMemory object %s is unconnected!", name());
90 }
91
92 for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
93 if (*pi)
94 (*pi)->sendStatusChange(Port::RangeChange);
95 }
96
97 //Print stats at exit
98 RubyExitCallback* rc = new RubyExitCallback(this);
99 registerExitCallback(rc);
100
101 //Sched RubyEvent, automatically reschedules to advance ruby cycles
102 rubyTickEvent = new RubyEvent(this);
103 schedule(rubyTickEvent, curTick + ruby_clock + ruby_phase);
104 }
105
106 //called by rubyTickEvent
107 void RubyMemory::tick() {
108 g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1);
109 schedule(rubyTickEvent, curTick + ruby_clock); //dsm: clock_phase was added here. This is wrong, the phase is only added on the first tick
110 }
111
112
113 RubyMemory::~RubyMemory() {
114 delete g_system_ptr;
115 }
116
117 void
118 RubyMemory::hitCallback(Packet* pkt)
119 {
120 RubyMemoryPort* port = m_packet_to_port_map[pkt];
121 assert(port != NULL);
122 m_packet_to_port_map.erase(pkt);
123
124 DPRINTF(MemoryAccess, "Hit callback\n");
125
126 bool needsResponse = pkt->needsResponse();
127 doAtomicAccess(pkt);
128
129 // turn packet around to go back to requester if response expected
130 if (needsResponse) {
131 // recvAtomic() should already have turned packet into
132 // atomic response
133 assert(pkt->isResponse());
134 DPRINTF(MemoryAccess, "Sending packet back over port\n");
135 port->sendTiming(pkt);
136 } else {
137 delete pkt;
138 }
139 DPRINTF(MemoryAccess, "Hit callback done!\n");
140 }
141
142 Port *
143 RubyMemory::getPort(const std::string &if_name, int idx)
144 {
145 // Accept request for "functional" port for backwards compatibility
146 // with places where this function is called from C++. I'd prefer
147 // to move all these into Python someday.
148 if (if_name == "functional") {
149 return new RubyMemoryPort(csprintf("%s-functional", name()), this);
150 }
151
152 if (if_name != "port") {
153 panic("RubyMemory::getPort: unknown port %s requested", if_name);
154 }
155
156 if (idx >= ports.size()) {
157 ports.resize(idx+1);
158 }
159
160 if (ports[idx] != NULL) {
161 panic("RubyMemory::getPort: port %d already assigned", idx);
162 }
163
164 RubyMemoryPort *port =
165 new RubyMemoryPort(csprintf("%s-port%d", name(), idx), this);
166
167 ports[idx] = port;
168 return port;
169 }
170
171 RubyMemory::RubyMemoryPort::RubyMemoryPort(const std::string &_name,
172 RubyMemory *_memory)
173 : PhysicalMemory::MemoryPort::MemoryPort(_name, _memory)
174 {
175 ruby_mem = _memory;
176 }
177
178 bool
179 RubyMemory::RubyMemoryPort::recvTiming(PacketPtr pkt)
180 {
181 DPRINTF(MemoryAccess, "Timing access caught\n");
182
183 //dsm: based on SimpleTimingPort::recvTiming(pkt);
184
185 // If the device is only a slave, it should only be sending
186 // responses, which should never get nacked. There used to be
187 // code to hanldle nacks here, but I'm pretty sure it didn't work
188 // correctly with the drain code, so that would need to be fixed
189 // if we ever added it back.
190 assert(pkt->isRequest());
191
192 if (pkt->memInhibitAsserted()) {
193 warn("memInhibitAsserted???");
194 // snooper will supply based on copy of packet
195 // still target's responsibility to delete packet
196 delete pkt;
197 return true;
198 }
199
200 ruby_mem->m_packet_to_port_map[pkt] = this;
201
202 Sequencer* sequencer = g_system_ptr->getSequencer(pkt->req->contextId());
203
204 if ( ! sequencer->isReady(pkt) ) {
205 DPRINTF(MemoryAccess, "Sequencer isn't ready yet!!\n");
206 return false;
207 }
208
209 DPRINTF(MemoryAccess, "Issuing makeRequest\n");
210
211 sequencer->makeRequest(pkt);
212 return true;
213 }
214
215 void
216 RubyMemory::RubyMemoryPort::sendTiming(PacketPtr pkt)
217 {
218 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
219 }
220
221 void RubyMemory::printConfigStats()
222 {
223 std::ostream *os = simout.create(stats_file);
224 g_system_ptr->printConfig(*os);
225 *os << endl;
226 g_system_ptr->printStats(*os);
227 }
228
229
230 //Right now these functions seem to be called by RubySystem. If they do calls
231 // to RubySystem perform it intended actions, you'll get into an inf loop
232 //FIXME what's the purpose of these here?
233 void RubyMemory::printStats(std::ostream & out) const {
234 //g_system_ptr->printConfig(out);
235 }
236
237 void RubyMemory::clearStats() {
238 //g_system_ptr->clearStats();
239 }
240
241 void RubyMemory::printConfig(std::ostream & out) const {
242 //g_system_ptr->printConfig(out);
243 }
244
245
246 //Python-interface code
247 RubyMemory *
248 RubyMemoryParams::create()
249 {
250 return new RubyMemory(this);
251 }
252