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/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"
46 using namespace TheISA
;
48 RubyMemory::RubyMemory(const Params
*p
)
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
;
59 debug_file
= p
->debug_file
;
66 g_NUM_PROCESSORS
= num_cpus
;
71 g_debug_ptr
->setVerbosityString("high");
72 g_debug_ptr
->setDebugTime(1);
73 if (debug_file
!= "") {
74 g_debug_ptr
->setDebugOutputFile("ruby.debug");
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");
86 g_system_ptr
->clearStats();
88 if (ports
.size() == 0) {
89 fatal("RubyMemory object %s is unconnected!", name());
92 for (PortIterator pi
= ports
.begin(); pi
!= ports
.end(); ++pi
) {
94 (*pi
)->sendStatusChange(Port::RangeChange
);
98 RubyExitCallback
* rc
= new RubyExitCallback(this);
99 registerExitCallback(rc
);
101 //Sched RubyEvent, automatically reschedules to advance ruby cycles
102 rubyTickEvent
= new RubyEvent(this);
103 schedule(rubyTickEvent
, curTick
+ ruby_clock
+ ruby_phase
);
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
113 RubyMemory::~RubyMemory() {
118 RubyMemory::hitCallback(Packet
* pkt
)
120 RubyMemoryPort
* port
= m_packet_to_port_map
[pkt
];
121 assert(port
!= NULL
);
122 m_packet_to_port_map
.erase(pkt
);
124 DPRINTF(MemoryAccess
, "Hit callback\n");
126 bool needsResponse
= pkt
->needsResponse();
129 // turn packet around to go back to requester if response expected
131 // recvAtomic() should already have turned packet into
133 assert(pkt
->isResponse());
134 DPRINTF(MemoryAccess
, "Sending packet back over port\n");
135 port
->sendTiming(pkt
);
139 DPRINTF(MemoryAccess
, "Hit callback done!\n");
143 RubyMemory::getPort(const std::string
&if_name
, int idx
)
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);
152 if (if_name
!= "port") {
153 panic("RubyMemory::getPort: unknown port %s requested", if_name
);
156 if (idx
>= ports
.size()) {
160 if (ports
[idx
] != NULL
) {
161 panic("RubyMemory::getPort: port %d already assigned", idx
);
164 RubyMemoryPort
*port
=
165 new RubyMemoryPort(csprintf("%s-port%d", name(), idx
), this);
171 RubyMemory::RubyMemoryPort::RubyMemoryPort(const std::string
&_name
,
173 : PhysicalMemory::MemoryPort::MemoryPort(_name
, _memory
)
179 RubyMemory::RubyMemoryPort::recvTiming(PacketPtr pkt
)
181 DPRINTF(MemoryAccess
, "Timing access caught\n");
183 //dsm: based on SimpleTimingPort::recvTiming(pkt);
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());
192 if (pkt
->memInhibitAsserted()) {
193 warn("memInhibitAsserted???");
194 // snooper will supply based on copy of packet
195 // still target's responsibility to delete packet
200 ruby_mem
->m_packet_to_port_map
[pkt
] = this;
202 Sequencer
* sequencer
= g_system_ptr
->getSequencer(pkt
->req
->contextId());
204 if ( ! sequencer
->isReady(pkt
) ) {
205 DPRINTF(MemoryAccess
, "Sequencer isn't ready yet!!\n");
209 DPRINTF(MemoryAccess
, "Issuing makeRequest\n");
211 sequencer
->makeRequest(pkt
);
216 RubyMemory::RubyMemoryPort::sendTiming(PacketPtr pkt
)
218 schedSendTiming(pkt
, curTick
+ 1); //minimum latency, must be > 0
221 void RubyMemory::printConfigStats()
223 std::ostream
*os
= simout
.create(stats_file
);
224 g_system_ptr
->printConfig(*os
);
226 g_system_ptr
->printStats(*os
);
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);
237 void RubyMemory::clearStats() {
238 //g_system_ptr->clearStats();
241 void RubyMemory::printConfig(std::ostream
& out
) const {
242 //g_system_ptr->printConfig(out);
246 //Python-interface code
248 RubyMemoryParams::create()
250 return new RubyMemory(this);