Chiselを使ったDiplomacyのデザイン作成、今回はあまりDiplomacyは関係なく、ELFファイルをロードしてメモリに書き込むためのプログラムを作成する。
ELFをロードして解析するプログラムはC++製のものを前に作ったものから取り寄せてきた。ELFをロードするプログラムは昔からちょっと複雑なものを使用しているので、もう少し簡単なライブラリみたいなものを用意しておきたい。
ELFをロードした後、肝になるのがどのようにしてメモリに転送するのかという話だが、1サイクル後としかデータを転送できないので、1サイクルごとに起動させるdebug_tick()
を使って、この関数が呼び出されるたびにアドレスを進めながらELFの中身を書きだしていくしかない。
その結果以下のようなあまり格好の良くないプログラムが完成してしまった。
extern "C" int debug_tick( unsigned char *debug_req_valid, unsigned char debug_req_ready, int *debug_req_bits_addr, int *debug_req_bits_data) { if (!elf_loaded) { m_memory = std::unique_ptr<Memory> (new Memory ()); m_func_table = std::unique_ptr<FunctionTable> (new FunctionTable ()); m_gvar_table = std::unique_ptr<VariableTable> (new VariableTable ()); LoadBinary("", "/home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple", true); elf_loaded = true; } auto m_memory_ptr = m_memory.get(); static auto m_it = m_memory_ptr->GetIterBegin(); static Addr_t addr = 0; if (debug_req_ready && (m_it != m_memory_ptr->GetIterEnd() && addr < m_it->second->GetBlockSize())) { uint32_t data = 0; for (int i = 0; i < 4; i++) { uint8_t byte = m_it->second->ReadByte (static_cast<Addr_t>(addr + i)); data = data << 8 | byte; } *debug_req_valid = 1; *debug_req_bits_addr = addr + m_it->second->GetBaseAddr(); *debug_req_bits_data = data; addr += 4; if (addr >= m_it->second->GetBlockSize() && m_it != m_memory_ptr->GetIterEnd()) { m_it ++; addr = 0; } } else { *debug_req_valid = 0; *debug_req_bits_addr = 0; *debug_req_bits_data = 0; } return 0; }
static
を多用して前の値を保持し、関数が呼び出されるたびにアドレスを進めている。4バイト毎にデータを作成してロード用のパスに流し込み、TileLinkに変換してもらってメモリに転送している。
この挙動を波形で確認すると以下のようになった。DTMからメモリに書き込むべき値が転送され、TileLinkのプロトコルに変換されてメモリに書き込んでいる。