久しぶりになってしまった自作命令セットシミュレータのベクトル命令サポート。少し時間があるので再挑戦する。
前回、全命令のデコーダを生成したのだが、全命令ではなかった。ロードストア命令が抜けている。今回はロードストア命令の内基本的なものを作っていく。
RVV0.9のベクトル命令は仕様が変わっており、byte/halfword/wordという言葉が取り払われており、vle8.v, vle16.v, ...
などという名称に変更されている。JSONのデコーダテンプレートを以下のように生成した。
/* MEMORY ACCESS */ {"name":"vle8.v v[11:7],(r[19:15]),vm[25]", "length":"32", "dlength":"128", "field": ["00000", "0X", "XXXXX", "XXXXX", "000", "XXXXX", "00001", "11"], "category":"VEC", "func_suffix":"", "impl":[""], "inst_ctrl":[""]}, {"name":"vlse8.v v[11:7],(r[19:15]),r[24:20],vm[25]", "length":"32", "dlength":"128", "field": ["00001", "0X", "XXXXX", "XXXXX", "000", "XXXXX", "00001", "11"], "category":"VEC", "func_suffix":"", "impl":[""], "inst_ctrl":[""]}, {"name":"vlxei8.v v[11:7],(r[19:15]),v[24:20],vm[25]", "length":"32", "dlength":"128", "field": ["00001", "1X", "XXXXX", "XXXXX", "000", "XXXXX", "00001", "11"], "category":"VEC", "func_suffix":"", "impl":[""], "inst_ctrl":[""]}, {"name":"vse8.v v[11:7],(r[19:15]),vm[25]", "length":"32", "dlength":"128", "field": ["00000", "0X", "XXXXX", "XXXXX", "000", "XXXXX", "01001", "11"], "category":"VEC", "func_suffix":"", "impl":[""], "inst_ctrl":[""]}, {"name":"vsuxei8.v v[11:7],(r[19:15]),v[24:20],vm[25]", "length":"32", "dlength":"128", "field": ["00000", "1X", "XXXXX", "XXXXX", "000", "XXXXX", "01001", "11"], "category":"VEC", "func_suffix":"", "impl":[""], "inst_ctrl":[""]}, ...
命令を定義してビルドするとデコーダが追加されるので、命令を実装していく。
swimmer_riscv/src/inst_riscv_vector.cpp
void InstEnv::RISCV_INST_VLSE8_V(InstWord_t inst_hex) {} void InstEnv::RISCV_INST_VLXEI8_V(InstWord_t inst_hex) {} void InstEnv::RISCV_INST_VSE8_V(InstWord_t inst_hex) {} void InstEnv::RISCV_INST_VSUXEI8_V(InstWord_t inst_hex) {} void InstEnv::RISCV_INST_VSSE8_V(InstWord_t inst_hex) {} void InstEnv::RISCV_INST_VSXEI8_V(InstWord_t inst_hex) {} ...
例えばvle8.v
を実装する場合、以下のことを注意する必要がありそうだ。
- スキップする要素。
vstart
までのベクトル要素は処理をスキップする。ロード命令でもi < vstart
の部分はロードしない。 - マスクの処理。マスクレジスタのビットフィールドは、ベクトル要素に対して1ビットずつ隣接して割り当てられている。
以上を考慮して、とりあえず処理をコピペして並べる。
void InstEnv::RISCV_INST_VLE8_V(InstWord_t inst_hex) { if (!m_pe_thread->IsVECAvailable ()) { m_pe_thread->GenerateException (ExceptCode::Except_IllegalInst, 0); return; } const RegAddr_t rs1_addr = ExtractR1Field (inst_hex); const RegAddr_t vd_addr = ExtractRDField (inst_hex); Addr_t mem_base_addr = m_pe_thread->ReadGReg<DWord_t> (rs1_addr); const uint8_t nf = 0; Word_t vl; m_pe_thread->CSRRead (static_cast<Addr_t>(SYSREG_ADDR_VL), &vl); bool vm = ExtractBitField(inst_hex, 25, 25); Word_t vstart; m_pe_thread->CSRRead (static_cast<Addr_t>(SYSREG_ADDR_VSTART), &vstart); for (int i = vstart; i < vl; i++) { if (vm == 0) { const int midx = i / 8; const int mpos = i % 8; bool skip = ((m_pe_thread->ReadVReg<uint8_t>(0, midx) >> mpos) & 0x1) == 0; if (skip) { continue; } } Addr_t mem_addr = mem_base_addr + i * 8; Byte_t res; MemResult except = m_pe_thread->LoadFromBus (mem_addr, &res); if (except == MemResult::MemMisAlign) { m_pe_thread->CSRWrite (static_cast<Addr_t>(SYSREG_ADDR_VSTART), i); m_pe_thread->GenerateException (ExceptCode::Except_LoadAddrMisalign, mem_addr); return; } if (except == MemResult::MemTlbError) { m_pe_thread->CSRWrite (static_cast<Addr_t>(SYSREG_ADDR_VSTART), i); m_pe_thread->GenerateException (ExceptCode::Except_LoadPageFault, mem_addr); return; } if (except == MemResult::MemNotDefined) { m_pe_thread->CSRWrite (static_cast<Addr_t>(SYSREG_ADDR_VSTART), i); m_pe_thread->GenerateException (ExceptCode::Except_LoadAccessFault, mem_addr); return; } m_pe_thread->WriteVReg (vd_addr, i, res); } }
こんな感じかな。ただしこれではベクトル要素分ログが出てきてとんでもなく読みにくい命令ログになる。少しやり方を考えなければ...