

#include "base/vulnerability/vul_tracker.hh"
#include "base/vulnerability/vul_structs.hh"
#include "debug/VulTracker.hh"

void
VulTracker::initVars(int numDest, int numSrc, int pcSize,
                            int numRegs, InstSeqNum seqNum, unsigned int seqNumWidth, unsigned int flagWidth, unsigned int phyRegWidth) 
{
    addField(INST_OPCODE, OPCODE_WIDTH, "opcode");
    addField(INST_PC, pcSize, "pc");
    addField(INST_TID, 1, "tid");
    addField(INST_SEQNUM, seqNumWidth,"seqnum");
    addField(INST_PREDPC, pcSize, "predpc");
    addField(INST_FLAGS, flagWidth, "flags");

    for(int i = 0; i < numSrc; ++i) {
        addField(INST_PHYSRCREGSIDX, phyRegWidth,"physrcregidx",i);
        vulOnWrite(INST_PHYSRCREGSIDX, seqNum, i);
    }

    for(int i = 0; i < numDest; ++i) {
        addField(INST_PHYDESTREGSIDX, phyRegWidth,"phydestregidx", i);

        vulOnWrite(INST_PHYDESTREGSIDX, seqNum, i);
    }

    vulOnWrite(INST_OPCODE, seqNum);
    vulOnWrite(INST_PC, seqNum);
    vulOnWrite(INST_TID, seqNum);
    vulOnWrite(INST_SEQNUM, seqNum);
    vulOnWrite(INST_PREDPC, seqNum);
    vulOnWrite(INST_FLAGS, seqNum);

}

void
VulTracker::addField(InstField f, int size, std::string name, int idx) 
{
    Field fd;

    fd.f = f;
    fd.size = size;
    fd.regIdx = idx;
    fd.name = name;

    fd.reads = 0;
    fd.writes = 0;

    fields.push_back(fd);
}

void
VulTracker::vulOnRead(InstField f, InstSeqNum seqNum, int regIdx) 
{
    fIter fit = fields.begin();

    while(fit != fields.end()) {
        
        if(fit->f == f && regIdx == -1)
            break;
        else if(fit->f == f && regIdx == fit->regIdx)
            break;

        fit++;
    }
    assert(fit != fields.end());

    assert(fit->hist[seqNum].t != -1);

    long vul = fit->size*(curTick() - fit->hist[seqNum].t);
    fit->vul += vul;
    
    // If previous operation was a WRITE, then this READ is vulnerable.
    // If previous operation was a READ, then this READ is vulnerable.
    // If previous operation was INVALID, does not matter.
    if(fit->hist[seqNum].op == WRITE || fit->hist[seqNum].op == READ) {
        
        // Make a pair with the previous WRITE/READ tick and this READ,
        // which would then make a vulnerable interval.
        //fit->vulIntervals[seqNum] = std::make_pair(fit->hist[seqNum].t, curTick());
    }


    fit->hist[seqNum].op = READ;
    fit->hist[seqNum].t = curTick();

    fit->reads++;

}

/*
uStructure* 
VulTracker::selectStruct(uStruct s) {

    uStructure *st;

    switch(s) {

        case ST_REGFILE:
            st = &regFile;
            break;

        default:
            st = NULL;
            break;
    }

    return st;
}
*/
/*
void
VulTracker::vulOnRead(uStruct s, InstField f, int idx) {

    if(idx == 33)
        return;

    uStructure *st = selectStruct(s);

    assert(st != NULL);
    
    fIter fit = st->fields.begin();

    while(fit != st->fields.end()) {

        if(fit->f == f && idx == -1)
            break;
        else if(fit->f == f && idx == fit->regIdx)
            break;

        fit++;

    }

    assert(fit != st->fields.end());

    if(fit->hist.op == READ && fit->hist.t == curTick())
        return;
    
    fit->vul += fit->size*(curTick() - fit->hist.t);

    if(fit->hist.op == WRITE || fit->hist.op == READ) {
        //DPRINTF(VulTracker,"Making pair %ld %ld\n",fit->hist.t,curTick());
        fit->vulIntervals.push_back(std::make_pair(fit->hist.t, curTick()));
    }

    fit->hist.op = READ;
    fit->hist.t = curTick();

    fit->reads++;
}
*/

void
VulTracker::vulOnWrite(InstField f, InstSeqNum seqNum, int regIdx) 
{

    fIter fit = fields.begin();

    while(fit != fields.end()) {

        if(fit->f == f && regIdx == -1)
            break;
        else if(fit->f == f && regIdx == fit->regIdx)
            break;

        fit++;
    }
    assert(fit != fields.end());

    fit->hist[seqNum].op = WRITE;
    fit->hist[seqNum].t = curTick();
    fit->hist[seqNum].incomingTick = curTick();        //Tick for the first write.

    fit->writes++;
}

/*
void
VulTracker::vulOnWrite(uStruct s, InstField f, int idx) {

    uStructure *st = selectStruct(s);

    fIter fit = st->fields.begin();

    while(fit != st->fields.end()) {

        if(fit->f == f && idx == -1)
            break;
        else if(fit->f == f && idx == fit->regIdx)
            break;

        fit++;
    }

    assert(fit != st->fields.end());

    fit->hist.op = WRITE;
    fit->hist.t = curTick();
    fit->hist.incomingTick = curTick();

    fit->writes++;

}
*/

/*
bool 
VulTracker::isVulnerable(Tick t, InstField f, int regIdx) {
    
    if(t > curTick())
        return false;

    fIter fit = fields.begin();

    while(fit != fields.end()) {

        if(fit->f == f && regIdx == -1)
            break;
        else if(fit->f == f && regIdx == fit->regIdx)
            break;

        fit++;

    }

    assert(fit != fields.end());
    
    std::list<std::pair<long,long>>::iterator vulIt = fit->vulIntervals.begin();

    while( vulIt != fit->vulIntervals.end()) {

        if(t >= vulIt->first &&
                t <= vulIt->second) {
            return true;
        }

        vulIt++;
    }

    return false;
}
*/
/*
void
VulTracker::printVulIntervals(uStruct s, InstField f, int seqnum, int regIdx, bool isCommitted) {

    uStructure *st = selectStruct(s);

    fIter fit;

    if(st == NULL) {
        fit = fields.begin();

        while(fit != fields.end()) {

            if(fit->f == f && regIdx == -1)
                break;
            else if(fit->f == f && regIdx == fit->regIdx)
                break;

            fit++;
        }
        if(fit == fields.end())
            return;
    }
    else {
        fit = st->fields.begin();

        while(fit != st->fields.end()) {

            if(fit->f == f && regIdx == -1)
                break;
            else if(fit->f == f && regIdx == fit->regIdx)
                break;

            fit++;

        }
        if(fit == st->fields.end())
            return;
    }

    if(!isCommitted && fit->writes > 0)
        DPRINTF(VulTracker,"[sn:%i]: writes: %d reads: %d committed: %d\n", seqnum, fit->writes, fit->reads, (int)isCommitted); 
    std::list<std::pair<long,long>>::iterator vulIt = fit->vulIntervals.begin();

    while(vulIt != fit->vulIntervals.end()) {

        //DPRINTF(VulTracker,"[sn:%i]: %s vulnerable from tick %ld to %ld\n", seqnum, (fit->name).c_str(), 
        //                                                    vulIt->first, vulIt->second);
        vulIt++;

    }

}
*/
