FPGA開発日記

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

QEMUに入門してみる(20. CSRレジスタの追加)

QEMU実装の続き。CSR命令の実装が足りていないので、いくつか主要なものを実装していく。現時点ではmhartidしか実装していないので追加していく。csr.cにはCSR命令追加のテンプレートが用意されているのでこれを使っていく。

  • qemu/target/myriscvx/csr.c
/* Control and Status Register function table */
static myriscvx_csr_operations csr_ops[CSR_TABLE_SIZE] = {
    /* Machine Information Registers */
    [CSR_MVENDORID] =           { any,  read_zero                           },
    [CSR_MARCHID] =             { any,  read_zero                           },
    [CSR_MIMPID] =              { any,  read_zero                           },
    [CSR_MHARTID] =             { any,  read_mhartid                        },

    /* Machine Trap Setup */
    [CSR_MSTATUS] =             { any,  read_mstatus,     write_mstatus     },
    [CSR_MISA] =                { any,  read_misa,        write_misa        },
    [CSR_MIDELEG] =             { any,  read_mideleg,     write_mideleg     },
    [CSR_MEDELEG] =             { any,  read_medeleg,     write_medeleg     },
    [CSR_MIE] =                 { any,  read_mie,         write_mie         },
    [CSR_MTVEC] =               { any,  read_mtvec,       write_mtvec       }
};

CSR読み込み用と、CSR書き込み用のコードが用意されている。

  • qemu/target/myriscvx/csr.c
static int read_mstatus(CPUMYRISCVXState *env, int csrno, target_ulong *val)
{
  *val = env->mstatus;
  return 0;
}
static int write_mstatus(CPUMYRISCVXState *env, int csrno, target_ulong val)
{
  target_ulong mstatus = env->mstatus;
  target_ulong mask = 0;
  int dirty;

  /* flush tlb on mstatus fields that affect VM */
  if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
                         MSTATUS_MPRV | MSTATUS_SUM)) {
    tlb_flush(env_cpu(env));
  }
  mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
    MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
    MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
    MSTATUS_TW;
#if defined(TARGET_RISCV64)
  /*
   * RV32: MPV and MTL are not in mstatus. The current plan is to
   * add them to mstatush. For now, we just don't support it.
   */
  mask |= MSTATUS_MTL | MSTATUS_MPV;
#endif

  mstatus = (mstatus & ~mask) | (val & mask);

  dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
    ((mstatus & MSTATUS_XS) == MSTATUS_XS);
  mstatus = set_field(mstatus, MSTATUS_SD, dirty);
  env->mstatus = mstatus;

  return 0;
}

とりあえずMYRISCVXの実装にそれらを追加していく。RISC-Vの実装からとりあえずパクってくることにした。

これらのCSR命令の操作はmyriscvx_csrrw()から呼び出される。

int myriscvx_csrrw(CPUMYRISCVXState *env, int csrno, target_ulong *ret_value,
                   target_ulong new_value, target_ulong write_mask)
{
  int ret;
  target_ulong old_value;
...
  /* execute combined read/write operation if it exists */
  if (csr_ops[csrno].op) {
    return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask);
  }

  /* if no accessor exists then return failure */
  if (!csr_ops[csrno].read) {
    return -1;
  }

  /* read old value */
  ret = csr_ops[csrno].read(env, csrno, &old_value);
  if (ret < 0) {
    return ret;
  }
  ....

ここまででさらにテストベクタが進むようになった。次はシフト演算命令かな?

IN:
Priv: 3; Virt: 0
0x00000000800000a8:  00100513          addi            a0,zero,1
0x00000000800000ac:  01f51513          slli            a0,a0,31

19397@1595696172.703149:myriscvx_trap hart:0, async:0, cause:2, epc:0x800000ac, tval:0x0, desc=illegal_instruction
----------------
IN:
Priv: 3; Virt: 0
0x0000000080000004:  34202f73          csrrs           t5,mcause,zero

19397@1595696172.703218:myriscvx_trap hart:0, async:0, cause:2, epc:0x80000004, tval:0x0, desc=illegal_instruction
19397@1595696172.703246:myriscvx_trap hart:0, async:0, cause:2, epc:0x80000004, tval:0x0, desc=illegal_instruction
19397@1595696172.703253:myriscvx_trap hart:0, async:0, cause:2, epc:0x80000004, tval:0x0, desc=illegal_instruction
19397@1595696172.703259:myriscvx_trap hart:0, async:0, cause:2, epc:0x80000004, tval:0x0, desc=illegal_instruction
19397@1595696172.703265:myriscvx_trap hart:0, async:0, cause:2, epc:0x80000004, tval:0x0, desc=illegal_instruction