target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, target_ulong csr, target_ulong new_pc) { validate_csr(env, csr, 1, new_pc); uint64_t csr_backup = csr_read_helper(env, csr); csr_write_helper(env, (~src) & csr_backup, csr); return csr_backup; }
target_ulong helper_mrts(CPURISCVState *env, target_ulong curr_pc) { target_ulong mstatus = env->csr[NEW_CSR_MSTATUS]; if(!(get_field(mstatus, MSTATUS_PRV) >= PRV_M)) { // TODO: real illegal instruction trap printf("ILLEGAL INST"); exit(1); } csr_write_helper(env, set_field(mstatus, MSTATUS_PRV, PRV_S), NEW_CSR_MSTATUS); env->csr[NEW_CSR_SBADADDR] = env->csr[NEW_CSR_MBADADDR]; env->csr[NEW_CSR_SCAUSE] = env->csr[NEW_CSR_MCAUSE]; env->csr[NEW_CSR_SEPC] = env->csr[NEW_CSR_MEPC]; if (env->csr[NEW_CSR_STVEC] & 0x3) { helper_raise_exception_mbadaddr(env, NEW_RISCV_EXCP_INST_ADDR_MIS, curr_pc); return curr_pc; } return env->csr[NEW_CSR_STVEC]; }
target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) { target_ulong mstatus = env->csr[NEW_CSR_MSTATUS]; if(!(get_field(mstatus, MSTATUS_PRV) >= PRV_S)) { // TODO: real illegal instruction trap printf("ILLEGAL INST"); exit(1); } target_ulong retpc = 0; switch(get_field(mstatus, MSTATUS_PRV)) { case PRV_S: // set PC val to sepc retpc = env->csr[NEW_CSR_SEPC]; break; case PRV_M: // set PC val to mepc retpc = env->csr[NEW_CSR_MEPC]; break; default: // TODO: illegal inst printf("ILLEGAL INST"); exit(1); break; } if (retpc & 0x3) { // check for misaligned fetch helper_raise_exception_mbadaddr(env, NEW_RISCV_EXCP_INST_ADDR_MIS, cpu_pc_deb); return cpu_pc_deb; } target_ulong next_mstatus = pop_priv_stack(env->csr[NEW_CSR_MSTATUS]); csr_write_helper(env, next_mstatus, NEW_CSR_MSTATUS); return retpc; }
target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, target_ulong csr) { uint64_t csr_backup = csr_read_helper(env, csr); csr_write_helper(env, (~src) & csr_backup, csr); return csr_backup; }
/* * Handle writes to CSRs and any resulting special behavior * * Note: mtohost and mfromhost are not handled here */ inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, target_ulong csrno) { #ifdef RISCV_DEBUG_PRINT fprintf(stderr, "Write CSR reg: 0x" TARGET_FMT_lx "\n", csrno); fprintf(stderr, "Write CSR val: 0x" TARGET_FMT_lx "\n", val_to_write); #endif switch (csrno) { case NEW_CSR_FFLAGS: env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD; env->csr[NEW_CSR_FFLAGS] = val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT); break; case NEW_CSR_FRM: env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD; env->csr[NEW_CSR_FRM] = val_to_write & (FSR_RD >> FSR_RD_SHIFT); break; case NEW_CSR_FCSR: env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD; env->csr[NEW_CSR_FFLAGS] = (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT; env->csr[NEW_CSR_FRM] = (val_to_write & FSR_RD) >> FSR_RD_SHIFT; break; case NEW_CSR_MTIME: case NEW_CSR_STIMEW: // this implementation ignores writes to MTIME break; case NEW_CSR_MTIMEH: case NEW_CSR_STIMEHW: // this implementation ignores writes to MTIME break; case NEW_CSR_TIMEW: cpu_riscv_store_timew(env, val_to_write); break; case NEW_CSR_TIMEHW: fprintf(stderr, "CSR_TIMEHW unsupported on RV64I\n"); exit(1); break; case NEW_CSR_CYCLEW: case NEW_CSR_INSTRETW: cpu_riscv_store_instretw(env, val_to_write); break; case NEW_CSR_CYCLEHW: case NEW_CSR_INSTRETHW: fprintf(stderr, "CSR_CYCLEHW/INSTRETHW unsupported on RV64I\n"); exit(1); break; case NEW_CSR_MSTATUS: { target_ulong mstatus = env->csr[NEW_CSR_MSTATUS]; #ifdef RISCV_DEBUG_PRINT target_ulong debug_mstatus = mstatus; #endif if ((val_to_write ^ mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV)) { #ifdef RISCV_DEBUG_PRINT fprintf(stderr, "flushing TLB\n"); #endif helper_tlb_flush(env); } // no extension support target_ulong mask = MSTATUS_IE | MSTATUS_IE1 | MSTATUS_IE2 | MSTATUS_MPRV | MSTATUS_FS; if (validate_vm(get_field(val_to_write, MSTATUS_VM))) { mask |= MSTATUS_VM; } if (validate_priv(get_field(val_to_write, MSTATUS_PRV))) { mask |= MSTATUS_PRV; } if (validate_priv(get_field(val_to_write, MSTATUS_PRV1))) { mask |= MSTATUS_PRV1; } if (validate_priv(get_field(val_to_write, MSTATUS_PRV2))) { mask |= MSTATUS_PRV2; } mstatus = (mstatus & ~mask) | (val_to_write & mask); int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS; dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS; mstatus = set_field(mstatus, MSTATUS64_SD, dirty); env->csr[NEW_CSR_MSTATUS] = mstatus; break; } case NEW_CSR_MIP: { target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP; env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) | (val_to_write & mask); CPUState *cs = CPU(riscv_env_get_cpu(env)); if (env->csr[NEW_CSR_MIP] & MIP_SSIP) { stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1); } else { stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0); } if (env->csr[NEW_CSR_MIP] & MIP_STIP) { stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x1); } else { stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x0); } if (env->csr[NEW_CSR_MIP] & MIP_MSIP) { stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1); } else { stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0); } break; } case NEW_CSR_MIPI: { CPUState *cs = CPU(riscv_env_get_cpu(env)); env->csr[NEW_CSR_MIP] = set_field(env->csr[NEW_CSR_MIP], MIP_MSIP, val_to_write & 1); if (env->csr[NEW_CSR_MIP] & MIP_MSIP) { stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1); } else { stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0); } break; } case NEW_CSR_MIE: { target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP; env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) | (val_to_write & mask); break; } case NEW_CSR_SSTATUS: { target_ulong ms = env->csr[NEW_CSR_MSTATUS]; ms = set_field(ms, MSTATUS_IE, get_field(val_to_write, SSTATUS_IE)); ms = set_field(ms, MSTATUS_IE1, get_field(val_to_write, SSTATUS_PIE)); ms = set_field(ms, MSTATUS_PRV1, get_field(val_to_write, SSTATUS_PS)); ms = set_field(ms, MSTATUS_FS, get_field(val_to_write, SSTATUS_FS)); ms = set_field(ms, MSTATUS_XS, get_field(val_to_write, SSTATUS_XS)); ms = set_field(ms, MSTATUS_MPRV, get_field(val_to_write, SSTATUS_MPRV)); csr_write_helper(env, ms, NEW_CSR_MSTATUS); break; } case NEW_CSR_SIP: { target_ulong mask = MIP_SSIP; env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) | (val_to_write & mask); CPUState *cs = CPU(riscv_env_get_cpu(env)); if (env->csr[NEW_CSR_MIP] & MIP_SSIP) { stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1); } else { stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0); } break; } case NEW_CSR_SIE: { target_ulong mask = MIP_SSIP | MIP_STIP | MIP_SXIP; env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) | (val_to_write & mask); break; } case NEW_CSR_SEPC: env->csr[NEW_CSR_SEPC] = val_to_write; break; case NEW_CSR_STVEC: env->csr[NEW_CSR_STVEC] = val_to_write >> 2 << 2; break; case NEW_CSR_SPTBR: env->csr[NEW_CSR_SPTBR] = val_to_write & -(1L << PGSHIFT); break; case NEW_CSR_SSCRATCH: env->csr[NEW_CSR_SSCRATCH] = val_to_write; break; case NEW_CSR_MEPC: env->csr[NEW_CSR_MEPC] = val_to_write; break; case NEW_CSR_MSCRATCH: env->csr[NEW_CSR_MSCRATCH] = val_to_write; break; case NEW_CSR_MCAUSE: env->csr[NEW_CSR_MCAUSE] = val_to_write; break; case NEW_CSR_MBADADDR: env->csr[NEW_CSR_MBADADDR] = val_to_write; break; case NEW_CSR_MTIMECMP: // NOTE: clearing bit in MIP handled in cpu_riscv_store_compare cpu_riscv_store_compare(env, val_to_write); break; case NEW_CSR_MTOHOST: fprintf(stderr, "Write to mtohost should not be handled here\n"); exit(1); break; case NEW_CSR_MFROMHOST: fprintf(stderr, "Write to mfromhost should not be handled here\n"); exit(1); break; } }