The simplest way to implement this (assuming that you want to invalidate the whole cache and not a single block) is probably to break into Python and execute something like this:

m5.memWriteback(root)
m5.memInvalidate(root)

These functions are called recursively on the object tree denoted by root, which can be any object in the simulation hierarchy (e.g., a single cache or the simulation root). Another option is to call memWriteback() on the specific object you are interested in. For example:

root.cpu.l1cache.memWriteback()

There is no "clean" way of making callbacks into the simulation script. (I've been planning on implementing this for a while.) The method I currently use is to execute "m5 fail" pseudo instructions in the simulated systems. I usually reserve one bit to denote non-failure exits (e.g., 0x80) and handle the exit code in my simulation scripts. Doing a call into gem5 from the kernel should be fairly easy since this is just a read from a magic address (0xFFFF0000 + offset). I use the following assembly code in some of my test cases (calls m5fail(delay=0, code=0x80)):

mov $0xFFFF0000, %r14   /* m5 interface base address  */
xor %rdi, %rdi          /* Set delay to 0 */
mov $0x80, %rsi         /* Set error code */
mov 0x2200(%r14), %rax  /* Call m5fail */

The read into rax becomes a "fake" function call that uses the Linux x86-64 ABI. Have a look at m5op_x86.S for an example that generates c-wrappers.

//Andreas


On 2014-01-21 23:53, Fangfei Liu wrote:
Thanks! I really appreciate your help! I just realized TLB flush is also
implemented without timing. Anyway, I will try the functional
implementation first.

*From:*gem5-users-boun...@gem5.org [mailto:gem5-users-boun...@gem5.org]
*On Behalf Of *Amin Farmahini
*Sent:* 2014年1月21日1:03
*To:* gem5 users mailing list
*Subject:* Re: [gem5-users] implement cache flush in classic memory model

Hi Fangfei,

If you want to implement it using *functional *accesses (*zero
*latency), you need to
1. Writeback every dirty lines in the cache.

2. Invalidate all lines in the cache.

For invalidation and writeback you can use visitor functions. Here is a
piece of code that might help you.

template<class TagStore>
void
Cache<TagStore>::memWriteback()
{
     WrappedBlkVisitor visitor(*this, &Cache<TagStore>::writebackVisitor);
     tags->forEachBlk(visitor);
}

template<class TagStore>
void
Cache<TagStore>::memInvalidate()
{
     DPRINTF(Cache, "memInvalidate\n");
     WrappedBlkVisitor visitor(*this, &Cache<TagStore>::invalidateVisitor);
     tags->forEachBlk(visitor);
}

template<class TagStore>
bool
Cache<TagStore>::writebackVisitor(BlkType &blk)
{
     if (blk.isDirty()) {
         DPRINTF(Cache, "writebackVisitor set %d\n", blk.set);
         assert(blk.isValid());

         Request request(tags->regenerateBlkAddr(blk.tag, blk.set),
                         blkSize, 0, Request::funcMasterId);

         Packet packet(&request, MemCmd::WriteReq);
         packet.dataStatic(blk.data);

         memSidePort->sendFunctional(&packet);

         blk.status &= ~BlkDirty;
     }

     return true;
}

template<class TagStore>
bool
Cache<TagStore>::invalidateVisitor(BlkType &blk)
{

     DPRINTF(Cache, "invalidateVisitor set %d\n", blk.set);
     if (blk.isDirty())
         warn_once("Invalidating dirty cache lines. Expect things to
break.\n");

     if (blk.isValid()) {
         assert(!blk.isDirty());
         tags->invalidate(dynamic_cast< BlkType *>(&blk));
         blk.invalidate();
     }

     return true;
}

Your pseudo instr can simply call memWriteback() and memInvaliate()
funcitons. You also need to have a pointer to the cache that you are
flushing. You can extend this code to take into account the latency for
flushing by using timing accesses.

If you end up implementing this, please post a patch to review board.

Thanks,
Amin

On Mon, Jan 20, 2014 at 9:08 PM, Fangfei Liu <fangf...@princeton.edu
<mailto:fangf...@princeton.edu>> wrote:

    Hi everyone,

    I would like to implement cache flush (invalidate all and write back
    to main memory) in classic memory model for my project (x86 full
    system). Right now I’m considering two choices. One is to implement
    x86 wbinvd instruction and the other is to add a gem5 pseudo
    instruction. This instruction will be used by Linux kernel. I was
    wondering which method is easier to implement? Does anyone have any
    idea on how to implement it? I find that it seems gem5 implemented
    the TLB flush instruction, can I follow the similar way to implement
    wbinvd instruction? Thanks!

    Best regards

    Fangfei


    _______________________________________________
    gem5-users mailing list
    gem5-users@gem5.org <mailto:gem5-users@gem5.org>
    http://m5sim.org/cgi-bin/mailman/listinfo/gem5-users



_______________________________________________
gem5-users mailing list
gem5-users@gem5.org
http://m5sim.org/cgi-bin/mailman/listinfo/gem5-users


_______________________________________________
gem5-users mailing list
gem5-users@gem5.org
http://m5sim.org/cgi-bin/mailman/listinfo/gem5-users

Reply via email to