Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InstructionGenerator to also generate dummy ops #104

Open
egieske opened this issue Oct 19, 2023 · 3 comments
Open

InstructionGenerator to also generate dummy ops #104

egieske opened this issue Oct 19, 2023 · 3 comments

Comments

@egieske
Copy link

egieske commented Oct 19, 2023

For more accurate Fetch Unit behavior, speculative ops that aren't from a correct path trace provided instruction are desirable. i.e., wrong-path fetched ops (similar ops may be useful for prefetches).
The InstructionGenerator should be enabled to create these dummy ops so that its unique_id is correct and the correct path trace instructions are not lost.
One approach would be to overload the getNextInst(const sparta::Clock * clk) with another signature like getNextInst(const sparta::Clock * clk, bool dummy).
Another approach might be to add a function getDummyInst(const sparta::Clock * clk)

Note from a prior email exchange with Knute:
The use of RISC-V hint instructions or no-ops where the operand number has special meaning.  For example, if you look at

inst = mavis_facade_->makeInstDirectly(ex_info, clk);

you can see how you can create a specific instruction + operands that you can use to determine if spec.

@ghost
Copy link

ghost commented Oct 19, 2023

For "fake" speculative execution, there are four avenues until we have full execution-driven capabilities:

  1. Do nothing. Stall fetching, wait for branch resolution and then resume fetch when resolved
  2. Inject no-ops
  3. Read ahead in the trace, then rewind when branch resolved
  4. Fetch real instructions from the original ELF

The main issue with all approaches -- it just ain't accurate w.r.t. load/store addressing and branch targets (on the wrong path). Each methodology has its perks, but also minuses.

I would request that you focus on avenues 1 and 3 to allow for analysts to see the effects with and without a spec path, even it that path is not representative.

How you can do item 3: the trace reader uses iterators to walk the trace. If you stash that iterator in the instruction object you can restore the trace reader (instruction generator) back to the mispredicted branch (on a redirect):

(from

InstPtr inst = mavis_facade_->makeInst(opcode, clk);
inst->setPC(next_it_->pc());
inst->setUniqueID(++unique_id_);
inst->setProgramID(unique_id_);
):

            InstPtr inst = mavis_facade_->makeInst(opcode, clk);
            inst->setPC(next_it_->pc());
            inst->setUniqueID(++unique_id_);
            inst->setProgramID(unique_id_);
            inst->setSTFIterator(next_it_);    // <<< add support for this

Update the flushing mechanism to accept the flushing instruction for redirect:
(from

void Fetch::flushFetch_(const uint64_t & new_addr) {
)

    void Fetch::flushFetch_(const uint64_t & new_addr) /// <<< old
    void Fetch::flushFetch_(const InstPtr & flushing_inst) /// <<< new

Finally, after flushing, reset the instruction trace generator with the iterator you stashed in the redirecting instruction. Something like this:

    inst_generator_->reset(flushing_inst->getSTFIterator());

then resume fetching.

@zxc12523
Copy link

zxc12523 commented Oct 30, 2023

@knute-sifive I want to solve this issue, but I have a few questions.

  1. To my best knowledge, Fetch Unit will fetch multiple instructions in a cycle.
    InstPtr ex_inst = inst_generator_->getNextInst(my_clk_);
    , how do we know these instructions contain branch and set Iterator for these instructions.
  2. What if we encounter multiple branch before branch resolution, do we need to store all these iterator?
  3. How do we know a branch is resolved?

@ghost
Copy link

ghost commented Oct 30, 2023

@egieske, is your team already looking at this (or @zxc12523, are you on that team)?

To answer your questions:

  1. You can use Mavis to determine if an instruction is a branch. Add this code to class Inst.hpp:
         bool isBranch() const { return mavis_info_->isInstType(mavis::OpcodeInfo::InstructionTypes::BRANCH); }
    
  2. Yes, you store the iterator in the Inst class for each and every branch. Branches can be executed/resolved/completed out of order. Fetch needs to account for that
  3. You will need to add a sparta::DataOutPort to the ExecutePipe unit and a sparta::DataInPort to the Fetch unit that will be used to communicate branch resolutions from the Execution stage back to the Fetch stage. Suggest that Fetch keep a running list of outstanding, unresolved branches it expects to receive from Execute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants