GEM5 O3 CPU Backend

2020/07/03

This is my note on reading GEM5’s O3 cpu backend. I could not find a good document online, and the code is a little bit entangled and tricky to understand. So here I would extract the key function chain to show how an instruction is handled by the backend.

Hopefully this could help more people. I assume you are already familiar with GEM5.

Compute Instructions

Compute instructions are simpler as they do not access memory and not interact with the LSQ. It is actually pretty straightforward and here is a high-level description. I first show the calling chain (only important functions), and then describe its functionality.

Rename::tick()->Rename::RenameInsts()
IEW::tick()->IEW::dispatchInsts()
IEW::tick()->InstructionQueue::scheduleReadyInsts()
IEW::tick()->IEW::executeInsts()
IEW::tick()->IEW::writebackInsts()
Commit::tick()->Commit::commitInsts()->Commit::commitHead()

Load Instruction

Load instructions shares the same path as compute instructions until execution.

IEW::tick()->IEW::executeInsts()
  ->LSQUnit::executeLoad()
    ->StaticInst::initiateAcc()
      ->LSQ::pushRequest()
        ->LSQUnit::read()
          ->LSQRequest::buildPackets()
          ->LSQRequest::sendPacketToCache()
    ->LSQUnit::checkViolation()
DcachePort::recvTimingResp()->LSQRequest::recvTimingResp()
  ->LSQUnit::completeDataAccess()
    ->LSQUnit::writeback()
      ->StaticInst::completeAcc()
      ->IEW::instToCommit()
IEW::tick()->IEW::writebackInsts()

Store Instruction

Store instructions are similar to load instructions, but only writeback to cache after committed.

IEW::tick()->IEW::executeInsts()
  ->LSQUnit::executeStore()
    ->StaticInst::initiateAcc()
      ->LSQ::pushRequest()
        ->LSQUnit::write()
    ->LSQUnit::checkViolation()
Commit::tick()->Commit::commitInsts()->Commit::commitHead()
IEW::tick()->LSQUnit::commitStores()
IEW::tick()->LSQUnit::writebackStores()
  ->LSQRequest::buildPackets()
  ->LSQRequest::sendPacketToCache()
  ->LSQUnit::storePostSend()
DcachePort::recvTimingResp()->LSQRequest::recvTimingResp()
  ->LSQUnit::completeDataAccess()
    ->LSQUnit::completeStore()

Atomic Instruction

Atomic instructions are similar to store instructions, but they are executed non-speculatively.

Rename::tick()->Rename::RenameInsts()
IEW::tick()->IEW::dispatchInsts()
  ->LSQUnit::insertStore()
  ->InstructionQueue::insertNonSpec()
    ->MemDepUnit::insertNonSpec()
Commit::tick()->Commit::commitInsts()->Commit::commitHead()
IEW::tick()->InstructionQueue::scheduleNonSpec()
  ->MemDepUnit::nonSpecInstReady()
    ->MemDepUnit::moveToReady()
      ->InstructionQueue::addReadyMemInst()
IEW::tick()->InstructionQueue::scheduleReadyInsts()
IEW::tick()->IEW::executeInsts()
  ->LSQUnit::executeStore()
    ->StaticInst::initiateAcc()
      ->LSQ::pushRequest()
        ->LSQUnit::write()
    ->LSQUnit::SQEntry::canWB() = true
    ->LSQUnit::checkViolation()
IEW::tick()->LSQUnit::writebackStores()
  ->LSQRequest::buildPackets()
  ->LSQRequest::sendPacketToCache()
  ->LSQUnit::storePostSend()
DcachePort::recvTimingResp()->LSQRequest::recvTimingResp()
  ->LSQUnit::completeDataAccess()
    ->LSQUnit::writeback()
      ->IEW::instToCommit()
    ->LSQUnit::completeStore()
Commit::tick()->Commit::commitInsts()->Commit::commitHead()

Branch Misspeculation

Branch misspeculation is handled in the IEW::executeInsts(). It will notify the commit stage to start squashing all instructions in the ROB until the misspeculated branch.

IEW::tick()->IEW::executeInsts()->IEW::squashDueToBranch()

Memory Order Misspeculation

The InstructionQueue has a MemDepUnit to track memory order dependence. The IQ will not schedule an instruction if MemDepUnit says there is no more dependence.

In LSQUnit::read(), the LSQ will search for possible aliasing store and forward if possible. Otherwise, the load is blocked and rescheduled when the blocking store completes, by notifying the MemDepUnit.

Both LSQUnit::executeLoad/Store() will call LSQUnit::checkViolation() to search in the LQ for possible misspeculation. If found, it will set LSQUnit::memDepViolator and later IEW::executeInsts() will start to squash.

IEW::tick()->IEW::executeInsts()
  ->LSQUnit::executeLoad()
    ->StaticInst::initiateAcc()
    ->LSQUnit::checkViolation()
  ->IEW::squashDueToMemOrder()