An HTML attachment was scrubbed...
URL: 
http://sos.ece.cmu.edu/pipermail/simflex/attachments/20051021/7fba5057/attachment.html
From twenisch at ece.cmu.edu  Fri Oct 21 17:02:01 2005
From: twenisch at ece.cmu.edu (Thomas Wenisch)
List-Post: [email protected]
Date: Fri Oct 21 17:01:35 2005
Subject: [Simflex] Re: File names trunked
In-Reply-To: <[email protected]>
References: <[email protected]>
Message-ID: <pine.lnx.4.53l-ece.cmu.edu.0510211656330.15...@dalmore.ece.cmu.edu>

Hi Lu,

Filenames on ISO images will be truncated if you do not burn the CD with
Joliet, Rock Ridge, or ISO 9660 Level 3 extensions.  For unix systems,
Rock Ridge is the usual file system extension used to represent long
filenames.  To enable Rock Ridge, use the -R and -J options with mkisofs.

For your CD burning software, you will have to look at the documentation.

As an alternative, if you can't get long file names to work, create a zip
or tar archive of your files on the CD, and then decompress the files in
the simulation.  When you decompress the archive, the long file names will
be restored.

Regards,
-Tom Wenisch
Computer Architecture Lab
Carnegie Mellon University

On Fri, 21 Oct 2005, lu peng wrote:

>
> HI Tom,
>
> How are you recently? I encountered a problem. I was trying to port SPECjbb 
> to simflex. I burned an ISO by using Winiso and loaded it on simics 2.0.28 
> sarek
> through file-cdrom. It has automatic mount function when a cdrom inserted. 
> After mounted, the long file names were all trunked to be a short file name. 
> E.g,
> jbbmain.class became jbbmai~1.cla. This made it can't be run. Could you have 
> any suggestions? Or what kind of tools are you using to burn the ISO files? 
> Any
> special instructions that I have to follow? One problem I doubt is that the 
> soaris using SCSI cdrom instead of IDE cdrom. I burned a lot of ISO files and 
> worked
> well with Linux targets.
>
> Thanks a lot,
>
> Lu
>
>
>
From twenisch at ece.cmu.edu  Fri Oct 21 18:34:07 2005
From: twenisch at ece.cmu.edu (Thomas Wenisch)
List-Post: [email protected]
Date: Fri Oct 21 18:33:50 2005
Subject: [simflex]re: x86-multithread on SimFlex error
In-Reply-To: <[email protected]>
References: <[email protected]>
Message-ID: <pine.lnx.4.53l-ece.cmu.edu.0510211824340.15...@dalmore.ece.cmu.edu>

Hi Shan,

I have attached new versions of SimicsTracer.hpp and TraceConsumer.hpp for
you to try.  They both go in the InorderSimicsFeeder component.

I still have not set up an x86 test workload to confirm that my fix
works.  If you still have trouble, let me know, and I will actually put
together a disk image for testing here.

Basically, I have completely separated the v9 and x86 code paths for
atomic operations, and removed all the sparc-specific hacks from the x86
code path.  The x86 code should not cause any assertions, and should be
able to deal with any random sequence of atomic memory operations that
Simics throws at it.  The only thing I am doing that is potentially wrong
is that I am assuming that all atomic operations are read-modify-writes.
I think this may not be strictly true for x86 (the lock prefix can be used
with certain load instructions), but it is a conservative approximation.
The CMPXCHG instructions is definately a read-modify-write.

Thanks for your (continued) efforts in helping me fix these bugs.

Regards,
-Tom Wenisch

On Thu, 20 Oct 2005, shan wrote:

> Hi, I used SIM_disassemble and the instruction is:
>
> CMPXCHG lock [ESI],ECX
>
> Do you need other information?
> Thanks
> shan
>
> -----Original Message-----
> From: Thomas Wenisch [mailto:[email protected]]
> Sent: Thursday, October 20, 2005 7:48 PM
> To: shan
> Subject: Re: [simflex]re: x86-multithread on SimFlex error
>
> Hi Shan,
>
> Can you try to determine the opcode that is causing the error?  This will
> be helpful, as then I can write a small assembly test case to try to fix
> the problem in SimicsTracer.
>
> I suggest you read through the function that is triggering the assertion.
> There is code elsewhere in the function that reads the opcode of an
> instruction, you can copy this code to the location of the assertion.  You
> can change the opcode back into human readable assembly with the
> SIM_disassemble function (documented in the simics reference manual, or
> you could grep the Flexus codebase to see how its used, I'm sure we use it
> somewhere).
>
> Regards,
> -Tom Wenisch
>
> On Thu, 20 Oct 2005, shan wrote:
>
> > Hi Thomas,
> >   Sorry, I guess there is something wrong with my department's mail
> server.
> > I am not sure if you have got my following e-mail.
> >   I tried your patch. The old problem disappeared but there are still
> > problem in thread_create function. Do you have some debug version code, so
> > that I can get more debugging information to tell you?
> >
> > Thanks
> > Shan
> >
> > -----Original Message-----
> > From: shan [mailto:[email protected]]
> > Sent: Tuesday, October 18, 2005 8:57 PM
> > To: 'Thomas Wenisch'
> > Cc: '[email protected]'
> > Subject: RE: x86-multithread on SimFlex error
> >
> > Hi Thomas,
> >   Thanks very much. I used your new file. The program runs longer but
> still
> > fails after a while. The screen output is like:
> > 46 <flexus.cpp:240> {3276800}- Timestamp: 2005-Oct-18 21:45:08
> > 47 <SimicsTracer.hpp:662> (<undefined>[<undefined>]) {3405134}- Assertion
> > failed: ((!(inst.isNOP()))) : <undefined>
> > ***  Simics getting shaky, switching to 'safe' mode.
> > ***  Simics (main thread) received an abort signal, probably an assertion.
> > <Simics is running in 'safe' mode>
> >
> >   The SimicsTracer.hpp:662 seems to be operating on some atomic
> instruction.
> > I am pretty sure it is inside the pthread_create system call ...
> >   Do you need some other information? Maybe I can dump out what is the
> 'bad'
> > instruction's PC ...
> >   By the way, as for the TLB problem, I think I understand what you said.
> > But if that is the problem, even if you add error checking, you still can
> > not get the physical address, yes? how do you solve the problem?
> > Thanks
> > Shan
> >
> > -----Original Message-----
> > From: Thomas Wenisch [mailto:[email protected]]
> > Sent: Tuesday, October 18, 2005 12:35 PM
> > To: shan
> > Cc: [email protected]
> > Subject: Re: x86-multithread on SimFlex error
> >
> > Hi Shan,
> >
> > On Tue, 18 Oct 2005, shan wrote:
> >
> > > Hi,
> > >   I am trying the x86 module of Flexus. It works perfectly with single
> > > thread application, but when I try some multithreaded program (just a
> very
> > > simple toy application with pthread_create and pthread_join). There is
> > some
> > > error. The error information is like:
> > >
> > > ....
> > > 31 <flexus.cpp:240> {1835008}- Timestamp: 2005-Oct-18 09:57:25
> > > [cpu0] <address not in TLB>
> > > simics> c
> > > [cpu0] <address not in TLB>
> > > simics>
> >
> > The address not in TLB exception is an exception that Simics raises
> > anytime some piece of code (i.e., Flexus) asks it to translate a logical
> > address to a physical address, but the translation is not available in the
> > TLB of the current CPU.  This situation is very unusual - it probably only
> > arises while the OS is manipulating TLB entries or is about to take a page
> > fault on an instruction reference or something similar.  However,
> > functions like pthread_create are more likely to create this situation.
> >
> > The fact that this is causing your simulation to stop is a bug in Flexus.
> > Flexus uses the SIM_logical_to_physical call to get the physical PC
> > of instructions in a few special cases.  This call can fail if the
> > translation for the PC is not available in the TLB (which implies the CPU
> > is about to take an ITLB fault).  However, I forgot to include an error
> > check after the calls to SIM_logical_to_physical, so the exception ends up
> > propagating back to the Simics frontend, and stops the simulation.
> >
> > The fix is to add an error check after the SIM_logical_to_physical calls
> > in components/InorderSimicsFeeder/SimicsTracer.hpp.  I have attached a
> > fixed version of the file to this email.  Note that I did not test it
> > (except to check that it compiles), as I do not have any x86 test images
> > handy.  We don't use x86 extensively here, which is why this bug has gone
> > unnoticed.
> >
> > Please let me know if you continue to have problems. If so, I will help
> > you add a bunch of debugging messages so we can confirm if the problem is
> > actually what I think it is.
> >
> > Regards,
> > -Tom Wenisch
> > Computer Architecture Lab
> > Carnegie Mellon University
> >
> > >
> > >   It happens after the program simulated a little while, maybe right at
> > the
> > > time when the thread is created.
> > >   I guess I miss some multi-thread related flag... what should I do to
> > > simulate a multithreaded application?
> > >   Oh, my toy application can run on simics without flexus module loaded.
> > > Thanks
> > > Shan
> > >
> > >
> >
> >
>
>
-------------- next part --------------
// DO-NOT-REMOVE begin-copyright-block
//
// Redistributions of any form whatsoever must retain and/or include the
// following acknowledgment, notices and disclaimer:
//
// This product includes software developed by Carnegie Mellon University.
//
// Copyright \(c\) 2005 by Brian Gold, Nikos Hardavellas, Jangwoo Kim,
// Jared Smolens, Stephen Somogyi, Tom Wenisch, Babak Falsafi and
// James C. Hoe for the SimFlex Project, Computer Architecture Lab
// at Carnegie Mellon, Carnegie Mellon University.
//
// For more information, see the SimFlex project website at:
//   http://www.ece.cmu.edu/~simflex
//
// You may not use the name Carnegie Mellon University or derivations
// thereof to endorse or promote products derived from this software.
//
// If you modify the software you must place a notice on or within any
// modified version provided or made available to any third party stating
// that you have modified the software.  The notice shall include at least
// your name, address, phone number, email address and the date and purpose
// of the modification.
//
// THE SOFTWARE IS PROVIDED AS-IS WITHOUT ANY WARRANTY OF ANY KIND, EITHER
// EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO ANY WARRANTY
// THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS OR BE ERROR-FREE AND ANY
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
// TITLE, OR NON-INFRINGEMENT.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
// BE LIABLE FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO DIRECT, INDIRECT,
// SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN
// ANY WAY CONNECTED WITH THIS SOFTWARE (WHETHER OR NOT BASED UPON WARRANTY,
// CONTRACT, TORT OR OTHERWISE).
//
// DO-NOT-REMOVE end-copyright-block
/*
  V9 Memory Op
*/




namespace nInorderSimicsFeeder {

std::set<Flexus::Simics::API::conf_object_t *> theTimingModels;

class SimicsTracerImpl  {
  private:
    conf_object_t * theUnderlyingObject;
    conf_object_t * theCPU;
    index_t theIndex;
    boost::shared_ptr<SimicsTraceConsumer> theConsumer;
    SimicsCycleManager * theCycleManager; //Non-owning pointer
    StoreBuffer theStoreBuffer;
    bool theInterruptsEnabled;
    bool theIgnoreFlag;
    conf_object_t * thePhysMemory;
    conf_object_t * thePhysIO;
    physical_address_t current_pc;

  public:
    //Default Constructor, creates a SimicsTracer that is not connected
    //to an underlying Simics object.
    SimicsTracerImpl(conf_object_t * anUnderlyingObject)
      : theUnderlyingObject(anUnderlyingObject)
      , theConsumer()
      , theInterruptsEnabled(true)
      , theIgnoreFlag(false)
    {}

    // Initialize the tracer to the desired CPU
    void init(conf_object_t * aCPU, index_t anIndex) {
        theCPU = aCPU;
        theIndex = anIndex;

        attr_value_t attr;

        theIndex = anIndex;


        if (SIM_class_has_attribute(theCPU->class_data, 
"turbo_execution_mode")) {
          DBG_Assert( false , ( << "Simics appears to be running with the -fast 
option.  You must launch Simics with -stall to run in-order simulations") );
        }

        attr = SIM_get_attribute(theCPU, "ooo_mode");
        if ( attr.kind != Sim_Val_String || std::string(attr.u.string) != 
"in-order" ) {
          DBG_Assert( false , ( << "Simics appears to be running with the -ma 
option.  You must launch Simics with -stall to run in-order simulations") );
        }

        attr.kind = Sim_Val_Object;
        attr.u.object = theCPU;

        SIM_set_attribute(theUnderlyingObject, "queue", &attr);


        attr.kind = Sim_Val_Object;
        attr.u.object = theUnderlyingObject;

        /* Tell memory we have a mem hier */
        thePhysMemory = SIM_get_attribute(theCPU, "physical_memory").u.object;
        SIM_set_attribute(thePhysMemory, "timing_model", &attr);
        if (theTimingModels.count(thePhysMemory) > 0) {
          DBG_Assert( false, ( << "Two CPUs connected to the same memory 
timing_model: " << thePhysMemory->name) );
        }
        theTimingModels.insert(thePhysMemory);


        #if FLEXUS_TARGET_IS(v9)
          //We only use the snoop interface for v9
          /* Tell memory we have a mem hier */
          SIM_set_attribute(thePhysMemory, "snoop_device", &attr);


          /* Tell memory we have a mem hier */
          thePhysIO = SIM_get_attribute(theCPU, "physical_io").u.object;
          SIM_set_attribute(thePhysIO, "timing_model", &attr);
        #endif //FLEXUS_TARGET_IS(v9)


        if (theTimingModels.count(thePhysIO) > 0) {
          DBG_Assert( false, ( << "Two CPUs connected to the same I/O 
timing_model: " << thePhysIO->name) );
        }
        theTimingModels.insert(thePhysIO);

        current_pc = 0;

    }

    void setTraceConsumer(boost::shared_ptr<SimicsTraceConsumer> aConsumer) {
        theConsumer = aConsumer;
        theConsumer->init(theIndex);
    }

    void setCycleManager(SimicsCycleManager & aManager) {
        theCycleManager = &aManager;
    }


    void setIgnore() {
      DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << "set ignore" ) );
      theIgnoreFlag = true;
    }

    void clearIgnore() {
      DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << "clear ignore" ) );
      theIgnoreFlag = false;
    }

    bool ignore() const {
      return theIgnoreFlag;
    }

    void enableInterrupts() {
      if (! theInterruptsEnabled) {
        theInterruptsEnabled = true;
        attr_value_t attr;
        attr.kind = Sim_Val_Integer;
        #if FLEXUS_TARGET_IS(v9)
          attr.u.integer = 1;
          SIM_set_attribute(theCPU, "extra_irq_enable", &attr);
        #elif FLEXUS_TARGET_IS(x86)
          attr.u.integer = 0;
          SIM_set_attribute(theCPU, "temporary_interrupt_mask", &attr);
        #endif //FLEXUS_TARGET_IS(v9)
      }
    }

    void disableInterrupts() {
      if (theInterruptsEnabled) {
        theInterruptsEnabled = false;
        attr_value_t attr;
        attr.kind = Sim_Val_Integer;
        #if FLEXUS_TARGET_IS(v9)
          attr.u.integer = 0;
          SIM_set_attribute(theCPU, "extra_irq_enable", &attr);
        #elif FLEXUS_TARGET_IS(x86)
          attr.u.integer = 1;
          SIM_set_attribute(theCPU, "temporary_interrupt_mask", &attr);
        #endif //FLEXUS_TARGET_IS(v9)
      }
    }

    bool interruptsEnabled() const {
      return theInterruptsEnabled;
    }


    DoubleWord readStoreBuffer(PhysicalMemoryAddress const & anAlignedAddress) {
      StoreBuffer::iterator iter = theStoreBuffer.find(anAlignedAddress);
      if (iter != theStoreBuffer.end()) {
        //DBG_(Tmp, ( << "Store buffer access hit for address: " << &std::hex 
<< anAlignedAddress << &std::dec << " returning value: " << 
iter->second.theNewValue ));
        return iter->second.theNewValue;
      }
      return DoubleWord();
    }

    //Returns the current contents of the store buffer for a memory location
    DoubleWord getMemoryValue(PhysicalMemoryAddress & anAlignedAddress) {
      unsigned long long memory( Simics::API::SIM_read_phys_memory(theCPU, 
anAlignedAddress, 8) );
      DoubleWord store_buffer( readStoreBuffer(anAlignedAddress) );
      DoubleWord ret_val(memory, store_buffer);
      DBG_(VVerb, ( << "Applying SB: " << store_buffer << " to " << & std::hex 
<< memory << & std::dec << " results in " << ret_val << &std::dec  ));
      return ret_val;
    }


    cycles_t trace_mem_hier_operate(conf_object_t *space, map_list_t *map, 
generic_transaction_t *aMemTrans) {
      memory_transaction_t * mem_trans = reinterpret_cast<memory_transaction_t 
*>(aMemTrans);
      #ifdef FLEXUS_FEEDER_TRACE_DEBUGGER
        theConsumer->debugger.nextCallback(mem_trans);
      #endif //FLEXUS_FEEDER_TRACE_DEBUGGER

      int stall = real_hier_operate(space, map, mem_trans);

      #ifdef FLEXUS_FEEDER_TRACE_DEBUGGER
        theConsumer->debugger.ret(stall);

        // verify we aren't trying to stall when it is not permitted
        if( (!mem_trans->s.may_stall) && (stall > 0) ) {
          DBG_(Crit, SetNumeric( (FlexusIdx) theIndex )
                   ( << "stalling " << stall << " cycles when not permitted" ) 
);
          theConsumer->debugger.dump();
        }
      #endif //FLEXUS_FEEDER_TRACE_DEBUGGER

      return stall;
    }


    //Useful debugging stuff for tracing every instruction
    void debugTransaction(memory_transaction_t *mem_trans) {
        logical_address_t pc_logical = SIM_get_program_counter(theCPU);
        physical_address_t pc = SIM_logical_to_physical(theCPU, 
Sim_DI_Instruction, pc_logical);
        if (SIM_clear_exception() != SimExc_No_Exception) {
          DBG_(Tmp, SetNumeric( (FlexusIdx) theIndex)
                  ( << "Instruction results in ITLB Miss pc_logical: " << 
pc_logical)
            );
           return;
        }
        tuple_int_string_t * retval = SIM_disassemble(theCPU, pc , 0);
        (void)retval; //suppress unused variable warning

        DBG_(Tmp, SetNumeric( (FlexusIdx) theIndex)
                  ( << "Mem Heir Instr: " << retval->string << " pc: " << pc)
            );

      if (SIM_mem_op_is_data(&mem_trans->s)) {
        if (SIM_mem_op_is_write(&mem_trans->s)) {
          DBG_(Tmp, SetNumeric( (FlexusIdx) theIndex)
                    ( << "  Write @" << &std::hex << 
mem_trans->s.physical_address << &std::dec << '[' << mem_trans->s.size << ']'
                      << " type=" << mem_trans->s.type
                      << (  mem_trans->s.atomic ? " atomic" : "" )
                      << (  mem_trans->s.may_stall ? "" : " no-stall" )
                      << (  mem_trans->s.inquiry ? " inquiry" : "")
                      << (  mem_trans->s.speculative ? " speculative" : "")
                      << (  mem_trans->s.ignore ? " ignore" : "")
                    )
            );
        } else {
          if ( mem_trans->s.type == Simics::API::Sim_Trans_Prefetch) {
              DBG_(Tmp, SetNumeric( (FlexusIdx) theIndex)
                        ( << "  Prefetch @" << &std::hex << 
mem_trans->s.physical_address << &std::dec << '[' << mem_trans->s.size  << ']'
                          << " type=" << mem_trans->s.type
                          << (  mem_trans->s.atomic ? " atomic" : "" )
                          << (  mem_trans->s.may_stall ? "" : " no-stall" )
                          << (  mem_trans->s.inquiry ? " inquiry" : "")
                          << (  mem_trans->s.speculative ? " speculative" : "")
                          << (  mem_trans->s.ignore ? " ignore" : "")
                        )
                );
          } else {
              DBG_(Tmp, SetNumeric( (FlexusIdx) theIndex)
                        ( << "  Read @" << &std::hex << 
mem_trans->s.physical_address << &std::dec << '[' << mem_trans->s.size  << ']'
                          << " type=" << mem_trans->s.type
                          << (  mem_trans->s.atomic ? " atomic" : "" )
                          << (  mem_trans->s.may_stall ? "" : " no-stall" )
                          << (  mem_trans->s.inquiry ? " inquiry" : "")
                          << (  mem_trans->s.speculative ? " speculative" : "")
                          << (  mem_trans->s.ignore ? " ignore" : "")
                        )
                );
          }
        }
      }
    }

    bool requiresSync(memory_transaction_t *mem_trans) {
      if ( mem_trans->s.size > 8) {
        //Anything larger than 8 bytes must sync
        return true;
      }

      #if FLEXUS_TARGET_IS(v9)
        //If we are using a stange ASI, mark this as a sync
        switch ( mem_trans->address_space ) {
          //Privileged
            case 0x04: //NUCLEUS
            case 0x0C: //NUCLEUS_LITTLE
            case 0x10: //AS_IF_USER_PRIMARY
            case 0x11: //AS_IF_USER_SECONDARY
            case 0x18: //AS_IF_USER_PRIMARY_LITTLE
            case 0x19: //AS_IF_USER_SECONDARY_LITTLE
            case 0x24: //NUCLEUS_QUAD_LDD
            case 0x2C: //NUCLEUS_QUAD_LDD_LITTLE
            //User
            case 0x81: //SECONDARY
            case 0x88: //PRIMARY_LITTLE
            case 0x89: //SECONDARY_LITTLE
            case 0x80: //PRIMARY
              break;
          default:
            //Any other ASI requires a Sync
            DBG_(Iface, SetNumeric( (FlexusIdx) theIndex)
                 (    << "Alternate ASI " << mem_trans->address_space <<" @" << 
&std::hex
                      << mem_trans->s.physical_address
                      << '[' << &std::dec << mem_trans->s.size << ']'
                 )
            );

            return true;
        }

        //Non-cacheable operations require a sync
        if ( (! mem_trans->cache_virtual) || ( ! mem_trans->cache_physical) ) {
          DBG_(Iface, SetNumeric( (FlexusIdx) theIndex)
               (    << "Non-cacheable @" << &std::hex
                    << mem_trans->s.physical_address
                    << '[' << &std::dec << mem_trans->s.size << ']'
               )
          );
          return true;
        }
      #endif //FLEXUS_TARGET_IS(v9)

      return false;
    }

    cycles_t real_hier_operate(conf_object_t *space, map_list_t *map, 
memory_transaction_t *mem_trans) {
    //NOTE: Multiple return paths
      const int k_no_stall = 0;
      const int k_call_me_next_cycle = 1;



      //debugTransaction(mem_trans);

      //Ensure that we see future accesses to this block
      mem_trans->s.block_STC = 1;

      //Case 0: This is an IO access
      //============================

        //All IO accesses must stall until SB is empty
        if (space == thePhysIO) {
          if ( ! theStoreBuffer.empty() ) {
            DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  Got an IO 
access while the Store buffer contains data.  Must stall access till the store 
buffer flushes." ) );

            // JWK:
            // Previous IO (store) instruction should be marked as IO 
instruction here...
            // Execute doesn't release it until SB becomes empty
            // This instruction must be the last one in theEntries....
            theConsumer->theEntries.back().theReadyInstruction->setIO();

            theCycleManager->advanceFlexus();
            cycles_t stall_cycles = 
theCycleManager->reconcileTime(theConsumer->queueSize());

            if (stall_cycles == 0) {
              disableInterrupts();
              return k_call_me_next_cycle;
            } else {
              disableInterrupts();
              return stall_cycles;
            }
          } else {
            DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  Got an IO 
access but store buffer is empty.  Access may proceed." ) );
            //Otherwise, we allow the access to complete.
            return k_no_stall;
          }

        }


      //Case 1: Previously pending operation has completed since last call
      //==================================================================
          //See if perviously pending instructions have been completed
          if(theConsumer->isComplete()) {
            // We have completed the instruction that was previously stalled 
since
            // the last time we were called by Simics

            DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 1: 
completed operation" ) );

            if ( mem_trans->s.type == Sim_Trans_Instr_Fetch ) {
                DBG_Assert( current_pc == mem_trans->s.physical_address ) ;
                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Ignoring 
re-issue of fetch operation." ) );
                return 0;
            }

            // Indicate that Simics is aware the instruction is complete
            theConsumer->simicsDone();

            //If we have placed this store instruction in the store buffer, then
            //we should prevent simics from performing the store operation now
            if (ignore()) {
              //Clear the ignore flag
              clearIgnore();

              //DBG_Assert( ( mem_trans->s.type == Sim_Trans_Store ) /*|| ( 
mem_trans->s.type == Sim_Trans_Load )*/);

              if ( ( mem_trans->s.type == Sim_Trans_Store ) ) {

                //Tell Simics not to perform this store operation
                mem_trans->s.ignore = 1;
                DBG_( VVerb, ( << "Ignoring this operation" ) );
              } else {
                DBG_( Crit, SetNumeric( (FlexusIdx) theIndex ) ( << "Expected 
to ignore a store completion, but got something that isn't a store.  
Transaction follows: " ) );
                debugTransaction(mem_trans);
              }
            }

            //We are completing the current instruction, so interrupts are ok
            enableInterrupts();

            // return zero cycle latency
            return k_no_stall;
          }


      //All the code below needs to distinguish fetches from data operations
        bool is_fetch = ( mem_trans->s.type == Sim_Trans_Instr_Fetch);
        bool is_data = ( mem_trans->s.type == Sim_Trans_Load ) || ( 
mem_trans->s.type == Sim_Trans_Store ) || ( mem_trans->s.type == 
Sim_Trans_Prefetch);

      //Case 2: We have a pending data operation that has not been completed
      //====================================================================
      // See if we have a pending operation.
        if (! theConsumer->isIdle()) {
          //There is some operation pending for this cpu, and it has not yet
          //been completed by flexus.

          DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 2: 
incomplete pending op" ) );

          //First, some assertions to make sure Simics has given us back the
          //same transaction as we were stalled on previously.

          if ( is_fetch ) {
            DBG_Assert( current_pc == 0 || current_pc == 
mem_trans->s.physical_address, ( << "CPU" << theIndex << " current_pc=" << 
current_pc << " mem_trans->s.physical_address=" << 
mem_trans->s.physical_address)) ;
            DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Ignoring 
re-issue of instruction fetch" ) );
            return 0;
          }
          else if ( is_data ) {
            //Ensure that this data operation is going t
            if( PhysicalMemoryAddress(mem_trans->s.physical_address) !=
                theConsumer->optimizedGetInstruction().physicalMemoryAddress() 
) {
              DBG_( Crit, SetNumeric( (FlexusIdx) theIndex )
                          ( << "data addresses don't match for reissued Simics 
request. Expected Instr: "
                            << theConsumer->optimizedGetInstruction()
                            << " Received: "
                            << mem_trans->s.physical_address
                          ) );
              #ifdef FLEXUS_FEEDER_TRACE_DEBUGGER
                theConsumer->debugger.dump();
              #endif //FLEXUS_FEEDER_TRACE_DEBUGGER
            }
          }
          else {
            DBG_(Crit, SetNumeric( (FlexusIdx) theIndex )
                       ( << "while pending, got a new transaction that is 
neither inst nor data" ) );
          }

          //Interrupts should be disabled
          DBG_Assert( ! interruptsEnabled() ) ;

          #ifndef FLEXUS_FEEDER_OLD_SCHEDULING

            // Try to advance Flexus
            theCycleManager->advanceFlexus();
            cycles_t stall_cycles = 
theCycleManager->reconcileTime(theConsumer->queueSize());

            if (stall_cycles > 0) {
              //All pending operations have not yet completed.
              //Interrupts remain disabled.  We will be called again.
              return stall_cycles;
            } else {
              //We can not advance flexus further.  This is either because
              //this cpu has completed all its pending operations, or because
              //some other cpu has run out of instructions.

              if(theConsumer->isComplete()) {
                //This cpu has completed all its operations.

                //Check if we should prevent Simics from executing the
                //operation
                if (ignore()) {
                  //We should.  This should only be the case for store
                  //instructions
                  DBG_Assert( ( mem_trans->s.type == Sim_Trans_Store )    );

                  //Inform Simics to ignore the store
                  mem_trans->s.ignore = 1;

                  //Clear the store pending flag
                  clearIgnore();
                  DBG_( VVerb, ( << "Ignoring this store" ) );
                }

                //Indicate to the consumer that we have notified simics that
                //the instruction is complete
                theConsumer->simicsDone();

                enableInterrupts();
                return k_no_stall;
              } else {
                //Some cpu has run out of instructions, but this cpu is still
                //pending. Interrupts remain disabled.  We will be called again.
                return k_call_me_next_cycle;  //Call back next cycle
              }
            }

          #else //FLEXUS_FEEDER_OLD_SCHEDULING
            return k_call_me_next_cycle;  //Call back next cycle
          #endif //FLEXUS_FEEDER_OLD_SCHEDULING

        }

      //Case 3: We have a new instruction fetch
      //=======================================
        if ( is_fetch ) {
          DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 3: new 
instruction fetch" ) );

          if (theFlexus->quiescing() ) {
            //We halt new instruction fetches when we are trying to quiesce 
Flexus
            return k_call_me_next_cycle;
          }

          // Instruction fetches should never be atomic memory operations
          DBG_Assert(!mem_trans->s.atomic,SetNumeric( (FlexusIdx) theIndex) );

          //If we have many instructions queued, we will advance Flexus
          //to drain the queue.  This may result in stall cycles.  However,
          //by default, we return without stall

          cycles_t ret = k_no_stall;

          #ifndef FLEXUS_FEEDER_OLD_SCHEDULING
            if(theConsumer->largeQueue()) {
              //theConsumer has many instructions queued.  We advance.

              DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "advancing 
large queue" ) );
              theCycleManager->advanceFlexus();

              //We give reconcileTime the number of pending instructions plus
              //1 for the instruction we have not yet queued.
              ret = theCycleManager->reconcileTime(theConsumer->queueSize() + 
1); //Take the instruction that we have not yet queued into account

            }
          #endif

          // create a new instruction object
          intrusive_ptr<ArchitecturalInstruction> new_inst( new 
ArchitecturalInstruction(theConsumer.get()) ) ;

          // set the PC
          new_inst->setVirtInstAddress( 
VirtualMemoryAddress(mem_trans->s.logical_address) );
          new_inst->setPhysInstAddress( 
PhysicalMemoryAddress(mem_trans->s.physical_address) );

          current_pc = mem_trans->s.physical_address;

          #if FLEXUS_TARGET_IS(v9)
            //See if the instruction is a MEMBAR
            unsigned long op_code = SIM_read_phys_memory(theCPU, 
mem_trans->s.physical_address, 4);
            new_inst->setOpcode(op_code);


            //MEMBAR  is 1000 0001 0100 0011 11-- ---- ---- ----
            const unsigned long kMEMBAR_mask = 0xFFFFC000;
            const unsigned long kMEMBAR_pattern = 0x8143C000;
            if ((op_code & kMEMBAR_mask) == kMEMBAR_pattern) {
              //It is a MEMBAR. Figure out which MEMBAR it is.  We care about:
                //MEMBAR #sync            8143E0040
                //MEMBAR #memissue        8143E0020
                //MEMBAR #lookaside       8143E0010
                //MEMBAR #storeload       8143E0002
              const unsigned long kMEMBAR_SYNC_mask = 0x72;

              if ( (op_code & kMEMBAR_SYNC_mask) != 0) {
                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  
Instruction is a syncing MEMBAR" ) );
                new_inst->setIsMEMBAR();
              }

            }
          #else
            //Reading op-codes not supported on x86
            new_inst->setOpcode(0);
          #endif //FLEXUS_TARGET_IS(v9)

          //Pass the newly created instruction to the consumer
          theConsumer->consumeInstOperation(new_inst);

          //If we did not stall while advancing, or did not adance
          if (ret == 0) {
            enableInterrupts();
          } else {
            disableInterrupts();
          }
          return ret;

        }

      //Case 4: We have a data operation to attach to the previously fetched 
instruction
      
//================================================================================
        if ( is_data ) {
          DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 4: Data 
operation" ) );


          bool is_write = ( mem_trans->s.type == Sim_Trans_Store );
          bool is_atomic = mem_trans->s.atomic;

          //Obtain the physical PC of this operation so we can verify
          //that it matches the first half of the atomic operation
          logical_address_t pc_logical = SIM_get_program_counter(theCPU);
          physical_address_t pc = SIM_logical_to_physical(theCPU, 
Sim_DI_Instruction, pc_logical);
          if (SIM_clear_exception() != SimExc_No_Exception) {
            pc = 0;
          }

          //Case 4.1: Atomic memory operation
          //=================================

            // for atomic operations, if this is the first half (the read), just
            // append the data reference onto the most recent instruction; if 
this
            // is the second half, verify that it matches with the first half
            if( is_atomic ) {

              DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 4.1: 
Atomic operation" ) );


              #if FLEXUS_TARGET_IS(v9)
                //v9 implementation - handles special cases where simics
                //issues the pieces of RMWs separately


                //See if this is the first or second half of the operation.  It
                //is the second half if theConsumer's queue is empty, since this
                //means we just got a second back-to-back data operation, which
                //only occurs in the case of the second mem ops
                if(theConsumer->theEntries.empty() && 
theConsumer->isAtomicOperationPending()) {
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  second 
half of atomic operation" ) );

                  //Verify that the second half of the atomic operation matches
                  //the first half that we just completed
                  theConsumer->verifyAtomicOperation(is_write, 
PhysicalMemoryAddress(pc), PhysicalMemoryAddress(mem_trans->s.physical_address 
) );

                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex )
                             ( << "  verified atomic operation" ) );

                  enableInterrupts();
                  return k_no_stall;
                } else {
                  //First half of an atomic operation
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  first 
half of atomic operation" ) );

                  //Better not be a write
                  DBG_Assert(!is_write);

                  // Obtain a reference to the previous fetch so we can add the 
data
                  // operation to it.
                  ArchitecturalInstruction & inst = 
theConsumer->optimizedGetInstruction();

                  //Ensure that we are not overwriting another instruction
                  DBG_Assert(inst.isNOP());

                  //Fill in the physical address for this memory operation
                  inst.setAddress( 
PhysicalMemoryAddress(mem_trans->s.physical_address) );

                  // record the opcode
                  unsigned long op_code = SIM_read_phys_memory(theCPU, pc, 4);
                  inst.setOpcode(op_code);

                  //LDD(a)            is 11-- ---0 -001 1--- ---- ---- ---- ----
                  //STD(a)            is 11-- ---0 -011 1--- ---- ---- ---- ----

                  //LDSTUB(a)/SWAP(a) is 11-- ---0 -11- 1--- ---- ---- ---- ----
                  //CAS(x)A           is 11-- ---1 111- 0--- ---- ---- ---- ----

                  const unsigned long kLDD_mask = 0xC1780000;
                  const unsigned long kLDD_pattern = 0xC0180000;

                  const unsigned long kSTD_mask = 0xC1780000;
                  const unsigned long kSTD_pattern = 0xC038000;

                  const unsigned long kRMW_mask = 0xC1680000;
                  const unsigned long kRMW_pattern = 0xC0680000;

                  const unsigned long kCAS_mask = 0xC1E80000;
                  const unsigned long kCAS_pattern = 0xC1E00000;

                  if ((op_code & kLDD_mask) == kLDD_pattern) {
                    inst.setIsLoad();
                  } else if ((op_code & kSTD_mask) == kSTD_pattern) {
                    inst.setIsStore();
                    inst.setSync();
                  } else if (((op_code & kRMW_mask) == kRMW_pattern) || 
((op_code & kCAS_mask) == kCAS_pattern))  {
                    inst.setIsRmw();
                  } else {
                    DBG_Assert( false, ( << "Unknown atomic operation. Opcode: 
" << std::hex << op_code << " pc: " << pc << std::dec ) );
                  }

                  theConsumer->recordAtomicVerification( 
PhysicalMemoryAddress(pc), PhysicalMemoryAddress(mem_trans->s.physical_address 
));

                  //Remember the size of the rmw
                  inst.setSize(mem_trans->s.size);

                  if (mem_trans->priv) {
                    //Mark privileged operations
                    inst.setPriv();
                  }


                  // add this data instruction to the consumer
                  theConsumer->consumeDataOperation();

                }
              #else //Not v9

                //See if this is a second (or subsequent) part of an atomic
                //memory access that we have already passed to the consumer
                //(as an RMW instruction).  If the last thing we passed the
                //consumer was an atomic memory transaction with the same PC
                //and data address, we assume that this new transaction is the
                //same instruction as the previous one.  However, if there
                //is a mismatch between data and PC, we issue it to flexus as
                //a separate RMW.  This ensures that we get the right memory
                //accesses in Flexus.

                if (  theConsumer->isAtomicOperationPending()
                   && theConsumer->getAtomicPC() == PhysicalMemoryAddress(pc)
                   && theConsumer->getAtomicData() == 
PhysicalMemoryAddress(mem_trans->s.physical_address )
                   ) {
                   //This memory transaction completes an atomic operation that
                   //has already been sent to the consumer.  No need to send
                   //another operation through.

                  theConsumer->clearAtomicPending();
                  enableInterrupts();
                  return k_no_stall;

                } else {
                  //This does not match an atomic operation we just issued.
                  //Issue it as a new atomic operation

                  //Construct a new instruction object, if neccessary
                  if ( theConsumer->isEmpty() ) {
                      // create a new instruction object
                      intrusive_ptr<ArchitecturalInstruction> new_inst( new 
ArchitecturalInstruction( theConsumer.get() ) ) ;
                      // set the PC
                      new_inst->setPhysInstAddress( PhysicalMemoryAddress( pc ) 
);
                      //Pass the newly created instruction to the consumer
                      theConsumer->consumeInstOperation(new_inst);
                  }

                  // Obtain a reference to the previous fetch so we can add the 
data
                  // operation to it.
                  ArchitecturalInstruction & inst = 
theConsumer->optimizedGetInstruction();

                  //Fill in the physical address for this memory operation
                  inst.setAddress( 
PhysicalMemoryAddress(mem_trans->s.physical_address) );

                  //Assume all atomic x86 operations are RMWs.  This may not
                  //be true
                  inst.setIsRmw();

                  //Remember the size of the load or store
                  inst.setSize(mem_trans->s.size);

                  if (mem_trans->mode == Sim_CPU_Mode_Supervisor) {
                    //Mark privileged operations
                    inst.setPriv();
                  }

                  // add this data instruction to the consumer
                  theConsumer->consumeDataOperation();

                }



              #endif //FLEXUS_TARGET_IS(v9)


          //Case 4.2: Load or store operation
          //=================================
            } else {

              DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 4.2: 
Load or Store operation" ) );

              if ( theConsumer->isEmpty() ) {

                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 4.2a: 
non-stallable LDD or STD" ) );

                //Non-stallable LDD and STD instructions are the only cases 
where
                //we can have a memory operation while theConsumer is empty

                //We simulate a fetch operation here.
                //Need to get a PC.
                logical_address_t pc_logical = SIM_get_program_counter(theCPU);
                physical_address_t pc = SIM_logical_to_physical(theCPU, 
Sim_DI_Instruction, pc_logical);
                if (SIM_clear_exception() != SimExc_No_Exception) {
                  pc = 0;
                }

                // create a new instruction object
                intrusive_ptr<ArchitecturalInstruction> new_inst( new 
ArchitecturalInstruction( theConsumer.get() ) ) ;

                // set the PC
                new_inst->setPhysInstAddress( PhysicalMemoryAddress( pc ) );

                //Pass the newly created instruction to the consumer
                theConsumer->consumeInstOperation(new_inst);

              }


              // Obtain a reference to the previous fetch so we can add the data
              // operation to it.
              ArchitecturalInstruction & inst = 
theConsumer->optimizedGetInstruction();

              //Fill in the physical address for this memory operation
              inst.setAddress( 
PhysicalMemoryAddress(mem_trans->s.physical_address) );

              if (is_write) {
                //Indicate that its a store
                inst.setIsStore();
              } else {
                inst.setIsLoad();
              }

              //See if it meets any of the conditions which require a sync
              if ( requiresSync(mem_trans) ) {
                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  store 
requires sync" ) );
                inst.setSync();
              }

              //See if this is a store operation which may use the store buffer
              if (is_write && !inst.isSync() && FLEXUS_TARGET_IS(v9) ) {

                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "Case 4.2b: 
Store which uses Store Buffer" ) );

                //This store does not require a Sync, so it may use the store
                //buffer

                //Obtain the double-word-aligned address
                PhysicalMemoryAddress 
aligned_addr(mem_trans->s.physical_address & ~7LL);

                //Construct the new word-aligned value
                DoubleWord new_value;
                new_value.set( SIM_get_mem_op_value_cpu(&mem_trans->s), 
mem_trans->s.size, (mem_trans->s.physical_address & 7));

                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) 
Addr(mem_trans->s.physical_address) ( << "  SB-entry Store @" << &std::hex << 
mem_trans->s.physical_address << '[' << &std::dec << mem_trans->s.size << "] 
aligned: " << &std::hex << aligned_addr << &std::dec << " new value: " << 
new_value) );

                //Prevent mem op from modifying memory
                  setIgnore();
                //enter the memory op into the store buffer.
                std::pair<StoreBuffer::iterator, bool> entry =
                    theStoreBuffer.insert
                      (  std::make_pair
                            ( aligned_addr
                            , StoreBufferEntry( new_value )
                            )
                      );

                //Already had an entry, coalescing
                if (! entry.second) {
                  //Increment the outstanding store count
                  ++( entry.first->second);

                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex ) ( << "  
coalescing with existing entry" ) );

                  //Change the new value
                  entry.first->second.theNewValue.set( 
SIM_get_mem_op_value_cpu(&mem_trans->s), mem_trans->s.size, 
(mem_trans->s.physical_address & 7) ) ;
                }

                //Attach the store buffer to the instruction
                inst.setStoreBuffer(&theStoreBuffer);

                //Remember the data and size of the store, so we can perform
                //it later
                inst.setData(new_value);
              }

              //Remember the size of the load or store
              inst.setSize(mem_trans->s.size);

              #if FLEXUS_TARGET_IS(v9)
                if (mem_trans->priv) {
                  //Mark privileged operations
                  inst.setPriv();
                }
              #elif FLEXUS_TARGET_IS(x86)
                if (mem_trans->mode == Sim_CPU_Mode_Supervisor) {
                  //Mark privileged operations
                  inst.setPriv();
                }
              #endif //FLEXUS_TARGET_IS(v9)

              // add this data instruction to the consumer
              theConsumer->consumeDataOperation();
            }

          //Advance Flexus for sub-cases of Case 4
          //========================================

            if ( ! mem_trans->s.may_stall ) {
              //We complete the STD / LDD without advancing flexus

              //See if the store operation should be supressed
              if (ignore()) {

                mem_trans->s.ignore = 1;
                clearIgnore();
                DBG_( VVerb, ( << "  ignoring this op" ) );
              }

              theConsumer->simicsDone();

              enableInterrupts();
              // return zero cycle latency
              return k_no_stall;
            } else {

              #ifndef FLEXUS_FEEDER_OLD_SCHEDULING
                //Advance flexus and determine if we must stall
                theCycleManager->advanceFlexus();
                DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex )
                           ( << "  Advancing flexus" ) );
                cycles_t stall_cycles = 
theCycleManager->reconcileTime(theConsumer->queueSize());

                if (stall_cycles > 0) {
                  //We must stall, so we will have an operation pending.  
Disable
                  //interrupts so Simics doesn't change the operation on us
                  disableInterrupts();
                  return stall_cycles;
                } else {
                  //No need to stall
                  if(theConsumer->isComplete()) {
                    //We finished the pending operation

                    //See if the store operation should be supressed
                    if (ignore()) {
                      mem_trans->s.ignore = 1;
                      DBG_Assert( ( mem_trans->s.type == Sim_Trans_Store )    );
                      clearIgnore();
                      DBG_( VVerb, ( << "  ignoring this op" ) );
                    }

                    //Indicate that we are done
                    theConsumer->simicsDone();

                    //Allow interrupts again.
                    enableInterrupts();
                    return k_no_stall;
                  } else {
                    //We must stall, so we will have an operation pending.  
Disable
                    //interrupts so Simics doesn't change the operation on us
                    disableInterrupts();
                    return k_call_me_next_cycle;  //Call back next cycle
                  }
                }
              #else //defined(FLEXUS_FEEDER_OLD_SCHEDULING)
                disableInterrupts();
                return k_call_me_next_cycle;  //Call back next cycle
              #endif //FLEXUS_FEEDER_OLD_SCHEDULING
            }
        }
      //Case 5: We have something that is neither instruction, nor data. We 
simply
      //complete these without taking any action in flexus
      
//================================================================================
          //Neither instruction nor data access.  We will ignore this.
          /* shouldn't happen? */
          DBG_(Crit, SetNumeric( (FlexusIdx) theIndex) ( << "Case 5: Neither 
instruction nor data" ) );

          clearIgnore();
          enableInterrupts();

          return k_no_stall;
    }


    cycles_t trace_snoop_operate(conf_object_t *space, map_list_t *map, 
generic_transaction_t *aMemTrans) {

      memory_transaction_t * mem_trans = reinterpret_cast<memory_transaction_t 
*>(aMemTrans);

      if (Simics::API::SIM_mem_op_is_data(&mem_trans->s) && (mem_trans->s.size 
<= 8) ) {
        //We do not snoop PREFETCH and block load/store operations

        //Obtain the word-aligned address
        PhysicalMemoryAddress aligned_addr(mem_trans->s.physical_address & 
~7LL);

        DBG_(VVerb, Condition(Simics::API::SIM_mem_op_is_write(&mem_trans->s))
                   SetNumeric( (FlexusIdx) theIndex)
                   (  << "Snoop interface Write @"
                      << &std::hex  << mem_trans->s.physical_address
                      << " aligned: " << aligned_addr << &std::dec
                   )
            );

        PhysicalMemoryAddress interesting_region(mem_trans->s.physical_address 
& ~0xFFLL);

        //If this transaction is a store, assert that we have a store buffer 
enty
        //for it
        if (! Simics::API::SIM_mem_op_is_write(&mem_trans->s)) {
          //Assert that Simics got what we think is the new value

          DoubleWord value_according_to_sb(getMemoryValue(aligned_addr));
          DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << "    Value 
including SB contents: " << value_according_to_sb ) );

          //The correct value is in the store buffer
          switch( mem_trans->s.size) {
            case 1:
              {
                  unsigned char our_value = 
value_according_to_sb.getByte(mem_trans->s.physical_address & 7);
                  SIM_set_mem_op_value_cpu(&mem_trans->s, our_value);
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << " snoop 
value: " << &std::hex << (unsigned int)our_value) );
              }
              break;
            case 2:
              {
                  unsigned short our_value = 
value_according_to_sb.getHalfWord(mem_trans->s.physical_address & 7);
                  SIM_set_mem_op_value_cpu(&mem_trans->s, our_value);
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << " snoop 
value: " << &std::hex << our_value ) );
              }
              break;
            case 4:
              {
                  unsigned long our_value = 
value_according_to_sb.getWord(mem_trans->s.physical_address & 7);
                  SIM_set_mem_op_value_cpu(&mem_trans->s, our_value);
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << " snoop 
value: " << &std::hex << our_value ) );
              }
              break;
            case 8:
              {
                  unsigned long long our_value = 
value_according_to_sb.getDoubleWord(mem_trans->s.physical_address & 7);
                  SIM_set_mem_op_value_cpu(&mem_trans->s, our_value);
                  DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex) ( << " snoop 
value: " << &std::hex << our_value ) );
              }
              break;
            default:
              DBG_Assert( false, SetNumeric( (FlexusIdx) theIndex) ( << 
"Unsupported memory transaction size: " << mem_trans->s.size) );
          }

        }
      }

      return 0;
    }
  };  // class SimicsTracerImpl


class SimicsTracer : public Simics::AddInObject <SimicsTracerImpl> {
    typedef Simics::AddInObject<SimicsTracerImpl> base;
   public:
    static const Simics::Persistence  class_persistence = Simics::Session;
    static std::string className() { return "InOrderFeeder"; }
    static std::string classDescription() { return "Flexus's In-order 
instruction feeder."; }

    SimicsTracer() : base() { }
    SimicsTracer(Simics::API::conf_object_t * aSimicsObject) : 
base(aSimicsObject) {}
    SimicsTracer(SimicsTracerImpl * anImpl) : base(anImpl) {}
};


}
-------------- next part --------------
// DO-NOT-REMOVE begin-copyright-block
//
// Redistributions of any form whatsoever must retain and/or include the
// following acknowledgment, notices and disclaimer:
//
// This product includes software developed by Carnegie Mellon University.
//
// Copyright \(c\) 2005 by Brian Gold, Nikos Hardavellas, Jangwoo Kim,
// Jared Smolens, Stephen Somogyi, Tom Wenisch, Babak Falsafi and
// James C. Hoe for the SimFlex Project, Computer Architecture Lab
// at Carnegie Mellon, Carnegie Mellon University.
//
// For more information, see the SimFlex project website at:
//   http://www.ece.cmu.edu/~simflex
//
// You may not use the name Carnegie Mellon University or derivations
// thereof to endorse or promote products derived from this software.
//
// If you modify the software you must place a notice on or within any
// modified version provided or made available to any third party stating
// that you have modified the software.  The notice shall include at least
// your name, address, phone number, email address and the date and purpose
// of the modification.
//
// THE SOFTWARE IS PROVIDED AS-IS WITHOUT ANY WARRANTY OF ANY KIND, EITHER
// EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO ANY WARRANTY
// THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS OR BE ERROR-FREE AND ANY
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
// TITLE, OR NON-INFRINGEMENT.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
// BE LIABLE FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO DIRECT, INDIRECT,
// SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN
// ANY WAY CONNECTED WITH THIS SOFTWARE (WHETHER OR NOT BASED UPON WARRANTY,
// CONTRACT, TORT OR OTHERWISE).
//
// DO-NOT-REMOVE end-copyright-block

#include <core/types.hpp>
#include <core/boost_extensions/intrusive_ptr.hpp>
#include <core/stats.hpp>

namespace Flexus {
namespace SharedTypes {


  struct ConsumerEntry {
    enum FeederStatus {
      Idle,        // no operation ready for fetch; no transaction in progress
      Ready,       // the operation is waiting to be executed
      InProgress,  // the transaction is in progress
      Complete     // the current operation has completed
    };

    //Current status
    FeederStatus theStatus;
    boost::intrusive_ptr<ArchitecturalInstruction> theReadyInstruction;

    ConsumerEntry()
      : theStatus(Idle)
      {}

    ConsumerEntry(boost::intrusive_ptr<ArchitecturalInstruction> & 
anInstruction)
      : theStatus(Ready)
      , theReadyInstruction(anInstruction)
      {}

    bool isIdle() const {
      return theStatus == Idle;
    }

    bool isReady() const {
      return theStatus == Ready;
    }

    bool isInProgress() const {
      return theStatus == InProgress;
    }

    bool isComplete() const {
      return theStatus == Complete;
    }

    void acknowledgeComplete() {
      DBG_Assert( (isComplete()) );
      theStatus = Idle;
    }

    void beginInstruction() {
      DBG_Assert( (isReady()) );
      theStatus = InProgress;
    }

    void releaseInstruction(ArchitecturalInstruction const & anInstruction) {
      DBG_Assert( (isInProgress()) );
      DBG_Assert( (&anInstruction == theReadyInstruction.get()) );
      theStatus = Complete;
    }

    void consumeInstruction(boost::intrusive_ptr<ArchitecturalInstruction> & 
anInstruction) {
      DBG_Assert( (isIdle()) );
      theStatus = Ready;
      theReadyInstruction = anInstruction;
    }

    //Provides a reference to the contained instruction object.
    //Allows faster access to the instruction in the SimicsTracer.
    ArchitecturalInstruction & optimizedGetInstruction() {
      return *theReadyInstruction;
    }

    //Note the conversion from boost::intrusive_ptr<ArchitecturalInstruction> to
    //boost::intrusive_ptr<Instruction>
    boost::intrusive_ptr<ArchitecturalInstruction> ready_instruction() {
      DBG_Assert( (isReady()) );
      return theReadyInstruction;
    }

  };  // struct ConsumerEntry

  inline std::ostream & operator<< (std::ostream & anOstream, ConsumerEntry & 
entry) {
    static char * statusStr[] = {"Idle", "Ready", "InProgress", "Complete"};
    anOstream << statusStr[entry.theStatus] << "-" << 
*entry.theReadyInstruction;
    return anOstream;
  };



  struct SimicsTraceConsumer {
    // queue of outstanding operations

    std::deque<ConsumerEntry> theEntries;
    // has Simics been told to wait (if this is true, the next memory request
    // must be a repeat of the last one)
    bool simicsPending;

    unsigned long long theInitialCycleCount;

    Flexus::Stat::StatCounter theInstructionCount;

    // info on the most recent atomic operation, for verification purposes
    PhysicalMemoryAddress theAtomicInstAddress;
    PhysicalMemoryAddress theAtomicDataAddress;
    bool atomicVerifyPending;

    unsigned int theIndex;


  #ifdef FLEXUS_FEEDER_TRACE_DEBUGGER
    // trace info on the last several instructions
    SimicsTraceDebugger debugger;
  #endif //FLEXUS_FEEDER_TRACE_DEBUGGER

    SimicsTraceConsumer(std::string const & aName)
      : simicsPending(false)
      , theInitialCycleCount(0)
      , theInstructionCount(aName + "-Instructions")
      , atomicVerifyPending(false)
      {}


    void init(unsigned int anIndex) {
      theIndex = anIndex;
      #ifdef FLEXUS_FEEDER_TRACE_DEBUGGER
        debugger.init(anIndex);
      #endif //FLEXUS_FEEDER_TRACE_DEBUGGER
    }

    void setInitialCycleCount(unsigned long long aCycleCount) {
      theInitialCycleCount = aCycleCount;
    }

    unsigned long long initialCycleCount() {
      return theInitialCycleCount;
    }

    bool largeQueue() const {
      return (theEntries.size() > 1000) ;
    }

    bool queueSize() const {
      return theEntries.size() ;
    }

    bool isIdle() const {
      return (!simicsPending);
    }

    bool isQuiesced() const {
      return isIdle() && theEntries.empty();
    }

    void simicsDone() {
      DBG_Assert( (simicsPending) );
      simicsPending = false;
    }

    bool isReady() const {
      if(theEntries.empty()) {
        return false;
      }
      else {
        return theEntries.front().isReady();
      }
    }

    bool isInProgress() const {
      if(theEntries.empty()) {
        return false;
      }
      else {
        return theEntries.front().isInProgress();
      }
    }

    bool isComplete() const {
      // We're done if all outstanding operations have been completed and
      // acknowledged (i.e. the instruction queue is empty) but Simics is
      // still expecting a response
      return (theEntries.empty() && simicsPending);
    }

    void releaseInstruction(ArchitecturalInstruction const & anInstruction) {
      DBG_Assert( (!theEntries.empty()) );
      theEntries.front().releaseInstruction(anInstruction);
      theEntries.pop_front();
    }

    void consumeInstOperation(boost::intrusive_ptr<ArchitecturalInstruction> & 
anInstruction) {
      // a new instruction operation always requires a new entry
      theEntries.push_back( ConsumerEntry(anInstruction) );
      clearAtomicPending();
    }

    bool isEmpty() {
      return theEntries.empty();
    }

    ArchitecturalInstruction & optimizedGetInstruction() {
      DBG_Assert( ! theEntries.empty() );
      return theEntries.back().optimizedGetInstruction();
    }


    void consumeDataOperation() {
        simicsPending = true;
    }

    void recordAtomicVerification( PhysicalMemoryAddress const & aPC, 
PhysicalMemoryAddress const & aDataAddr ) {
        DBG_Assert(!atomicVerifyPending);
        theAtomicInstAddress = aPC;
        theAtomicDataAddress = aDataAddr;
        atomicVerifyPending = true;
    }

    bool isAtomicOperationPending() {
      return atomicVerifyPending;
    }

    PhysicalMemoryAddress getAtomicPC() {
      return theAtomicInstAddress;
    }

    PhysicalMemoryAddress getAtomicDataAddr() {
      return theAtomicDataAddress;
    }

    void clearAtomicPending() {
      atomicVerifyPending = false;
    }

    void verifyAtomicOperation(bool anIsWrite, PhysicalMemoryAddress const & 
aPC, PhysicalMemoryAddress const & aDataAddr) {
      DBG_Assert(atomicVerifyPending);
      DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex)
                 Condition(aPC != theAtomicInstAddress)
                 ( << "atomic PC's don't match: saved="
                   << theAtomicInstAddress << " new_op="
                   << aPC
                 ) );
      if(anIsWrite) {
        DBG_(VVerb, SetNumeric( (FlexusIdx) theIndex)
                   Condition(aDataAddr != theAtomicDataAddress)
                   ( << "atomic data addresses don't match: saved="
                     << theAtomicDataAddress << " new_op="
                     << aDataAddr
                   ) );
        //DBG_Assert(aDataAddr == theAtomicDataAddress);
      }
      //DBG_Assert(aPC == theAtomicInstAddress);
      atomicVerifyPending = false;
    }

    boost::intrusive_ptr<ArchitecturalInstruction> ready_instruction() {
      DBG_Assert( (isReady()) );
      return theEntries.front().ready_instruction();
    }

    void begin_instruction() {
      DBG_Assert( (isReady()) );
      theEntries.front().beginInstruction();
      theInstructionCount++;
    }

  };  // struct SimicsTraceConsumer

  inline std::ostream & operator<< (std::ostream & anOstream, 
SimicsTraceConsumer & cons) {
    std::deque<ConsumerEntry>::iterator iter;
    anOstream << "FeederMemOpQueue: ";
    for(iter = cons.theEntries.begin(); iter != cons.theEntries.end(); iter++) {
      anOstream << *iter << " ";
    }
    anOstream << std::endl;
    return anOstream;
  };


} //SharedTypes
} //Flexus
From shanlu at cs.uiuc.edu  Fri Oct 21 22:05:22 2005
From: shanlu at cs.uiuc.edu (shan)
List-Post: [email protected]
Date: Fri Oct 21 22:05:50 2005
Subject: [simflex]re: x86-multithread on SimFlex error
In-Reply-To: 
<pine.lnx.4.53l-ece.cmu.edu.0510211824340.15...@dalmore.ece.cmu.edu>
Message-ID: <[email protected]>

Hi Thomas,
  Thanks very much :).
  I have tried the patch and it works fine with my small multithreaded
program :). 
  Thanks. Just one thing, there seem to be a typo in TraceConsumer.hpp Line
735, which should be getAtomicDataAddress instead of getAtomicData. The
latter can not compile.
  
  Thanks :)
Shan 

-----Original Message-----
From: Thomas Wenisch [mailto:[email protected]] 
Sent: Friday, October 21, 2005 4:34 PM
To: shan
Cc: [email protected]
Subject: RE: [simflex]re: x86-multithread on SimFlex error

Hi Shan,

I have attached new versions of SimicsTracer.hpp and TraceConsumer.hpp for
you to try.  They both go in the InorderSimicsFeeder component.

I still have not set up an x86 test workload to confirm that my fix
works.  If you still have trouble, let me know, and I will actually put
together a disk image for testing here.

Basically, I have completely separated the v9 and x86 code paths for
atomic operations, and removed all the sparc-specific hacks from the x86
code path.  The x86 code should not cause any assertions, and should be
able to deal with any random sequence of atomic memory operations that
Simics throws at it.  The only thing I am doing that is potentially wrong
is that I am assuming that all atomic operations are read-modify-writes.
I think this may not be strictly true for x86 (the lock prefix can be used
with certain load instructions), but it is a conservative approximation.
The CMPXCHG instructions is definately a read-modify-write.

Thanks for your (continued) efforts in helping me fix these bugs.

Regards,
-Tom Wenisch

On Thu, 20 Oct 2005, shan wrote:

> Hi, I used SIM_disassemble and the instruction is:
>
> CMPXCHG lock [ESI],ECX
>
> Do you need other information?
> Thanks
> shan
>
> -----Original Message-----
> From: Thomas Wenisch [mailto:[email protected]]
> Sent: Thursday, October 20, 2005 7:48 PM
> To: shan
> Subject: Re: [simflex]re: x86-multithread on SimFlex error
>
> Hi Shan,
>
> Can you try to determine the opcode that is causing the error?  This will
> be helpful, as then I can write a small assembly test case to try to fix
> the problem in SimicsTracer.
>
> I suggest you read through the function that is triggering the assertion.
> There is code elsewhere in the function that reads the opcode of an
> instruction, you can copy this code to the location of the assertion.  You
> can change the opcode back into human readable assembly with the
> SIM_disassemble function (documented in the simics reference manual, or
> you could grep the Flexus codebase to see how its used, I'm sure we use it
> somewhere).
>
> Regards,
> -Tom Wenisch
>
> On Thu, 20 Oct 2005, shan wrote:
>
> > Hi Thomas,
> >   Sorry, I guess there is something wrong with my department's mail
> server.
> > I am not sure if you have got my following e-mail.
> >   I tried your patch. The old problem disappeared but there are still
> > problem in thread_create function. Do you have some debug version code,
so
> > that I can get more debugging information to tell you?
> >
> > Thanks
> > Shan
> >
> > -----Original Message-----
> > From: shan [mailto:[email protected]]
> > Sent: Tuesday, October 18, 2005 8:57 PM
> > To: 'Thomas Wenisch'
> > Cc: '[email protected]'
> > Subject: RE: x86-multithread on SimFlex error
> >
> > Hi Thomas,
> >   Thanks very much. I used your new file. The program runs longer but
> still
> > fails after a while. The screen output is like:
> > 46 <flexus.cpp:240> {3276800}- Timestamp: 2005-Oct-18 21:45:08
> > 47 <SimicsTracer.hpp:662> (<undefined>[<undefined>]) {3405134}-
Assertion
> > failed: ((!(inst.isNOP()))) : <undefined>
> > ***  Simics getting shaky, switching to 'safe' mode.
> > ***  Simics (main thread) received an abort signal, probably an
assertion.
> > <Simics is running in 'safe' mode>
> >
> >   The SimicsTracer.hpp:662 seems to be operating on some atomic
> instruction.
> > I am pretty sure it is inside the pthread_create system call ...
> >   Do you need some other information? Maybe I can dump out what is the
> 'bad'
> > instruction's PC ...
> >   By the way, as for the TLB problem, I think I understand what you
said.
> > But if that is the problem, even if you add error checking, you still
can
> > not get the physical address, yes? how do you solve the problem?
> > Thanks
> > Shan
> >
> > -----Original Message-----
> > From: Thomas Wenisch [mailto:[email protected]]
> > Sent: Tuesday, October 18, 2005 12:35 PM
> > To: shan
> > Cc: [email protected]
> > Subject: Re: x86-multithread on SimFlex error
> >
> > Hi Shan,
> >
> > On Tue, 18 Oct 2005, shan wrote:
> >
> > > Hi,
> > >   I am trying the x86 module of Flexus. It works perfectly with single
> > > thread application, but when I try some multithreaded program (just a
> very
> > > simple toy application with pthread_create and pthread_join). There is
> > some
> > > error. The error information is like:
> > >
> > > ....
> > > 31 <flexus.cpp:240> {1835008}- Timestamp: 2005-Oct-18 09:57:25
> > > [cpu0] <address not in TLB>
> > > simics> c
> > > [cpu0] <address not in TLB>
> > > simics>
> >
> > The address not in TLB exception is an exception that Simics raises
> > anytime some piece of code (i.e., Flexus) asks it to translate a logical
> > address to a physical address, but the translation is not available in
the
> > TLB of the current CPU.  This situation is very unusual - it probably
only
> > arises while the OS is manipulating TLB entries or is about to take a
page
> > fault on an instruction reference or something similar.  However,
> > functions like pthread_create are more likely to create this situation.
> >
> > The fact that this is causing your simulation to stop is a bug in
Flexus.
> > Flexus uses the SIM_logical_to_physical call to get the physical PC
> > of instructions in a few special cases.  This call can fail if the
> > translation for the PC is not available in the TLB (which implies the
CPU
> > is about to take an ITLB fault).  However, I forgot to include an error
> > check after the calls to SIM_logical_to_physical, so the exception ends
up
> > propagating back to the Simics frontend, and stops the simulation.
> >
> > The fix is to add an error check after the SIM_logical_to_physical calls
> > in components/InorderSimicsFeeder/SimicsTracer.hpp.  I have attached a
> > fixed version of the file to this email.  Note that I did not test it
> > (except to check that it compiles), as I do not have any x86 test images
> > handy.  We don't use x86 extensively here, which is why this bug has
gone
> > unnoticed.
> >
> > Please let me know if you continue to have problems. If so, I will help
> > you add a bunch of debugging messages so we can confirm if the problem
is
> > actually what I think it is.
> >
> > Regards,
> > -Tom Wenisch
> > Computer Architecture Lab
> > Carnegie Mellon University
> >
> > >
> > >   It happens after the program simulated a little while, maybe right
at
> > the
> > > time when the thread is created.
> > >   I guess I miss some multi-thread related flag... what should I do to
> > > simulate a multithreaded application?
> > >   Oh, my toy application can run on simics without flexus module
loaded.
> > > Thanks
> > > Shan
> > >
> > >
> >
> >
>
>

Reply via email to