Added a commitlog post-processor for Rocket
- Useful for taking Rocket's out-of-order writebacks and generating an in-order commit log. - Resulting commit log can be diffed against Spike's commit log.
This commit is contained in:
parent
17e971bbfa
commit
c8a7deb950
256
csrc/comlog.cc
Normal file
256
csrc/comlog.cc
Normal file
@ -0,0 +1,256 @@
|
||||
//*****************************************************
|
||||
// Christopher Celio
|
||||
// 2015 Feb 2
|
||||
//
|
||||
// Utility for taking a raw commit log from a processor and post-processing it
|
||||
// into a diff-able format against the spike ISA simulator's commit log.
|
||||
//
|
||||
// INPUT : a raw commit log via std::cin
|
||||
// OUTPUT: a cleaned up commit log via std::cout
|
||||
//
|
||||
// PROBLEM: some writebacks can occur after the commit point in a processor.
|
||||
// These partial entries will be marked as appropriate, and the writebacks will
|
||||
// be written to the log as soon as they occur (possibly out-of-order). This
|
||||
// program will put the writebacks in their proper place.
|
||||
//
|
||||
// FUNFACT: with processors that use renaming to break WAW hazards, it is
|
||||
// possible for writes to the same ISA register to also occur OoO. Thus, the
|
||||
// raw commit log must tell give us the physical destination (pdst)
|
||||
// indentifiers for matching write-backs to the appropriate partial commit
|
||||
// entry.
|
||||
|
||||
/*
|
||||
// Typical (raw) commit log...
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
0 0x0000000000002ccc (0x00973423)
|
||||
0 0x0000000000002cd0 (0x00a73023)
|
||||
0 0x0000000000002cd4 (0x05070113) x2 0x0000000000025180
|
||||
0 0x0000000000002cd8 (0xd8070713) x14 0x0000000000024eb0
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
0 0x000000000000208c (0x00b6b72f) x14 p 1 0xXXXXXXXXXXXXXXXX
|
||||
0 0x0000000000002090 (0x80000eb7) x29 0xffffffff80000000
|
||||
x14 p 1 0xffffffff80000000
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
|
||||
// Note: the first number is the current privileged mode of the committed
|
||||
// instruction.
|
||||
//
|
||||
-----------------------------------------------------------
|
||||
|
||||
The "x14 p 1 0xXXXXXXXXXXXXXXXX" segment needs to be replaced with the later
|
||||
"x14 0xffffffff80000000" segment.
|
||||
|
||||
The physical tags must be used for matching writebacks to partial commits,
|
||||
as it is possible with renaming to break the write-after-write hazard and
|
||||
have out-of-order writebacks to the same ISA/logical register! However, the
|
||||
physical tag needs to be deleted in the final output, as the ISA simulator
|
||||
does not know or care about renamed registers.
|
||||
|
||||
// Final (cleaned up) commit log
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
0 0x0000000000002ccc (0x00973423)
|
||||
0 0x0000000000002cd0 (0x00a73023)
|
||||
0 0x0000000000002cd4 (0x05070113) x2 0x0000000000025180
|
||||
0 0x0000000000002cd8 (0xd8070713) x14 0x0000000000024eb0
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
0 0x000000000000208c (0x00b6b72f) x14 0xffffffff80000000
|
||||
0 0x0000000000002090 (0x80000eb7) x29 0xffffffff80000000
|
||||
0 0x0000000000002cdc (0xea5ff0ef) x1 0x0000000000002ce0
|
||||
|
||||
-----------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <queue>
|
||||
#include <assert.h>
|
||||
|
||||
// data-structures
|
||||
|
||||
typedef struct RobEntry
|
||||
{
|
||||
bool ready; // is entry ready to be committed?
|
||||
int pdst; // the wb physical dest. register
|
||||
std::string str; // the commit string to print out
|
||||
} RobEntry;
|
||||
|
||||
std::deque <RobEntry> rob;
|
||||
|
||||
// partial entries are also stored in a side buffer, for faster CAM searching.
|
||||
// When a write-back occurs, it needs to search the ROB for the matching pdst
|
||||
// tag. But since that CAM search is generally painful in software (and the ROB
|
||||
// will be mostly full of ready-to-commit entries) let's only do the CAM search
|
||||
// on a smaller queue of still-busy entries. We will delete partial entries
|
||||
// once the write-back has returned. TODO... since there will only be one "pdst"
|
||||
// outstanding at a time, we could use a map for fast lookup instead of a
|
||||
// linear search.
|
||||
|
||||
typedef struct PartialEntry
|
||||
{
|
||||
RobEntry* rob_entry; // point to the ROB entry we correspond to
|
||||
int pdst;
|
||||
} PartialEntry;
|
||||
|
||||
std::deque <PartialEntry> pdst_cam;
|
||||
|
||||
|
||||
// functions
|
||||
|
||||
void push (std::string& line);
|
||||
void commit ();
|
||||
void writeback (std::string& line);
|
||||
bool is_instruction (std::string& line);
|
||||
bool is_partial_commit (std::string& line);
|
||||
int get_ldst (std::string& line);
|
||||
int get_pdst (std::string& line);
|
||||
|
||||
// add instruction to the ROB
|
||||
// mark as "not ready" if writeback data not ready
|
||||
void push (std::string& line)
|
||||
{
|
||||
bool is_partial = is_partial_commit(line);
|
||||
|
||||
RobEntry rob_entry;
|
||||
rob_entry.str = line;
|
||||
rob_entry.ready = !(is_partial);
|
||||
rob_entry.pdst = is_partial ? get_pdst(line) : 0;
|
||||
rob.push_back(rob_entry);
|
||||
|
||||
if (is_partial)
|
||||
{
|
||||
PartialEntry new_entry = (PartialEntry)
|
||||
{ .rob_entry = &(rob.back()),
|
||||
.pdst = rob_entry.pdst
|
||||
};
|
||||
pdst_cam.push_back(new_entry);
|
||||
}
|
||||
}
|
||||
|
||||
void commit ()
|
||||
{
|
||||
while (!rob.empty() && rob.front().ready)
|
||||
{
|
||||
std::cout << rob.front().str << std::endl;
|
||||
rob.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
int get_ldst (std::string& line)
|
||||
{
|
||||
assert (line.length() > 46);
|
||||
|
||||
int idx = line.find_first_of('x');
|
||||
int dst = atoi(line.substr(idx+1,2).c_str());
|
||||
return dst;
|
||||
}
|
||||
|
||||
int get_pdst (std::string& line)
|
||||
{
|
||||
assert (line.length() > 46);
|
||||
|
||||
int idx = line.find_first_of('p');
|
||||
int dst = atoi(line.substr(idx+1,2).c_str());
|
||||
return dst;
|
||||
}
|
||||
|
||||
bool is_partial_commit (std::string& line)
|
||||
{
|
||||
if (line.length() > 46 && (line.at(34) == 'x' || line.at(34) == 'f') && line.at(46) == 'X')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_instruction (std::string& line)
|
||||
{
|
||||
return !(line.at(0) == 'x' || line.at(0) == 'f');
|
||||
}
|
||||
|
||||
// find instruction in ROB and substitute in the writeback data
|
||||
// and mark it as ready for commit
|
||||
void writeback (std::string& line)
|
||||
{
|
||||
assert (line.at(0) == 'x' || line.at(0) == 'f');
|
||||
|
||||
int ldst = atoi(line.substr(1,2).c_str());
|
||||
int idx = line.find_first_of('p');
|
||||
assert (idx != std::string::npos);
|
||||
int pdst = atoi(line.substr(idx+1,2).c_str());
|
||||
|
||||
// search the partial queue for writeback, then modify the ROB entry, mark as ready
|
||||
RobEntry* rob_entry;
|
||||
bool found_entry = false;
|
||||
|
||||
// order of search doesn't matter; there should be a unique
|
||||
// pdst identifier (to deal with WAW hazards).
|
||||
// we then delete the entry once we've matched against it so
|
||||
// future matches will be fast.
|
||||
for (auto it = pdst_cam.begin(); it != pdst_cam.end();/*NOTE: no incrementation here*/ )
|
||||
{
|
||||
if (pdst == it->pdst)
|
||||
{
|
||||
// verify there is only ever one match!
|
||||
assert (!found_entry);
|
||||
rob_entry = it->rob_entry;
|
||||
it = pdst_cam.erase(it);
|
||||
found_entry = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// update ROB
|
||||
assert (found_entry);
|
||||
assert (rob_entry->str.length() > 32);
|
||||
std::string* rob_str = &(rob_entry->str);
|
||||
|
||||
rob_entry->ready = true;
|
||||
idx = line.find("0x");
|
||||
std::string wbdata = line.substr(idx+2,16);
|
||||
idx = rob_str->find("0x",32); // actually want to find the 3rd occurrence
|
||||
int p_idx = rob_str->find_first_of('p');
|
||||
rob_str->replace(idx+2,16,wbdata);
|
||||
rob_str->erase(p_idx, (idx-p_idx));
|
||||
}
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::string line;
|
||||
|
||||
// check for errno
|
||||
while (getline(std::cin, line))
|
||||
{
|
||||
if (is_instruction(line))
|
||||
{
|
||||
push(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeback(line);
|
||||
}
|
||||
|
||||
// check if head of the rob is ready, commit
|
||||
// instructions until either empty or not ready
|
||||
commit();
|
||||
}
|
||||
|
||||
if (std::cin.bad())
|
||||
{
|
||||
// IO error
|
||||
std::cout << "\nIO ERROR: cin.bad()\n\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user