前回で、CPUの汎用レジスタやシステムレジスタなどの部分において情報を保存する機能は実装した。 次に、メモリの情報について保存する機能について考えていく。
基本的には前回の記事でも書いたように、メモリのストアされた部分だけが情報として残っているので、それをダンプしていくだけでよい。 また、リストアするときはそのダンプした結果を読み込み、メモリに逐次書き込んでいくだけで良い。
自作ISSのメモリの構造について
本自作ISSでは、メモリはある固まったブロックを複数マップとして持つ構造になっており、 マップの先頭はベースアドレス、内容はメモリブロックそのもの、としている。 メモリブロックは0x1000バイトのメモリとなっており、そのに書き込みを行ったり、読み込みを行ったりする。 またストアしたい場所にメモリブロックが定義されていなければ、洗たに0x1000バイトのメモリブロックを定義し、書き込みを行う。 ロードしたい場所にメモリブロックが存在しなければ、それは不定領域からのロードということになる。
map - <Base=0x0000> : 00, 01, 00, 00, AC ... // 0x1000バイト分 - <Base=0xA000> : EF, FF, A5, 53, 91 ... - <Base=0x0200> : 00, 09, 8C, 3D, 11 ... ...
メモリのセーブ
メモリ内容をセーブするためには、以下のように、このmapの内容を全てファイルに書き出しておけば良い。
void Memory::DumpMemory (std::ofstream *ofs) { std::map<Addr_t, std::unique_ptr<MemoryBlock>>::iterator it = m_memory_vec.begin (); while (it != m_memory_vec.end()) { (*ofs) << std::hex << (*it).first << '\n'; for (Addr_t addr = 0; addr < ((*it).second)->GetBlockSize (); addr++) { (*ofs) << std::setw(2) << static_cast<int>(((*it).second)->ReadByte(addr)) << ' '; if ((addr % 16) == (16-1)) { (*ofs) << '\n'; } } it++; } }
メモリのリストア
メモリの内容をリストアするためには、上記の書き込んだファイルを呼び込み、ベースアドレスから算出したアドレスに対してデータをストアして行けば良い。
void Memory::RestoreMemory (std::ifstream *ifs) { while (!ifs->eof()) { Addr_t base_memory_addr; (*ifs) >> std::hex >> base_memory_addr; for (Addr_t i = 0; i < 0x1000ULL; i++) { int mem_data; (*ifs) >> std::hex >> mem_data; uint8_t u_data = static_cast<uint8_t>(mem_data); StoreMemByte (base_memory_addr, &u_data); base_memory_addr++; } } return; }
検証
Coremarkを動作させ、65535命令目で実行を止めてセーブした。
$ cat init.lua riscv = make_core ("risc-v") -- set_pcbreak (riscv, get_addr(riscv, "main")) skip_hier (riscv, "ee_printf") skip_hier (riscv, "cmp_complex") run (riscv) save_session (riscv, "session.log") $ ./swimmer_riscv --binfile ../benchmarks/releases/coremark_v1.0_riscv_gcc49_O2/coremark.bin --script init.lua --debug --out coremark.init.log
次にsession.logに保存されたセッションを復元し、再びCoremarkの実行を再開した。
$ cat restore.lua riscv = make_core ("risc-v") -- set_pcbreak (riscv, get_addr(riscv, "main")) restore_session (riscv, "session.log") run (riscv) $ ./swimmer_riscv --binfile ../benchmarks/releases/coremark_v1.0_riscv_gcc49_O2/coremark.bin --script restore.lua --debug --out coremark.restore.log --max 100000 --reg_abi soft
最後までCoremarkが完走したことを確認できた。実装は成功だ。