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