FPGA開発日記

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

LiteXによるSoC環境構築を試行する (割込み挿入方法)

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

LiteXの続き。LiteXでどうにかBIOSを立ち上げることができるようになったが、次はキーボードの入力が受け付けられない。 これはおそらく割込みをまじめに接続していないことだろう。LiteXのほかのデザインはどうだろうか?

まずはRocketの実装とVexRiscVの実装を見てみる。

  • Rocketの場合
        self.cpu_params = dict(
            # Clk / Rst.
            i_clock = ClockSignal("sys"),
            i_reset = ResetSignal("sys") | self.reset,

            # Debug (ignored).
            i_debug_clock                         = 0,
            i_debug_reset                         = ResetSignal() | self.reset,
            o_debug_clockeddmi_dmi_req_ready      = Open(),
            i_debug_clockeddmi_dmi_req_valid      = 0,
            i_debug_clockeddmi_dmi_req_bits_addr  = 0,
            i_debug_clockeddmi_dmi_req_bits_data  = 0,
            i_debug_clockeddmi_dmi_req_bits_op    = 0,
            i_debug_clockeddmi_dmi_resp_ready     = 0,
            o_debug_clockeddmi_dmi_resp_valid     = Open(),
            o_debug_clockeddmi_dmi_resp_bits_data = Open(),
            o_debug_clockeddmi_dmi_resp_bits_resp = Open(),
            i_debug_clockeddmi_dmiClock           = 0,
            i_debug_clockeddmi_dmiReset           = ResetSignal() | self.reset,
            o_debug_ndreset                       = Open(),
            o_debug_dmactive                      = Open(),
            i_debug_dmactiveAck                   = 0,

            # IRQ.
            i_interrupts = self.interrupt,
  • VexRiscVの場合
        # CPU Instance.
        self.cpu_params = dict(
            i_clk                    = ClockSignal("sys"),
            i_reset                  = ResetSignal("sys") | self.reset,

            i_externalInterruptArray = self.interrupt,
            i_timerInterrupt         = 0,
            i_softwareInterrupt      = 0,

Interruptという信号を接続しているようだ。これは元をたどれば、タイマーとUARTに接続されているようだ。

always @(*) begin
    main_interrupt <= 32'd0;
    main_interrupt[1] <= main_timer_irq;
    main_interrupt[0] <= main_uart_irq;
end

さらにこれをPLICに接続することが前提のようだ。Rocket側の実装を追いかけると、PLICのラッパーに接続されているようだ。

  ClockSinkDomain plicDomainWrapper ( // @[Plic.scala 359:39]
    .auto_plic_int_in_0(plicDomainWrapper_auto_plic_int_in_0),
    .auto_plic_int_in_1(plicDomainWrapper_auto_plic_int_in_1),
    .auto_plic_int_in_2(plicDomainWrapper_auto_plic_int_in_2),
    .auto_plic_int_in_3(plicDomainWrapper_auto_plic_int_in_3),
    .auto_plic_int_in_4(plicDomainWrapper_auto_plic_int_in_4),
    .auto_plic_int_in_5(plicDomainWrapper_auto_plic_int_in_5),
    .auto_plic_int_in_6(plicDomainWrapper_auto_plic_int_in_6),
    .auto_plic_int_in_7(plicDomainWrapper_auto_plic_int_in_7),
    .auto_plic_int_out_0(plicDomainWrapper_auto_plic_int_out_0),
    .auto_plic_in_a_ready(plicDomainWrapper_auto_plic_in_a_ready),
    .auto_plic_in_a_valid(plicDomainWrapper_auto_plic_in_a_valid),
    .auto_plic_in_a_bits_opcode(plicDomainWrapper_auto_plic_in_a_bits_opcode),
    .auto_plic_in_a_bits_param(plicDomainWrapper_auto_plic_in_a_bits_param),
    .auto_plic_in_a_bits_size(plicDomainWrapper_auto_plic_in_a_bits_size),
    .auto_plic_in_a_bits_source(plicDomainWrapper_auto_plic_in_a_bits_source),
    .auto_plic_in_a_bits_address(plicDomainWrapper_auto_plic_in_a_bits_address),
    .auto_plic_in_a_bits_mask(plicDomainWrapper_auto_plic_in_a_bits_mask),
    .auto_plic_in_a_bits_data(plicDomainWrapper_auto_plic_in_a_bits_data),
    .auto_plic_in_a_bits_corrupt(plicDomainWrapper_auto_plic_in_a_bits_corrupt),
    .auto_plic_in_d_ready(plicDomainWrapper_auto_plic_in_d_ready),
    .auto_plic_in_d_valid(plicDomainWrapper_auto_plic_in_d_valid),
    .auto_plic_in_d_bits_opcode(plicDomainWrapper_auto_plic_in_d_bits_opcode),
    .auto_plic_in_d_bits_size(plicDomainWrapper_auto_plic_in_d_bits_size),
    .auto_plic_in_d_bits_source(plicDomainWrapper_auto_plic_in_d_bits_source),
    .auto_plic_in_d_bits_data(plicDomainWrapper_auto_plic_in_d_bits_data),
    .auto_clock_in_clock(plicDomainWrapper_auto_clock_in_clock),
    .auto_clock_in_reset(plicDomainWrapper_auto_clock_in_reset)
  );

VexRiscVの場合は、直接MEIPに接続されるようになっている。ちょっと強引かな。

    CsrPlugin_mip_MEIP <= externalInterrupt;
    CsrPlugin_mip_MTIP <= timerInterrupt;
    CsrPlugin_mip_MSIP <= softwareInterrupt;

PLICの実装は、どこからかオープンソースのものを取ってこようと思う。

github.com