/* * Copyright (c) 1999 by Mark Hill and David Wood for the Wisconsin * Multifacet Project. ALL RIGHTS RESERVED. * * ##HEADER## * * This software is furnished under a license and may be used and * copied only in accordance with the terms of such license and the * inclusion of the above copyright notice. This software or any * other copies thereof or any derivative works may not be provided or * otherwise made available to any other persons. Title to and * ownership of the software is retained by Mark Hill and David Wood. * Any use of this software must include the above copyright notice. * * THIS SOFTWARE IS PROVIDED "AS IS". THE LICENSOR MAKES NO * WARRANTIES ABOUT ITS CORRECTNESS OR PERFORMANCE. * */ /* * $Id$ * */ #ifdef XACT_MEM #include "XactAbortRequestGenerator.hh" #include "LockStatus.hh" #include "Sequencer.hh" #include "System.hh" #include "RubyConfig.hh" #include "SubBlock.hh" #include "SyntheticDriver.hh" #include "Chip.hh" #include "Instruction.hh" #include "TransactionManager.hh" //uint8 XactAbortRequestGenerator::testArray[MAX_ADDRESS]; //uint8 XactAbortRequestGenerator::dataArray[MAX_ADDRESS]; Vector XactAbortRequestGenerator::testArray; XactAbortRequestGenerator::XactAbortRequestGenerator(NodeID node, SyntheticDriver& driver) : RequestGenerator(node, driver), m_driver(driver) { //DEBUG_EXPR(TESTER_COMP, MedPrio, "#### -- Creating XactAbortRequestGenerator\n"); cout << "#### -- Creating XactAbortRequestGenerator " << node << endl; testArray.setSize(g_MEMORY_SIZE_BYTES); assert(testArray.size() == g_MEMORY_SIZE_BYTES); // Create instructions m_instructions = new Instruction[XACT_LENGTH]; newTransaction(); m_xact_status = XactAbortRequestGeneratorStatus_Ready; m_last_transition = 0; m_node = node; //pickAddress(); m_counter = 0; m_register = 5; m_pc = 0; //for(int i=0; ischeduleEvent(this, 1+(random() % 200)); } void XactAbortRequestGenerator::newTransaction(){ int num_stores = 16; int num_loads = XACT_LENGTH - num_stores - 2; for(int i=0; igetTime(); execute(); } void XactAbortRequestGenerator::execute(){ assert(m_pc >= 0 && m_pc < XACT_LENGTH); Instruction current = m_instructions[m_pc]; //cout << " " << m_node << " executing pc: " << m_pc; switch (current.getOpcode()){ case Opcode_BEGIN: //cout << " -- begin."; initiateBeginTransaction(); break; case Opcode_LD: //cout << " -- load: " << current.getAddress(); initiateLoad(current.getAddress()); break; case Opcode_INC: //cout << " -- inc."; initiateInc(current.getAddress()); break; case Opcode_ST: //cout << " -- store: " << current.getAddress(); initiateStore(current.getAddress()); break; case Opcode_COMMIT: //cout << " -- commit."; initiateCommit(); break; default: WARN_EXPR(current.getOpcode()); ERROR_MSG("Invalid opcode"); }; //cout << endl; } void XactAbortRequestGenerator::performCallback(NodeID proc, SubBlock& data) { assert(m_xact_status == XactAbortRequestGeneratorStatus_Waiting || m_xact_status == XactAbortRequestGeneratorStatus_Aborted); assert(proc == m_node); Address address = data.getAddress(); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_xact_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); DEBUG_EXPR(TESTER_COMP, LowPrio, data); m_last_transition = g_eventQueue_ptr->getTime(); //cout << " " << m_node << " in performCallback, pc:" << m_pc // << ", addr:" << address << endl; if(m_xact_status == XactAbortRequestGeneratorStatus_Aborted){ cout << " " << m_node << " aborted, resetting pc." << endl; m_pc = 0; m_register = 5; m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, waitTime()); } else { m_xact_status = XactAbortRequestGeneratorStatus_Blocked; bool found; uint8 value; switch (m_instructions[m_pc].getOpcode()){ case Opcode_BEGIN: m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); m_register = 5; m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, waitTime()); m_pc++; break; case Opcode_LD: m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); m_register = data.getByte(0); //cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--LD: " << (int) m_register << endl; m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, waitTime()); m_pc++; break; //case Opcode_INC: // We shouldn't get a callback for this! //m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition); // break; case Opcode_ST: m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition); //data.setByte(address.getOffset(), m_register); data.setByte(0, m_register); //cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--ST: " << (int) m_register << endl; //dataArray[address.getAddress()] = m_register; found = sequencer()->setRubyMemoryValue(address, (char *) (&m_register), 1); assert(found); found = sequencer()->getRubyMemoryValue(address, (char *) (&value), 1); assert(found); assert(value == m_register); m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, thinkTime()); m_pc++; break; case Opcode_COMMIT: m_counter++; cout << " " << m_node << " callback--commit, counter is " << m_counter << " length is: " << g_tester_length << endl; // Check for correctness checkCorrectness(); m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition); if (m_counter < g_tester_length) { m_last_transition = g_eventQueue_ptr->getTime(); //pickAddress(); // Necessary? // Create new random transaction newTransaction(); m_pc = 0; m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, thinkTime()); } else { cout << "Ending" << endl; m_driver.reportDone(); m_xact_status = XactAbortRequestGeneratorStatus_Done; } break; default: ERROR_MSG("Invalid Opcode"); }; } } int XactAbortRequestGenerator::thinkTime() const { return g_think_time; } int XactAbortRequestGenerator::waitTime() const { return g_wait_time; } int XactAbortRequestGenerator::holdTime() const { return g_hold_time; } void XactAbortRequestGenerator::pickAddress() { //m_address = m_driver.pickAddress(m_node); } void XactAbortRequestGenerator::initiateBeginTransaction() { DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Begin Transaction"); cout << "### -- initiating Begin " << m_node << endl; m_xact_status = XactAbortRequestGeneratorStatus_Waiting; sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_BEGIN_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0)); transactionManager()->beginTransaction(); } void XactAbortRequestGenerator::initiateStore(Address addr) { //DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Store"); //cout << "### -- initiating Store " << m_node << endl; m_xact_status = XactAbortRequestGeneratorStatus_Waiting; ASSERT(transactionManager()->inTransaction(0)); sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_ST_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0)); } void XactAbortRequestGenerator::initiateCommit() { DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Commit "); cout << "### -- initiating Commit " << m_node << endl; m_xact_status = XactAbortRequestGeneratorStatus_Waiting; sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_COMMIT_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0)); transactionManager()->commitTransaction(); } void XactAbortRequestGenerator::initiateLoad(Address addr) { //DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Load "); //cout << "### -- initiating Load " << m_node << endl; m_xact_status = XactAbortRequestGeneratorStatus_Waiting; ASSERT(transactionManager()->inTransaction(0)); sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_LD_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0)); } void XactAbortRequestGenerator::initiateInc(Address addr) { //DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Load "); //cout << "### -- initiating Inc " << m_node << endl; m_register++; m_xact_status = XactAbortRequestGeneratorStatus_Ready; g_eventQueue_ptr->scheduleEvent(this, holdTime()); m_pc++; } void XactAbortRequestGenerator::checkCorrectness(){ // Execute the transaction on the test array int testPC = 0; bool done = false; for(int i=0; igetRubyMemoryValue(m_instructions[i].getAddress(), (char *) &ruby_value, 1); assert(found); if (ruby_value != testArray[i]){ success = false; WARN_MSG("DATA MISMATCH!"); WARN_EXPR((int) ruby_value); WARN_EXPR((int) testArray[i]); WARN_EXPR(i); assert(success); } break; case Opcode_COMMIT: done = true; break; default: ERROR_MSG("Invalid Opcode."); }; } cout << m_node << " CORRECT!" << endl; } Sequencer* XactAbortRequestGenerator::sequencer() const { return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); } TransactionManager* XactAbortRequestGenerator::transactionManager() const { return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getTransactionManager(m_node%RubyConfig::numberOfProcsPerChip()); } void XactAbortRequestGenerator::print(ostream& out) const { } void XactAbortRequestGenerator::abortTransaction(){ cout << " " << m_node << " *** ABORT! ***" << endl; //m_pc = 0; //m_register = 5; m_xact_status = XactAbortRequestGeneratorStatus_Aborted; } #endif //XACT_MEM