LiteXは自分でSoC環境を構成することができるツール。自作CPUをSoCに組み込んでみたいので、今回はこれを試行してみる。
基本的にはlitex/soc/cores/cpu/mycpu/core.py
を変更するらしい。
- ファイルリストの作成。
filelist.vf
などからファイルを切り出して生成する。ファイルリストの作成というか、コンパイルする対象のファイルを全部抽出するという感じか。
def add_manifest_sources(platform, manifest): basedir = get_data_mod("cpu", "scariv").data_location with open(os.path.join(basedir, manifest), 'r') as f: for l in f: res = re.search('(.+)', l) if res and not re.match('//', l): if re.match('\+incdir\+', l): platform.add_verilog_include_path(os.path.join(basedir, res.group(1))) else: platform.add_source(os.path.join(basedir, "src", res.group(1)))
ソースコードの割り当ては以下のようにして呼び出す。自動生成したデコードファイルなどもここに入れ込んでいる。
# Add Verilog sources. # TODO: use Flist.cv64a6_imafdc_sv39 and Flist.cv32a6_imac_sv0 instead basedir = get_data_mod("cpu", "scariv").data_location platform.add_source(os.path.join(basedir, "src", "riscv_common_pkg.sv")) platform.add_source(os.path.join(basedir, "src", "riscv_fpu_imafdc_pkg.sv")) platform.add_source(os.path.join(basedir, "src", "riscv64_pkg.sv")) platform.add_source(os.path.join(basedir, "src", "scariv_standard_conf_pkg.sv")) add_manifest_sources(platform, "src/fpnew.vf") add_manifest_sources(platform, "src/filelist.vf") platform.add_verilog_include_path(os.path.join(basedir, "src", "fpnew", "src", "common_cells", "include")) platform.add_source(os.path.join(basedir, "src", "decoder_inst_cat.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_alu_ctrl.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_lsu_ctrl.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_bru_ctrl.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_csu_ctrl.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_fpu_ctrl.sv")) platform.add_source(os.path.join(basedir, "src", "decoder_reg.sv")) platform.add_source(os.path.join(basedir, "src", "pma_map.sv"))
この自動生成ファイルは、実行前にmake
を呼び出してリポジトリに対して生成コマンドを実行している。
def do_finalize(self): assert hasattr(self, "reset_address") basedir = get_data_mod("cpu", "scariv").data_location subprocess.check_call("make -C {basedir}/verilator_sim .config_design_xlen64_flen64".format( basedir = basedir),
インタフェースの接続は以下のようになっている。AXIに対して接続する。Outputは接頭語としてo_
を、Inputは接頭語としてi_
をつけるらしい。これはVerilog生成時に自動的に切り取られる。
# CPU Instance. self.cpu_params = dict( # Clk / Rst. i_i_clk = ClockSignal("sys"), i_i_reset_n = ~ResetSignal("sys") | self.reset, # # Interrupts # i_irq_sources = self.interrupt, # AXI interface. o_o_l1d_req_valid = axi_if.ar.valid, o_o_l1d_req_addr = axi_if.ar.addr, o_o_l1d_req_tag = axi_if.ar.id, i_i_l1d_req_ready = axi_if.ar.ready, i_i_l1d_resp_valid = axi_if.r.valid, i_i_l1d_resp_tag = axi_if.r.id, i_i_l1d_resp_data = axi_if.r.data, o_o_l1d_resp_ready = axi_if.r.ready, o_o_ic_req_valid = axi_fetch_if.ar.valid, i_i_ic_req_ready = axi_fetch_if.ar.ready, o_o_ic_req_tag = axi_fetch_if.ar.id, o_o_ic_req_addr = axi_fetch_if.ar.addr, )
一応これで実行コンパイルまで進めるようになったが、今度は各種defineをどのように指定すればいいのかが分からない。というかLiteXのコマンドがどの場所を通じてVerilatorを呼び出していいるのかよく分からないので、どうやって生成しているのかは正直よく分からない。