FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LiteXによるSoC環境構築を試行する (4. 自作CPUのコンフィグレーション追加試行)

https://raw.githubusercontent.com/enjoy-digital/litex/master/doc/litex.png

LiteXは自分でSoC環境を構成することができるツール。自作CPUをSoCに組み込んでみたいので、今回はこれを試行してみる。

github.com

基本的には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を呼び出していいるのかよく分からないので、どうやって生成しているのかは正直よく分からない。