ベクトル命令における、LMUL>1の対応というのは結構難易度の高い問題だ。
今回はその解決方法として、LMULの値がVSETVL命令で変更されると、例外を出して物理レジスタの構成を整列し直す方式を考えたい。
ここでは、Spikeの実装のみを示すが、同様にハードウェア側も実装を変更する。
まず、現在のLMULとVSETVL命令で設定されたLMULが異なると、例外を発生させる。
require_vector_novtype(false, false); float old_vflmul = P.VU.vflmul; WRITE_RD(P.VU.set_vl(insn.rd(), insn.rs1(), RS1, insn.v_zimm11())); if (old_vflmul != P.VU.vflmul) { throw trap_lmul_change(); }
例外が設定されると、PCを更新して特別な例外ルーティングに移動するようにする。
if (t.cause() == CAUSE_LMUL_CHANGE) { fprintf(log_file, "detect lmul change\n"); state.pc = 0x2000; return; }
例外ルーティンの入っている領域はSpikeのモジュール接続を使用し、メモリを接続する。ここには、ベクトルレジスタをすべてストアして、ロードし直すルーティンが含まれている。
class lmul_change_rom_t : public abstract_device_t { FILE *lmul_change_log_fp; char ram[0x1000]; public: lmul_change_rom_t(std::string name); bool load(reg_t addr, size_t len, uint8_t* bytes); bool store(reg_t addr, size_t len, const uint8_t* bytes); private: uint8_t DATA[1024] = { #include "lmul_exc_rom.txt" }; };
.section .text csrrw sp, sscratch, sp la sp, temp_data sd x10, 0(sp) sd x11, 8(sp) la x10, vector_stack_data csrr x11, vlenb vs1r.v v0 , (x10); add x10, x10, x11 vs1r.v v1 , (x10); add x10, x10, x11 vs1r.v v2 , (x10); add x10, x10, x11 vs1r.v v3 , (x10); add x10, x10, x11 vs1r.v v4 , (x10); add x10, x10, x11 ... vs1r.v v30, (x10); add x10, x10, x11 vs1r.v v31, (x10); add x10, x10, x11 la x10, vector_stack_data vl1r.v v0 , (x10); add x10, x10, x11 vl1r.v v1 , (x10); add x10, x10, x11 vl1r.v v30, (x10); add x10, x10, x11 vl1r.v v31, (x10); add x10, x10, x11 ld x10, 0(sp) ld x11, 8(sp) csrrw sp, sscratch, sp
まだ物理レジスタのソーティングの機能を持たせてはいないが、ISS側ではとりあえずちゃんと動いてはいるようだ。次はハードウェア側の調整だ。