diff mbox

[13/18] target-riscv: Add CSR read/write helpers

Message ID dbcda0e1c2c27b5f3a7cd12a3a72b4ae1fe6cf4b.1474886798.git.sagark@eecs.berkeley.edu
State New
Headers show

Commit Message

Sagar Karandikar Sept. 26, 2016, 10:56 a.m. UTC
Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/op_helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)
diff mbox

Patch

diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index ee51f02..8449d1b 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -39,6 +39,11 @@  void set_privilege(CPURISCVState *env, target_ulong newpriv)
     env->priv = newpriv;
 }
 
+static int validate_vm(target_ulong vm)
+{
+    return vm == VM_SV32 || vm == VM_SV39 || vm == VM_SV48 || vm == VM_MBARE;
+}
+
 /* Exceptions processing helpers */
 static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
                                           uint32_t exception, uintptr_t pc)
@@ -83,6 +88,180 @@  target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
 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
+
+    uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_COP);
+    uint64_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
+
+    switch (csrno) {
+    case CSR_FFLAGS:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FFLAGS] = val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT);
+        break;
+    case CSR_FRM:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FRM] = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
+        break;
+    case CSR_FCSR:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FFLAGS] = (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT;
+        env->csr[CSR_FRM] = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
+        break;
+    case CSR_MSTATUS: {
+        target_ulong mstatus = env->csr[CSR_MSTATUS];
+        if ((val_to_write ^ mstatus) &
+            (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM |
+             MSTATUS_MXR)) {
+            helper_tlb_flush(env);
+        }
+
+        /* no extension support */
+        target_ulong mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE
+            | MSTATUS_MPIE | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV
+            | MSTATUS_PUM | MSTATUS_MXR;
+
+        if (validate_vm(get_field(val_to_write, MSTATUS_VM))) {
+            mask |= MSTATUS_VM;
+        }
+        if (validate_priv(get_field(val_to_write, MSTATUS_MPP))) {
+            mask |= MSTATUS_MPP;
+        }
+
+        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[CSR_MSTATUS] = mstatus;
+        break;
+    }
+    case CSR_MIP: {
+        target_ulong mask = MIP_SSIP | MIP_STIP;
+        env->csr[CSR_MIP] = (env->csr[CSR_MIP] & ~mask) |
+            (val_to_write & mask);
+        if (env->csr[CSR_MIP] & MIP_SSIP) {
+            qemu_irq_raise(SSIP_IRQ);
+        } else {
+            qemu_irq_lower(SSIP_IRQ);
+        }
+        if (env->csr[CSR_MIP] & MIP_STIP) {
+            qemu_irq_raise(STIP_IRQ);
+        } else {
+            qemu_irq_lower(STIP_IRQ);
+        }
+        if (env->csr[CSR_MIP] & MIP_MSIP) {
+            qemu_irq_raise(MSIP_IRQ);
+        } else {
+            qemu_irq_lower(MSIP_IRQ);
+        }
+        break;
+    }
+    case CSR_MIE: {
+        env->csr[CSR_MIE] = (env->csr[CSR_MIE] & ~all_ints) |
+            (val_to_write & all_ints);
+        break;
+    }
+    case CSR_MIDELEG:
+        env->csr[CSR_MIDELEG] = (env->csr[CSR_MIDELEG] & ~delegable_ints)
+                                | (val_to_write & delegable_ints);
+        break;
+    case CSR_MEDELEG: {
+        target_ulong mask = 0;
+        mask |= 1ULL << (RISCV_EXCP_INST_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_ILLEGAL_INST);
+        mask |= 1ULL << (RISCV_EXCP_BREAKPOINT);
+        mask |= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_U_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_S_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_H_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_M_ECALL);
+        env->csr[CSR_MEDELEG] = (env->csr[CSR_MEDELEG] & ~mask)
+                                | (val_to_write & mask);
+        break;
+    }
+    case CSR_MUCOUNTEREN:
+        env->csr[CSR_MUCOUNTEREN] = val_to_write & 7;
+        break;
+    case CSR_MSCOUNTEREN:
+        env->csr[CSR_MSCOUNTEREN] = val_to_write & 7;
+        break;
+    case CSR_SSTATUS: {
+        target_ulong ms = env->csr[CSR_MSTATUS];
+        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP
+                            | SSTATUS_FS | SSTATUS_XS | SSTATUS_PUM;
+        ms = (ms & ~mask) | (val_to_write & mask);
+        csr_write_helper(env, ms, CSR_MSTATUS);
+        break;
+    }
+    case CSR_SIP: {
+        target_ulong next_mip = (env->csr[CSR_MIP] & ~env->csr[CSR_MIDELEG])
+                                | (val_to_write & env->csr[CSR_MIDELEG]);
+        csr_write_helper(env, next_mip, CSR_MIP);
+        /* note: stw_phys should be done by the call to set MIP if necessary, */
+        /* so we don't do it here */
+        break;
+    }
+    case CSR_SIE: {
+        target_ulong next_mie = (env->csr[CSR_MIE] & ~env->csr[CSR_MIDELEG])
+                                | (val_to_write & env->csr[CSR_MIDELEG]);
+        csr_write_helper(env, next_mie, CSR_MIE);
+        break;
+    }
+    case CSR_SPTBR: {
+        env->csr[CSR_SPTBR] = val_to_write & (((target_ulong)1 <<
+                              (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
+        break;
+    }
+    case CSR_SEPC:
+        env->csr[CSR_SEPC] = val_to_write;
+        break;
+    case CSR_STVEC:
+        env->csr[CSR_STVEC] = val_to_write >> 2 << 2;
+        break;
+    case CSR_SSCRATCH:
+        env->csr[CSR_SSCRATCH] = val_to_write;
+        break;
+    case CSR_SCAUSE:
+        env->csr[CSR_SCAUSE] = val_to_write;
+        break;
+    case CSR_SBADADDR:
+        env->csr[CSR_SBADADDR] = val_to_write;
+        break;
+    case CSR_MEPC:
+        env->csr[CSR_MEPC] = val_to_write;
+        break;
+    case CSR_MTVEC:
+        env->csr[CSR_MTVEC] = val_to_write >> 2 << 2;
+        break;
+    case CSR_MSCRATCH:
+        env->csr[CSR_MSCRATCH] = val_to_write;
+        break;
+    case CSR_MCAUSE:
+        env->csr[CSR_MCAUSE] = val_to_write;
+        break;
+    case CSR_MBADADDR:
+        env->csr[CSR_MBADADDR] = val_to_write;
+        break;
+    case CSR_DCSR:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    case CSR_DPC:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    case CSR_DSCRATCH:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    }
 }
 
 /*
@@ -92,6 +271,151 @@  inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
  */
 inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
 {
+    int csrno2 = (int)csrno;
+    #ifdef RISCV_DEBUG_PRINT
+    fprintf(stderr, "READ CSR 0x%x\n", csrno2);
+    #endif
+
+    switch (csrno2) {
+    case CSR_FFLAGS:
+        return env->csr[CSR_FFLAGS];
+    case CSR_FRM:
+        return env->csr[CSR_FRM];
+    case CSR_FCSR:
+        return env->csr[CSR_FFLAGS] << FSR_AEXC_SHIFT |
+               env->csr[CSR_FRM] << FSR_RD_SHIFT;
+    case CSR_TIME:
+    case CSR_INSTRET:
+    case CSR_CYCLE:
+        if ((env->csr[CSR_MUCOUNTEREN] >> (csrno2 & (63))) & 1) {
+            return csr_read_helper(env, csrno2 + (CSR_MCYCLE - CSR_CYCLE));
+        }
+        break;
+    case CSR_STIME:
+    case CSR_SINSTRET:
+    case CSR_SCYCLE:
+        if ((env->csr[CSR_MSCOUNTEREN] >> (csrno2 & (63))) & 1) {
+            return csr_read_helper(env, csrno2 + (CSR_MCYCLE - CSR_SCYCLE));
+        }
+        break;
+    case CSR_MUCOUNTEREN:
+        return env->csr[CSR_MUCOUNTEREN];
+    case CSR_MSCOUNTEREN:
+        return env->csr[CSR_MSCOUNTEREN];
+    case CSR_MUCYCLE_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUTIME_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUINSTRET_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSCYCLE_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSTIME_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSINSTRET_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUCYCLE_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MUTIME_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MUINSTRET_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSCYCLE_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSTIME_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSINSTRET_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    /* notice the lack of CSR_MTIME - this is handled by throwing an exception
+       and letting the handler read from the RTC */
+    case CSR_MCYCLE:
+        /* Read instret here */
+        break;
+    case CSR_MINSTRET:
+        /* Read instret here */
+        break;
+    case CSR_MCYCLEH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MINSTRETH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_SSTATUS: {
+        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP
+                            | SSTATUS_FS | SSTATUS_XS | SSTATUS_PUM;
+        target_ulong sstatus = env->csr[CSR_MSTATUS] & mask;
+        if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
+                (sstatus & SSTATUS_XS) == SSTATUS_XS) {
+            sstatus |= SSTATUS64_SD;
+        }
+        return sstatus;
+    }
+    case CSR_SIP:
+        return env->csr[CSR_MIP] & env->csr[CSR_MIDELEG];
+    case CSR_SIE:
+        return env->csr[CSR_MIE] & env->csr[CSR_MIDELEG];
+    case CSR_SEPC:
+        return env->csr[CSR_SEPC];
+    case CSR_SBADADDR:
+        return env->csr[CSR_SBADADDR];
+    case CSR_STVEC:
+        return env->csr[CSR_STVEC];
+    case CSR_SCAUSE:
+        return env->csr[CSR_SCAUSE];
+    case CSR_SPTBR:
+        return env->csr[CSR_SPTBR];
+    case CSR_SSCRATCH:
+        return env->csr[CSR_SSCRATCH];
+    case CSR_MSTATUS:
+        return env->csr[CSR_MSTATUS];
+    case CSR_MIP:
+        return env->csr[CSR_MIP];
+    case CSR_MIE:
+        return env->csr[CSR_MIE];
+    case CSR_MEPC:
+        return env->csr[CSR_MEPC];
+    case CSR_MSCRATCH:
+        return env->csr[CSR_MSCRATCH];
+    case CSR_MCAUSE:
+        return env->csr[CSR_MCAUSE];
+    case CSR_MBADADDR:
+        return env->csr[CSR_MBADADDR];
+    case CSR_MISA:
+        return env->csr[CSR_MISA];
+    case CSR_MARCHID:
+        return 0; /* as spike does */
+    case CSR_MIMPID:
+        return 0; /* as spike does */
+    case CSR_MVENDORID:
+        return 0; /* as spike does */
+    case CSR_MHARTID:
+        return 0;
+    case CSR_MTVEC:
+        return env->csr[CSR_MTVEC];
+    case CSR_MEDELEG:
+        return env->csr[CSR_MEDELEG];
+    case CSR_MIDELEG:
+        return env->csr[CSR_MIDELEG];
+    case CSR_TDRSELECT:
+        return 0; /* as spike does */
+    case CSR_DCSR:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    case CSR_DPC:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    case CSR_DSCRATCH:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    }
+    /* used by e.g. MTIME read */
+    helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST);
     return 0;
 }