3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
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;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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.
31 * $Id: Sequencer.C 1.131 2006/11/06 17:41:01-06:00 bobba@gratiano.cs.wisc.edu $
35 #include "mem/ruby/common/Global.hh"
36 #include "mem/ruby/system/Sequencer.hh"
37 #include "mem/ruby/system/System.hh"
38 #include "mem/protocol/Protocol.hh"
39 #include "mem/ruby/profiler/Profiler.hh"
40 #include "mem/ruby/system/CacheMemory.hh"
41 #include "mem/ruby/config/RubyConfig.hh"
42 //#include "mem/ruby/recorder/Tracer.hh"
43 #include "mem/ruby/slicc_interface/AbstractChip.hh"
44 #include "mem/protocol/Chip.hh"
45 #include "mem/ruby/tester/Tester.hh"
46 #include "mem/ruby/common/SubBlock.hh"
47 #include "mem/protocol/Protocol.hh"
48 #include "mem/gems_common/Map.hh"
49 #include "mem/packet.hh"
51 Sequencer::Sequencer(AbstractChip
* chip_ptr
, int version
) {
52 m_chip_ptr
= chip_ptr
;
55 m_deadlock_check_scheduled
= false;
56 m_outstanding_count
= 0;
58 int smt_threads
= RubyConfig::numberofSMTThreads();
59 m_writeRequestTable_ptr
= new Map
<Address
, CacheMsg
>*[smt_threads
];
60 m_readRequestTable_ptr
= new Map
<Address
, CacheMsg
>*[smt_threads
];
62 m_packetTable_ptr
= new Map
<Address
, Packet
*>;
64 for(int p
=0; p
< smt_threads
; ++p
){
65 m_writeRequestTable_ptr
[p
] = new Map
<Address
, CacheMsg
>;
66 m_readRequestTable_ptr
[p
] = new Map
<Address
, CacheMsg
>;
71 Sequencer::~Sequencer() {
72 int smt_threads
= RubyConfig::numberofSMTThreads();
73 for(int i
=0; i
< smt_threads
; ++i
){
74 if(m_writeRequestTable_ptr
[i
]){
75 delete m_writeRequestTable_ptr
[i
];
77 if(m_readRequestTable_ptr
[i
]){
78 delete m_readRequestTable_ptr
[i
];
81 if(m_writeRequestTable_ptr
){
82 delete [] m_writeRequestTable_ptr
;
84 if(m_readRequestTable_ptr
){
85 delete [] m_readRequestTable_ptr
;
89 void Sequencer::wakeup() {
90 // Check for deadlock of any of the requests
91 Time current_time
= g_eventQueue_ptr
->getTime();
92 bool deadlock
= false;
94 // Check across all outstanding requests
95 int smt_threads
= RubyConfig::numberofSMTThreads();
96 int total_outstanding
= 0;
97 for(int p
=0; p
< smt_threads
; ++p
){
98 Vector
<Address
> keys
= m_readRequestTable_ptr
[p
]->keys();
99 for (int i
=0; i
<keys
.size(); i
++) {
100 CacheMsg
& request
= m_readRequestTable_ptr
[p
]->lookup(keys
[i
]);
101 if (current_time
- request
.getTime() >= g_DEADLOCK_THRESHOLD
) {
102 WARN_MSG("Possible Deadlock detected");
104 WARN_EXPR(m_chip_ptr
->getID());
105 WARN_EXPR(m_version
);
106 WARN_EXPR(keys
.size());
107 WARN_EXPR(current_time
);
108 WARN_EXPR(request
.getTime());
109 WARN_EXPR(current_time
- request
.getTime());
110 WARN_EXPR(*m_readRequestTable_ptr
[p
]);
111 ERROR_MSG("Aborting");
116 keys
= m_writeRequestTable_ptr
[p
]->keys();
117 for (int i
=0; i
<keys
.size(); i
++) {
118 CacheMsg
& request
= m_writeRequestTable_ptr
[p
]->lookup(keys
[i
]);
119 if (current_time
- request
.getTime() >= g_DEADLOCK_THRESHOLD
) {
120 WARN_MSG("Possible Deadlock detected");
122 WARN_EXPR(m_chip_ptr
->getID());
123 WARN_EXPR(m_version
);
124 WARN_EXPR(current_time
);
125 WARN_EXPR(request
.getTime());
126 WARN_EXPR(current_time
- request
.getTime());
127 WARN_EXPR(keys
.size());
128 WARN_EXPR(*m_writeRequestTable_ptr
[p
]);
129 ERROR_MSG("Aborting");
133 total_outstanding
+= m_writeRequestTable_ptr
[p
]->size() + m_readRequestTable_ptr
[p
]->size();
134 } // across all request tables
135 assert(m_outstanding_count
== total_outstanding
);
137 if (m_outstanding_count
> 0) { // If there are still outstanding requests, keep checking
138 g_eventQueue_ptr
->scheduleEvent(this, g_DEADLOCK_THRESHOLD
);
140 m_deadlock_check_scheduled
= false;
144 //returns the total number of requests
145 int Sequencer::getNumberOutstanding(){
146 return m_outstanding_count
;
149 // returns the total number of demand requests
150 int Sequencer::getNumberOutstandingDemand(){
151 int smt_threads
= RubyConfig::numberofSMTThreads();
152 int total_demand
= 0;
153 for(int p
=0; p
< smt_threads
; ++p
){
154 Vector
<Address
> keys
= m_readRequestTable_ptr
[p
]->keys();
155 for (int i
=0; i
< keys
.size(); i
++) {
156 CacheMsg
& request
= m_readRequestTable_ptr
[p
]->lookup(keys
[i
]);
157 if(request
.getPrefetch() == PrefetchBit_No
){
162 keys
= m_writeRequestTable_ptr
[p
]->keys();
163 for (int i
=0; i
< keys
.size(); i
++) {
164 CacheMsg
& request
= m_writeRequestTable_ptr
[p
]->lookup(keys
[i
]);
165 if(request
.getPrefetch() == PrefetchBit_No
){
174 int Sequencer::getNumberOutstandingPrefetch(){
175 int smt_threads
= RubyConfig::numberofSMTThreads();
176 int total_prefetch
= 0;
177 for(int p
=0; p
< smt_threads
; ++p
){
178 Vector
<Address
> keys
= m_readRequestTable_ptr
[p
]->keys();
179 for (int i
=0; i
< keys
.size(); i
++) {
180 CacheMsg
& request
= m_readRequestTable_ptr
[p
]->lookup(keys
[i
]);
181 if(request
.getPrefetch() == PrefetchBit_Yes
){
186 keys
= m_writeRequestTable_ptr
[p
]->keys();
187 for (int i
=0; i
< keys
.size(); i
++) {
188 CacheMsg
& request
= m_writeRequestTable_ptr
[p
]->lookup(keys
[i
]);
189 if(request
.getPrefetch() == PrefetchBit_Yes
){
195 return total_prefetch
;
198 bool Sequencer::isPrefetchRequest(const Address
& lineaddr
){
199 int smt_threads
= RubyConfig::numberofSMTThreads();
200 for(int p
=0; p
< smt_threads
; ++p
){
201 // check load requests
202 Vector
<Address
> keys
= m_readRequestTable_ptr
[p
]->keys();
203 for (int i
=0; i
< keys
.size(); i
++) {
204 CacheMsg
& request
= m_readRequestTable_ptr
[p
]->lookup(keys
[i
]);
205 if(line_address(request
.getAddress()) == lineaddr
){
206 if(request
.getPrefetch() == PrefetchBit_Yes
){
215 // check store requests
216 keys
= m_writeRequestTable_ptr
[p
]->keys();
217 for (int i
=0; i
< keys
.size(); i
++) {
218 CacheMsg
& request
= m_writeRequestTable_ptr
[p
]->lookup(keys
[i
]);
219 if(line_address(request
.getAddress()) == lineaddr
){
220 if(request
.getPrefetch() == PrefetchBit_Yes
){
229 // we should've found a matching request
230 cout
<< "isRequestPrefetch() ERROR request NOT FOUND : " << lineaddr
<< endl
;
235 AccessModeType
Sequencer::getAccessModeOfRequest(Address addr
, int thread
){
236 if(m_readRequestTable_ptr
[thread
]->exist(line_address(addr
))){
237 CacheMsg
& request
= m_readRequestTable_ptr
[thread
]->lookup(addr
);
238 return request
.getAccessMode();
239 } else if(m_writeRequestTable_ptr
[thread
]->exist(line_address(addr
))){
240 CacheMsg
& request
= m_writeRequestTable_ptr
[thread
]->lookup(addr
);
241 return request
.getAccessMode();
244 ERROR_MSG("Request not found in RequestTables");
248 Address
Sequencer::getLogicalAddressOfRequest(Address addr
, int thread
){
250 if(m_readRequestTable_ptr
[thread
]->exist(line_address(addr
))){
251 CacheMsg
& request
= m_readRequestTable_ptr
[thread
]->lookup(addr
);
252 return request
.getLogicalAddress();
253 } else if(m_writeRequestTable_ptr
[thread
]->exist(line_address(addr
))){
254 CacheMsg
& request
= m_writeRequestTable_ptr
[thread
]->lookup(addr
);
255 return request
.getLogicalAddress();
258 WARN_MSG("Request not found in RequestTables");
265 // returns the ThreadID of the request
266 int Sequencer::getRequestThreadID(const Address
& addr
){
267 int smt_threads
= RubyConfig::numberofSMTThreads();
270 for(int p
=0; p
< smt_threads
; ++p
){
271 if(m_readRequestTable_ptr
[p
]->exist(addr
)){
275 if(m_writeRequestTable_ptr
[p
]->exist(addr
)){
281 cout
<< "getRequestThreadID ERROR too many matching requests addr = " << addr
<< endl
;
284 ASSERT(num_found
== 1);
285 ASSERT(thread
!= -1);
290 // given a line address, return the request's physical address
291 Address
Sequencer::getRequestPhysicalAddress(const Address
& lineaddr
){
292 int smt_threads
= RubyConfig::numberofSMTThreads();
295 for(int p
=0; p
< smt_threads
; ++p
){
296 if(m_readRequestTable_ptr
[p
]->exist(lineaddr
)){
298 physaddr
= (m_readRequestTable_ptr
[p
]->lookup(lineaddr
)).getAddress();
300 if(m_writeRequestTable_ptr
[p
]->exist(lineaddr
)){
302 physaddr
= (m_writeRequestTable_ptr
[p
]->lookup(lineaddr
)).getAddress();
306 cout
<< "getRequestPhysicalAddress ERROR too many matching requests addr = " << lineaddr
<< endl
;
309 ASSERT(num_found
== 1);
314 void Sequencer::printProgress(ostream
& out
) const{
316 int total_demand
= 0;
317 out
<< "Sequencer Stats Version " << m_version
<< endl
;
318 out
<< "Current time = " << g_eventQueue_ptr
->getTime() << endl
;
319 out
<< "---------------" << endl
;
320 out
<< "outstanding requests" << endl
;
322 int smt_threads
= RubyConfig::numberofSMTThreads();
323 for(int p
=0; p
< smt_threads
; ++p
){
324 Vector
<Address
> rkeys
= m_readRequestTable_ptr
[p
]->keys();
325 int read_size
= rkeys
.size();
326 out
<< "proc " << m_chip_ptr
->getID() << " thread " << p
<< " Read Requests = " << read_size
<< endl
;
327 // print the request table
328 for(int i
=0; i
< read_size
; ++i
){
329 CacheMsg
& request
= m_readRequestTable_ptr
[p
]->lookup(rkeys
[i
]);
330 out
<< "\tRequest[ " << i
<< " ] = " << request
.getType() << " Address " << rkeys
[i
] << " Posted " << request
.getTime() << " PF " << request
.getPrefetch() << endl
;
331 if( request
.getPrefetch() == PrefetchBit_No
){
336 Vector
<Address
> wkeys
= m_writeRequestTable_ptr
[p
]->keys();
337 int write_size
= wkeys
.size();
338 out
<< "proc " << m_chip_ptr
->getID() << " thread " << p
<< " Write Requests = " << write_size
<< endl
;
339 // print the request table
340 for(int i
=0; i
< write_size
; ++i
){
341 CacheMsg
& request
= m_writeRequestTable_ptr
[p
]->lookup(wkeys
[i
]);
342 out
<< "\tRequest[ " << i
<< " ] = " << request
.getType() << " Address " << wkeys
[i
] << " Posted " << request
.getTime() << " PF " << request
.getPrefetch() << endl
;
343 if( request
.getPrefetch() == PrefetchBit_No
){
350 out
<< "Total Number Outstanding: " << m_outstanding_count
<< endl
;
351 out
<< "Total Number Demand : " << total_demand
<< endl
;
352 out
<< "Total Number Prefetches : " << m_outstanding_count
- total_demand
<< endl
;
358 void Sequencer::printConfig(ostream
& out
) {
360 out
<< "sequencer: Sequencer - TSO" << endl
;
362 out
<< "sequencer: Sequencer - SC" << endl
;
364 out
<< " max_outstanding_requests: " << g_SEQUENCER_OUTSTANDING_REQUESTS
<< endl
;
367 bool Sequencer::empty() const {
368 return m_outstanding_count
== 0;
371 // Insert the request on the correct request table. Return true if
372 // the entry was already present.
373 bool Sequencer::insertRequest(const CacheMsg
& request
) {
374 int thread
= request
.getThreadID();
376 int total_outstanding
= 0;
377 int smt_threads
= RubyConfig::numberofSMTThreads();
378 for(int p
=0; p
< smt_threads
; ++p
){
379 total_outstanding
+= m_writeRequestTable_ptr
[p
]->size() + m_readRequestTable_ptr
[p
]->size();
381 assert(m_outstanding_count
== total_outstanding
);
383 // See if we should schedule a deadlock check
384 if (m_deadlock_check_scheduled
== false) {
385 g_eventQueue_ptr
->scheduleEvent(this, g_DEADLOCK_THRESHOLD
);
386 m_deadlock_check_scheduled
= true;
389 if ((request
.getType() == CacheRequestType_ST
) ||
390 (request
.getType() == CacheRequestType_ATOMIC
)) {
391 if (m_writeRequestTable_ptr
[thread
]->exist(line_address(request
.getAddress()))) {
392 m_writeRequestTable_ptr
[thread
]->lookup(line_address(request
.getAddress())) = request
;
395 m_writeRequestTable_ptr
[thread
]->allocate(line_address(request
.getAddress()));
396 m_writeRequestTable_ptr
[thread
]->lookup(line_address(request
.getAddress())) = request
;
397 m_outstanding_count
++;
399 if (m_readRequestTable_ptr
[thread
]->exist(line_address(request
.getAddress()))) {
400 m_readRequestTable_ptr
[thread
]->lookup(line_address(request
.getAddress())) = request
;
403 m_readRequestTable_ptr
[thread
]->allocate(line_address(request
.getAddress()));
404 m_readRequestTable_ptr
[thread
]->lookup(line_address(request
.getAddress())) = request
;
405 m_outstanding_count
++;
408 g_system_ptr
->getProfiler()->sequencerRequests(m_outstanding_count
);
410 total_outstanding
= 0;
411 for(int p
=0; p
< smt_threads
; ++p
){
412 total_outstanding
+= m_writeRequestTable_ptr
[p
]->size() + m_readRequestTable_ptr
[p
]->size();
415 assert(m_outstanding_count
== total_outstanding
);
419 void Sequencer::removeRequest(const CacheMsg
& request
) {
420 int thread
= request
.getThreadID();
422 int total_outstanding
= 0;
423 int smt_threads
= RubyConfig::numberofSMTThreads();
424 for(int p
=0; p
< smt_threads
; ++p
){
425 total_outstanding
+= m_writeRequestTable_ptr
[p
]->size() + m_readRequestTable_ptr
[p
]->size();
427 assert(m_outstanding_count
== total_outstanding
);
429 if ((request
.getType() == CacheRequestType_ST
) ||
430 (request
.getType() == CacheRequestType_ATOMIC
)) {
431 m_writeRequestTable_ptr
[thread
]->deallocate(line_address(request
.getAddress()));
433 m_readRequestTable_ptr
[thread
]->deallocate(line_address(request
.getAddress()));
435 m_outstanding_count
--;
437 total_outstanding
= 0;
438 for(int p
=0; p
< smt_threads
; ++p
){
439 total_outstanding
+= m_writeRequestTable_ptr
[p
]->size() + m_readRequestTable_ptr
[p
]->size();
441 assert(m_outstanding_count
== total_outstanding
);
444 void Sequencer::writeCallback(const Address
& address
) {
446 writeCallback(address
, data
);
449 void Sequencer::writeCallback(const Address
& address
, DataBlock
& data
) {
450 // process oldest thread first
452 Time oldest_time
= 0;
453 int smt_threads
= RubyConfig::numberofSMTThreads();
454 for(int t
=0; t
< smt_threads
; ++t
){
455 if(m_writeRequestTable_ptr
[t
]->exist(address
)){
456 CacheMsg
& request
= m_writeRequestTable_ptr
[t
]->lookup(address
);
457 if(thread
== -1 || (request
.getTime() < oldest_time
) ){
459 oldest_time
= request
.getTime();
463 // make sure we found an oldest thread
464 ASSERT(thread
!= -1);
466 CacheMsg
& request
= m_writeRequestTable_ptr
[thread
]->lookup(address
);
468 writeCallback(address
, data
, GenericMachineType_NULL
, PrefetchBit_No
, thread
);
471 void Sequencer::writeCallback(const Address
& address
, DataBlock
& data
, GenericMachineType respondingMach
, PrefetchBit pf
, int thread
) {
473 assert(address
== line_address(address
));
475 assert(m_writeRequestTable_ptr
[thread
]->exist(line_address(address
)));
477 writeCallback(address
, data
, respondingMach
, thread
);
481 void Sequencer::writeCallback(const Address
& address
, DataBlock
& data
, GenericMachineType respondingMach
, int thread
) {
482 assert(address
== line_address(address
));
483 assert(m_writeRequestTable_ptr
[thread
]->exist(line_address(address
)));
484 CacheMsg request
= m_writeRequestTable_ptr
[thread
]->lookup(address
);
485 assert( request
.getThreadID() == thread
);
486 removeRequest(request
);
488 assert((request
.getType() == CacheRequestType_ST
) ||
489 (request
.getType() == CacheRequestType_ATOMIC
));
491 hitCallback(request
, data
, respondingMach
, thread
);
495 void Sequencer::readCallback(const Address
& address
) {
497 readCallback(address
, data
);
500 void Sequencer::readCallback(const Address
& address
, DataBlock
& data
) {
501 // process oldest thread first
503 Time oldest_time
= 0;
504 int smt_threads
= RubyConfig::numberofSMTThreads();
505 for(int t
=0; t
< smt_threads
; ++t
){
506 if(m_readRequestTable_ptr
[t
]->exist(address
)){
507 CacheMsg
& request
= m_readRequestTable_ptr
[t
]->lookup(address
);
508 if(thread
== -1 || (request
.getTime() < oldest_time
) ){
510 oldest_time
= request
.getTime();
514 // make sure we found an oldest thread
515 ASSERT(thread
!= -1);
517 CacheMsg
& request
= m_readRequestTable_ptr
[thread
]->lookup(address
);
519 readCallback(address
, data
, GenericMachineType_NULL
, PrefetchBit_No
, thread
);
522 void Sequencer::readCallback(const Address
& address
, DataBlock
& data
, GenericMachineType respondingMach
, PrefetchBit pf
, int thread
) {
524 assert(address
== line_address(address
));
525 assert(m_readRequestTable_ptr
[thread
]->exist(line_address(address
)));
527 readCallback(address
, data
, respondingMach
, thread
);
530 void Sequencer::readCallback(const Address
& address
, DataBlock
& data
, GenericMachineType respondingMach
, int thread
) {
531 assert(address
== line_address(address
));
532 assert(m_readRequestTable_ptr
[thread
]->exist(line_address(address
)));
534 CacheMsg request
= m_readRequestTable_ptr
[thread
]->lookup(address
);
535 assert( request
.getThreadID() == thread
);
536 removeRequest(request
);
538 assert((request
.getType() == CacheRequestType_LD
) ||
539 (request
.getType() == CacheRequestType_IFETCH
)
542 hitCallback(request
, data
, respondingMach
, thread
);
545 void Sequencer::hitCallback(const CacheMsg
& request
, DataBlock
& data
, GenericMachineType respondingMach
, int thread
) {
546 int size
= request
.getSize();
547 Address request_address
= request
.getAddress();
548 Address request_logical_address
= request
.getLogicalAddress();
549 Address request_line_address
= line_address(request_address
);
550 CacheRequestType type
= request
.getType();
551 int threadID
= request
.getThreadID();
552 Time issued_time
= request
.getTime();
553 int logical_proc_no
= ((m_chip_ptr
->getID() * RubyConfig::numberOfProcsPerChip()) + m_version
) * RubyConfig::numberofSMTThreads() + threadID
;
555 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, size
);
557 // Set this cache entry to the most recently used
558 if (type
== CacheRequestType_IFETCH
) {
559 if (Protocol::m_TwoLevelCache
) {
560 if (m_chip_ptr
->m_L1Cache_L1IcacheMemory_vec
[m_version
]->isTagPresent(request_line_address
)) {
561 m_chip_ptr
->m_L1Cache_L1IcacheMemory_vec
[m_version
]->setMRU(request_line_address
);
565 if (m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->isTagPresent(request_line_address
)) {
566 m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->setMRU(request_line_address
);
570 if (Protocol::m_TwoLevelCache
) {
571 if (m_chip_ptr
->m_L1Cache_L1DcacheMemory_vec
[m_version
]->isTagPresent(request_line_address
)) {
572 m_chip_ptr
->m_L1Cache_L1DcacheMemory_vec
[m_version
]->setMRU(request_line_address
);
576 if (m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->isTagPresent(request_line_address
)) {
577 m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->setMRU(request_line_address
);
582 assert(g_eventQueue_ptr
->getTime() >= issued_time
);
583 Time miss_latency
= g_eventQueue_ptr
->getTime() - issued_time
;
585 if (PROTOCOL_DEBUG_TRACE
) {
586 g_system_ptr
->getProfiler()->profileTransition("Seq", (m_chip_ptr
->getID()*RubyConfig::numberOfProcsPerChip()+m_version
), -1, request
.getAddress(), "", "Done", "",
587 int_to_string(miss_latency
)+" cycles "+GenericMachineType_to_string(respondingMach
)+" "+CacheRequestType_to_string(request
.getType())+" "+PrefetchBit_to_string(request
.getPrefetch()));
590 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, request_address
);
591 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, request
.getPrefetch());
592 if (request
.getPrefetch() == PrefetchBit_Yes
) {
593 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, "return");
594 g_system_ptr
->getProfiler()->swPrefetchLatency(miss_latency
, type
, respondingMach
);
595 return; // Ignore the software prefetch, don't callback the driver
598 // Profile the miss latency for all non-zero demand misses
599 if (miss_latency
!= 0) {
600 g_system_ptr
->getProfiler()->missLatency(miss_latency
, type
, respondingMach
);
605 (type
== CacheRequestType_ST
) ||
606 (type
== CacheRequestType_ATOMIC
);
609 m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->callBack(line_address(request
.getAddress()), data
,
610 m_packetTable_ptr
->lookup(request
.getAddress()));
613 // Copy the correct bytes out of the cache line into the subblock
614 SubBlock
subblock(request_address
, request_logical_address
, size
);
615 subblock
.mergeFrom(data
); // copy the correct bytes from DataBlock in the SubBlock
617 // Scan the store buffer to see if there are any outstanding stores we need to collect
619 m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->updateSubBlock(subblock
);
622 // Call into the Driver and let it read and/or modify the sub-block
623 Packet
* pkt
= m_packetTable_ptr
->lookup(request
.getAddress());
625 // update data if this is a store/atomic
628 if (pkt->req->isCondSwap()) {
629 L1Cache_Entry entry = m_L1Cache_vec[m_version]->lookup(Address(pkt->req->physAddr()));
630 DataBlk datablk = entry->getDataBlk();
631 uint8_t *orig_data = datablk.getArray();
632 if ( datablk.equal(pkt->req->getExtraData()) )
633 datablk->setArray(pkt->getData());
634 pkt->setData(orig_data);
638 g_system_ptr
->getDriver()->hitCallback(pkt
);
639 m_packetTable_ptr
->remove(request
.getAddress());
641 // If the request was a Store or Atomic, apply the changes in the SubBlock to the DataBlock
642 // (This is only triggered for the non-TSO case)
645 subblock
.mergeTo(data
); // copy the correct bytes from SubBlock into the DataBlock
650 void Sequencer::printDebug(){
651 //notify driver of debug
652 g_system_ptr
->getDriver()->printDebug();
655 //dsm: breaks build, delayed
656 // Returns true if the sequencer already has a load or store outstanding
658 Sequencer::isReady(const Packet
* pkt
) const
661 int cpu_number
= pkt
->req
->contextId();
662 la_t logical_addr
= pkt
->req
->getVaddr();
663 pa_t physical_addr
= pkt
->req
->getPaddr();
664 CacheRequestType type_of_request
;
665 if ( pkt
->req
->isInstFetch() ) {
666 type_of_request
= CacheRequestType_IFETCH
;
667 } else if ( pkt
->req
->isLocked() || pkt
->req
->isSwap() ) {
668 type_of_request
= CacheRequestType_ATOMIC
;
669 } else if ( pkt
->isRead() ) {
670 type_of_request
= CacheRequestType_LD
;
671 } else if ( pkt
->isWrite() ) {
672 type_of_request
= CacheRequestType_ST
;
676 int thread
= pkt
->req
->threadId();
678 CacheMsg
request(Address( physical_addr
),
679 Address( physical_addr
),
682 AccessModeType_UserMode
, // User/supervisor mode
683 0, // Size in bytes of request
684 PrefetchBit_No
, // Not a prefetch
686 Address(logical_addr
), // Virtual Address
689 return isReady(request
);
693 Sequencer::isReady(const CacheMsg
& request
) const
695 if (m_outstanding_count
>= g_SEQUENCER_OUTSTANDING_REQUESTS
) {
696 //cout << "TOO MANY OUTSTANDING: " << m_outstanding_count << " " << g_SEQUENCER_OUTSTANDING_REQUESTS << " VER " << m_version << endl;
697 //printProgress(cout);
701 // This code allows reads to be performed even when we have a write
702 // request outstanding for the line
704 (request
.getType() == CacheRequestType_ST
) ||
705 (request
.getType() == CacheRequestType_ATOMIC
);
707 // LUKE - disallow more than one request type per address
708 // INVARIANT: at most one request type per address, per processor
709 int smt_threads
= RubyConfig::numberofSMTThreads();
710 for(int p
=0; p
< smt_threads
; ++p
){
711 if( m_writeRequestTable_ptr
[p
]->exist(line_address(request
.getAddress())) ||
712 m_readRequestTable_ptr
[p
]->exist(line_address(request
.getAddress())) ){
713 //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl;
714 //printProgress(cout);
720 return m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->isReady();
725 //dsm: breaks build, delayed
726 // Called by Driver (Simics or Tester).
728 Sequencer::makeRequest(Packet
* pkt
)
730 int cpu_number
= pkt
->req
->contextId();
731 la_t logical_addr
= pkt
->req
->getVaddr();
732 pa_t physical_addr
= pkt
->req
->getPaddr();
733 int request_size
= pkt
->getSize();
734 CacheRequestType type_of_request
;
735 PrefetchBit prefetch
;
737 if ( pkt
->req
->isInstFetch() ) {
738 type_of_request
= CacheRequestType_IFETCH
;
739 } else if ( pkt
->req
->isLocked() || pkt
->req
->isSwap() ) {
740 type_of_request
= CacheRequestType_ATOMIC
;
742 } else if ( pkt
->isRead() ) {
743 type_of_request
= CacheRequestType_LD
;
744 } else if ( pkt
->isWrite() ) {
745 type_of_request
= CacheRequestType_ST
;
750 if (pkt
->req
->isPrefetch()) {
751 prefetch
= PrefetchBit_Yes
;
753 prefetch
= PrefetchBit_No
;
755 la_t virtual_pc
= pkt
->req
->getPC();
756 int isPriv
= false; // TODO: get permission data
757 int thread
= pkt
->req
->threadId();
759 AccessModeType access_mode
= AccessModeType_UserMode
; // TODO: get actual permission
761 CacheMsg
request(Address( physical_addr
),
762 Address( physical_addr
),
765 access_mode
, // User/supervisor mode
766 request_size
, // Size in bytes of request
769 Address(logical_addr
), // Virtual Address
773 if ( TSO
&& write
&& !pkt
->req
->isPrefetch() ) {
774 assert(m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->isReady());
775 m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->insertStore(pkt
, request
);
779 m_packetTable_ptr
->insert(Address( physical_addr
), pkt
);
784 bool Sequencer::doRequest(const CacheMsg
& request
) {
786 // Check the fast path
789 int thread
= request
.getThreadID();
791 hit
= tryCacheAccess(line_address(request
.getAddress()),
793 request
.getProgramCounter(),
794 request
.getAccessMode(),
798 if (hit
&& (request
.getType() == CacheRequestType_IFETCH
|| !REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH
) ) {
799 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, "Fast path hit");
800 hitCallback(request
, *data_ptr
, GenericMachineType_L1Cache
, thread
);
804 if (TSO
&& (request
.getType() == CacheRequestType_LD
|| request
.getType() == CacheRequestType_IFETCH
)) {
806 // See if we can satisfy the load entirely from the store buffer
807 SubBlock
subblock(line_address(request
.getAddress()), request
.getSize());
808 if (m_chip_ptr
->m_L1Cache_storeBuffer_vec
[m_version
]->trySubBlock(subblock
)) {
810 hitCallback(request
, dummy
, GenericMachineType_NULL
, thread
); // Call with an 'empty' datablock, since the data is in the store buffer
815 DEBUG_MSG(SEQUENCER_COMP
, MedPrio
, "Fast path miss");
816 issueRequest(request
);
820 void Sequencer::issueRequest(const CacheMsg
& request
) {
821 bool found
= insertRequest(request
);
824 CacheMsg msg
= request
;
825 msg
.getAddress() = line_address(request
.getAddress()); // Make line address
827 // Fast Path L1 misses are profiled here - all non-fast path misses are profiled within the generated protocol code
828 if (!REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH
) {
829 g_system_ptr
->getProfiler()->addPrimaryStatSample(msg
, m_chip_ptr
->getID());
832 if (PROTOCOL_DEBUG_TRACE
) {
833 g_system_ptr
->getProfiler()->profileTransition("Seq", (m_chip_ptr
->getID()*RubyConfig::numberOfProcsPerChip() + m_version
), -1, msg
.getAddress(),"", "Begin", "", CacheRequestType_to_string(request
.getType()));
837 // Commented out by nate binkert because I removed the trace stuff
838 if (g_system_ptr
->getTracer()->traceEnabled()) {
839 g_system_ptr
->getTracer()->traceRequest((m_chip_ptr
->getID()*RubyConfig::numberOfProcsPerChip()+m_version
), msg
.getAddress(), msg
.getProgramCounter(),
840 msg
.getType(), g_eventQueue_ptr
->getTime());
844 Time latency
= 0; // initialzed to an null value
846 latency
= SEQUENCER_TO_CONTROLLER_LATENCY
;
848 // Send the message to the cache controller
850 m_chip_ptr
->m_L1Cache_mandatoryQueue_vec
[m_version
]->enqueue(msg
, latency
);
855 bool Sequencer::tryCacheAccess(const Address
& addr
, CacheRequestType type
,
856 const Address
& pc
, AccessModeType access_mode
,
857 int size
, DataBlock
*& data_ptr
) {
858 if (type
== CacheRequestType_IFETCH
) {
859 if (Protocol::m_TwoLevelCache
) {
860 return m_chip_ptr
->m_L1Cache_L1IcacheMemory_vec
[m_version
]->tryCacheAccess(line_address(addr
), type
, data_ptr
);
863 return m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->tryCacheAccess(line_address(addr
), type
, data_ptr
);
866 if (Protocol::m_TwoLevelCache
) {
867 return m_chip_ptr
->m_L1Cache_L1DcacheMemory_vec
[m_version
]->tryCacheAccess(line_address(addr
), type
, data_ptr
);
870 return m_chip_ptr
->m_L1Cache_cacheMemory_vec
[m_version
]->tryCacheAccess(line_address(addr
), type
, data_ptr
);
875 void Sequencer::resetRequestTime(const Address
& addr
, int thread
){
877 //reset both load and store requests, if they exist
878 if(m_readRequestTable_ptr
[thread
]->exist(line_address(addr
))){
879 CacheMsg
& request
= m_readRequestTable_ptr
[thread
]->lookup(addr
);
880 if( request
.m_AccessMode
!= AccessModeType_UserMode
){
881 cout
<< "resetRequestType ERROR read request addr = " << addr
<< " thread = "<< thread
<< " is SUPERVISOR MODE" << endl
;
884 //ASSERT(request.m_AccessMode == AccessModeType_UserMode);
885 request
.setTime(g_eventQueue_ptr
->getTime());
887 if(m_writeRequestTable_ptr
[thread
]->exist(line_address(addr
))){
888 CacheMsg
& request
= m_writeRequestTable_ptr
[thread
]->lookup(addr
);
889 if( request
.m_AccessMode
!= AccessModeType_UserMode
){
890 cout
<< "resetRequestType ERROR write request addr = " << addr
<< " thread = "<< thread
<< " is SUPERVISOR MODE" << endl
;
893 //ASSERT(request.m_AccessMode == AccessModeType_UserMode);
894 request
.setTime(g_eventQueue_ptr
->getTime());
898 // removes load request from queue
899 void Sequencer::removeLoadRequest(const Address
& addr
, int thread
){
900 removeRequest(getReadRequest(addr
, thread
));
903 void Sequencer::removeStoreRequest(const Address
& addr
, int thread
){
904 removeRequest(getWriteRequest(addr
, thread
));
907 // returns the read CacheMsg
908 CacheMsg
& Sequencer::getReadRequest( const Address
& addr
, int thread
){
911 assert(temp
== line_address(temp
));
912 assert(m_readRequestTable_ptr
[thread
]->exist(addr
));
913 return m_readRequestTable_ptr
[thread
]->lookup(addr
);
916 CacheMsg
& Sequencer::getWriteRequest( const Address
& addr
, int thread
){
919 assert(temp
== line_address(temp
));
920 assert(m_writeRequestTable_ptr
[thread
]->exist(addr
));
921 return m_writeRequestTable_ptr
[thread
]->lookup(addr
);
924 void Sequencer::print(ostream
& out
) const {
925 out
<< "[Sequencer: " << m_chip_ptr
->getID()
926 << ", outstanding requests: " << m_outstanding_count
;
928 int smt_threads
= RubyConfig::numberofSMTThreads();
929 for(int p
=0; p
< smt_threads
; ++p
){
930 out
<< ", read request table[ " << p
<< " ]: " << *m_readRequestTable_ptr
[p
]
931 << ", write request table[ " << p
<< " ]: " << *m_writeRequestTable_ptr
[p
];
936 // this can be called from setState whenever coherence permissions are upgraded
937 // when invoked, coherence violations will be checked for the given block
938 void Sequencer::checkCoherence(const Address
& addr
) {
939 #ifdef CHECK_COHERENCE
940 g_system_ptr
->checkGlobalCoherenceInvariant(addr
);
944 bool Sequencer::getRubyMemoryValue(const Address
& addr
, char* value
,
945 unsigned int size_in_bytes
) {
946 for(unsigned int i
=0; i
< size_in_bytes
; i
++) {
947 std::cerr
<< __FILE__
<< "(" << __LINE__
<< "): Not implemented. " << std::endl
;
948 value
[i
] = 0; // _read_physical_memory( m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version,
949 // addr.getAddress() + i, 1 );
951 return false; // Do nothing?
954 bool Sequencer::setRubyMemoryValue(const Address
& addr
, char *value
,
955 unsigned int size_in_bytes
) {
956 char test_buffer
[64];
958 return false; // Do nothing?