前回のRVVLoadの定義に対して、いくつかデバッグをしていた。ドキュメントが数少ないので調べるのが大変なのだが、GDBで一つ一つコードの動きを読んでいく。
命令の定義には大きく分けて3ステップが必要そうだ。
Fault execute(ExecContext *, Trace::InstRecord *) const override; Fault initiateAcc(ExecContext *, Trace::InstRecord *) const override; Fault completeAcc(PacketPtr, ExecContext *, Trace::InstRecord *) const override;
execute()
は主に算術演算命令に使用される。Load/Store命令ではあまり使用されないようだ。実際、ロード命令でexecute()
をInvokeするとエラーを出力して終了した。
Execute (IEW::executeInsts()) Here we invoke the execute() function of the compute instruction and send them to commit. Notice execute() will write results to the destiniation register.
initiateAcc()
は、メモリアクセスを起動する操作らしい。メモリアクセスリクエストを発行するイメージでよい。
LSQUnit::executeLoad() will initiate the access by invoking the instruction’s initiateAcc(). Through the execution context interface, initiateAcc() will call initiateMemRead() and eventually be directed to LSQ::pushRequest().
つまり、LSQに対してリクエストが挿入されるイメージだ。
completeAcc()
は、メモリアクセスが完了してレジスタにデータが書き込まれるイメージだ。
LSQUnit::writeback() will invoke StaticInst::completeAcc(), which will eventually write loaded value to destination register. Then the instruction is pushed to commit queue, so that IEW::writebackInsts() will mark it done and wake up its dependents. Starting from here it shares same path with compute instructions.
これに基づいて、VLE8ベクトルロード命令を考えてみる。
まず、initiateAcc()
だが、initiateMemRead()
の方法がよくわからない。これはLSQを起動するとしたら、ベクトルアクセス要素数分だけ呼び出さないといけないのかなあ?この辺がよくわからない。
def template RVVLoadInitiateAcc {{ Fault %(class_name)s::initiateAcc(ExecContext *xc, Trace::InstRecord *traceData) const { Addr EA; %(op_src_decl)s; %(op_rd)s; MemElemType memData = 0; EA = Rs1; return initiateMemRead(xc, traceData, EA, memData, memAccessFlags); } }};
completeAcc()
のほうは、一応要素の数だけ書き込みを起こすようにしてみたが、それでも正しく動作しているのかよくわからない。
def template RVVLoadCompleteAcc {{ Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc, Trace::InstRecord *traceData) const { Addr EA; %(op_decl)s; %(op_rd)s; EA = Rs1; MemElemType memData = 0; { for (int i = 0; i < 16; i++) { getMemLE(pkt, memData, traceData); } } %(memacc_code)s; %(op_wb)s; return NoFault; } }};
なんか違うなあ。そもそもロード命令としてVLE8を定義するのが間違ってるのかなあ。もう一度SVEの実装を読み直してみたいと思う。