diff options
Diffstat (limited to 'src/mem/ruby/tester/RaceyPseudoThread.cc')
-rw-r--r-- | src/mem/ruby/tester/RaceyPseudoThread.cc | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/src/mem/ruby/tester/RaceyPseudoThread.cc b/src/mem/ruby/tester/RaceyPseudoThread.cc new file mode 100644 index 000000000..e5e1c1169 --- /dev/null +++ b/src/mem/ruby/tester/RaceyPseudoThread.cc @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1999 Mark D. Hill and David A. Wood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Description: see RaceyPseudoThread.hh + */ + +#include "mem/ruby/tester/RaceyPseudoThread.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/tester/RaceyDriver.hh" +#include "gzstream.hh" + +RaceyPseudoThread::RaceyPseudoThread(NodeID id, RaceyDriver& driver) + : m_driver(driver), m_proc_id(id) { + + resetIC(); // IC contains the committed instruction number + m_last_progress = 0; + m_done = false; + m_stop = 0; + m_driver.eventQueue->scheduleEvent(this, 1); +} + +RaceyPseudoThread::~RaceyPseudoThread() { +} + +void RaceyPseudoThread::checkForDeadlock() { + Time current_time = m_driver.eventQueue->getTime(); + if(!m_done && (current_time - m_last_progress) > g_DEADLOCK_THRESHOLD) { + WARN_EXPR(m_proc_id); + WARN_EXPR(m_ic_counter); + WARN_EXPR(m_last_progress); + ERROR_MSG("Deadlock detected."); + } +} + +void RaceyPseudoThread::performCallback(int proc, Address address, uint8_t * data ) { + assert(proc == m_proc_id); + + DEBUG_EXPR(TESTER_COMP, LowPrio, proc); + DEBUG_EXPR(TESTER_COMP, LowPrio, address); + + + m_last_progress = m_driver.eventQueue->getTime(); + + if(m_read) { + int b0, b1, b2, b3; + b0 = data[0]; b0 <<= 0; + b1 = data[1]; b1 <<= 8; + b2 = data[2]; b2 <<= 16; + b3 = data[3]; b3 <<= 24; + m_value = b0 | b1 | b2 | b3; + } else { + char b0, b1, b2, b3; + b0 = (m_value>>0)&0xFF; data[0] = b0; + b1 = (m_value>>8)&0xFF; data[1] = b1; + b2 = (m_value>>16)&0xFF; data[2] = b2; + b3 = (m_value>>24)&0xFF; data[3] = b3; + } + + // schedule wakeup for next requests in next cycle + m_driver.eventQueue->scheduleEvent(this, 1); + + // new instruction + m_ic_counter++; + +} + +void RaceyPseudoThread::wakeup() { + // for debug + if(m_stop != 0) { + cout << m_proc_id << " " << m_stop << ((m_read)? " read ":" written ") << m_value; + if(0) cout << " [" << m_driver.eventQueue->getTime() << "]"; + cout << endl; + } + + assert(!m_done); + + // Note, this function can not have ANY local variable! + + switch(m_stop) { + case 0: + break; + case 1: + goto L1; + case 2: + goto L2; + case 3: + goto L3; + case 4: + goto L4; + case 5: + goto L5; + case 6: + goto L6; + case 7: + goto L7; + case 8: + goto L8; + case 9: + goto L9; + case 10: + goto L10; + default: + WARN_EXPR(m_stop); + ERROR_MSG("RaceyPseudoThread: Bad context point!"); + } + + // + // initialization + // + if(m_proc_id == 0) { + for(m_looper = 0; m_looper < m_driver.m_num_procs; m_looper++) { + store_sig(m_looper, m_looper+1); + m_stop = 6; return; +L6: {}; + } + for(m_looper = 0; m_looper < M_ELEM; m_looper++) { + store_m(m_looper, M_ELEM-m_looper); + m_stop = 7; return; +L7: {}; + } + + // init done + m_initialized = true; + } else { + // other processors + if(!m_driver.Thread0Initialized()) { + // wait for processors 0 + m_driver.eventQueue->scheduleEvent(this, 1); + return; + } + } + + cout << "Thread " << m_proc_id << " started in parallel phase" << endl; + + // + // main thread body + // + for(m_looper = 0 ; m_looper < m_driver.m_tester_length; m_looper++) { + /* m_value = */ load_sig(m_proc_id); + m_stop = 1; return; +L1: {}; + m_num = m_value; + m_index1 = m_num%M_ELEM; + /* m_value = */ load_m(m_index1); + m_stop = 2; return; +L2: {}; + m_num = mix(m_num, m_value); + m_index2 = m_num%M_ELEM; + /* m_value = */ load_m(m_index2); + m_stop = 3; return; +L3: {}; + m_num = mix(m_num, m_value); + store_m(m_index2, m_num); + m_stop = 4; return; +L4: {}; + store_sig(m_proc_id, m_num); + m_stop = 5; return; +L5: {}; + } // end for + + // + // compute final sig + // + if(m_proc_id == 0) { + // wait for other threads + while (m_driver.runningThreads() > 1) { + m_driver.registerThread0Wakeup(); + m_stop = 10; return; +L10: {}; + } + + /* m_value = */ load_sig(0); + m_stop = 8; return; +L8: {}; + m_final_sig = m_value; + for(m_looper = 1; m_looper < m_driver.m_num_procs; m_looper++) { + /* m_value = */ load_sig(m_looper); + m_stop = 9; return; +L9: {}; + m_final_sig = mix(m_value, m_final_sig); + } + } // processors 0 + + // done + m_driver.joinThread(); + m_done = true; +} + +void RaceyPseudoThread::load_sig(unsigned index) { + cout << m_proc_id << " : load_sig " << index << endl; + + m_read = true; + // timestamp, threadid, action, and logical address are used only by transactional memory, should be augmented + uint8_t * read_data = new uint8_t[4]; + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(sig(index), read_data, 4, 0, RubyRequestType_LD, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(sig(index)); + request_data.data = read_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(sig(index)), Address(sig(index)), CacheRequestType_LD, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0 , false)); */ +} + +void RaceyPseudoThread::load_m(unsigned index) { + // cout << m_proc_id << " : load_m " << index << endl; + + m_read = true; + uint8_t * read_data = new uint8_t[4]; + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m(index), read_data, 4, 0, RubyRequestType_LD, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(m(index)); + request_data.data = read_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(m(index)), Address(m(index)), CacheRequestType_LD, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +void RaceyPseudoThread::store_sig(unsigned index, unsigned value) { + cout << m_proc_id << " : store_sig " << index << " " << value << endl; + + m_read = false; + m_value = value; + uint8_t * write_data = new uint8_t[4]; + + memcpy(write_data, &value, 4); + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(sig(index), write_data, 4, 0, RubyRequestType_ST, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(sig(index)); + request_data.data = write_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(sig(index)), Address(sig(index)), CacheRequestType_ST, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +void RaceyPseudoThread::store_m(unsigned index, unsigned value) { + //cout << m_proc_id << " : store_m " << index << endl; + + m_read = false; + m_value = value; + uint8_t * write_data = new uint8_t[4]; + memcpy(write_data, &value, 4); + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m(index), write_data, 4, 0, RubyRequestType_ST, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(m(index)); + request_data.data = write_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(m(index)), Address(m(index)), CacheRequestType_ST, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +// Save and Load context of a thread +void RaceyPseudoThread::saveCPUStates(string filename) { + ogzstream out(filename.c_str()); + out.write((char*)&m_looper, sizeof(int)); + out.write((char*)&m_num, sizeof(unsigned)); + out.write((char*)&m_index1, sizeof(unsigned)); + out.write((char*)&m_index2, sizeof(unsigned)); + out.write((char*)&m_stop, sizeof(unsigned)); + out.close(); +} + +void RaceyPseudoThread::loadCPUStates(string filename) { + igzstream out(filename.c_str()); + out.read((char*)&m_looper, sizeof(int)); + out.read((char*)&m_num, sizeof(unsigned)); + out.read((char*)&m_index1, sizeof(unsigned)); + out.read((char*)&m_index2, sizeof(unsigned)); + out.read((char*)&m_stop, sizeof(unsigned)); + out.close(); +} + +void RaceyPseudoThread::print(ostream& out) const { + out << "[Racey Pseudo Thread: " << m_proc_id << "]" << endl; +} + |