data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv
1: b"%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:16: syntax error, unexpected IDENTIFIER, expecting PACKAGE-IDENTIFIER\nmodule csr_regfile import ariane_pkg::*; #(\n                          ^~~~~~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:18: syntax error, unexpected parameter, expecting IDENTIFIER\n    parameter int          AsidWidth       = 1,\n    ^~~~~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:19: syntax error, unexpected parameter, expecting IDENTIFIER\n    parameter int unsigned NrCommitPorts   = 2,\n    ^~~~~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:20: syntax error, unexpected parameter, expecting IDENTIFIER\n    parameter int unsigned NrPMPEntries    = 8\n    ^~~~~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:21: syntax error, unexpected ')', expecting ';'\n) (\n^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:23: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic                  rst_ni,                      \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:24: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic                  time_irq_i,                  \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:26: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  flush_o,\n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:27: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  halt_csr_o,                  \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:29: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  scoreboard_entry_t [NrCommitPorts-1:0] commit_instr_i,  \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:32: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic[riscv::VLEN-1:0] boot_addr_i,                 \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:32: syntax error, unexpected ::, expecting ':'\n    input  logic[riscv::VLEN-1:0] boot_addr_i,                 \n                      ^~\n                                                                                                               : ... Perhaps 'riscv' is a package which needs to be predeclared? (IEEE 1800-2017 26.3)\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:33: syntax error, unexpected ::, expecting ':'\n    input  logic[riscv::XLEN-1:0] hart_id_i,                   \n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:39: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic[riscv::XLEN-1:0] csr_wdata_i,                 \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:39: syntax error, unexpected ::, expecting ':'\n    input  logic[riscv::XLEN-1:0] csr_wdata_i,                 \n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:40: syntax error, unexpected ::, expecting ':'\n    output logic[riscv::XLEN-1:0] csr_rdata_o,                 \n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:42: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic                  csr_write_fflags_i,          \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:43: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic  [riscv::VLEN-1:0]  pc_i,                     \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:43: syntax error, unexpected ::, expecting ':'\n    input  logic  [riscv::VLEN-1:0]  pc_i,                     \n                        ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:48: syntax error, unexpected ::, expecting ':'\n    output logic  [riscv::VLEN-1:0] epc_o,                     \n                        ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:50: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic  [riscv::VLEN-1:0] trap_vector_base_o,        \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:50: syntax error, unexpected ::, expecting ':'\n    output logic  [riscv::VLEN-1:0] trap_vector_base_o,        \n                        ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:55: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic [2:0]            frm_o,                       \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:56: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic [6:0]            fprec_o,                     \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:58: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output irq_ctrl_t             irq_ctrl_o,                  \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:61: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  en_ld_st_translation_o,      \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:62: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output riscv::priv_lvl_t      ld_st_priv_lvl_o,            \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:64: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  mxr_o,\n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:65: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic[riscv::PPNW-1:0] satp_ppn_o,\n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:65: syntax error, unexpected ::, expecting ':'\n    output logic[riscv::PPNW-1:0] satp_ppn_o,\n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:68: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic [1:0]            irq_i,                       \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:69: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic                  ipi_i,                       \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:70: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n    input  logic                  debug_req_i,                 \n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:71: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  set_debug_pc_o,\n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:73: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  tvm_o,                       \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:74: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  tw_o,                        \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:75: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  tsr_o,                       \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:76: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  debug_mode_o,                \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:77: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  single_step_o,               \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:79: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  icache_en_o,                 \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:80: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic                  dcache_en_o,                 \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:82: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic  [4:0]           perf_addr_o,                 \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:83: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output logic[riscv::XLEN-1:0] perf_data_o,                 \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:83: syntax error, unexpected ::, expecting ':'\n    output logic[riscv::XLEN-1:0] perf_data_o,                 \n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:84: syntax error, unexpected ::, expecting ':'\n    input  logic[riscv::XLEN-1:0] perf_data_i,                 \n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:87: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n    output riscv::pmpcfg_t [15:0] pmpcfg_o,    \n    ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:88: syntax error, unexpected ::, expecting ':'\n    output logic [15:0][riscv::PLEN-3:0] pmpaddr_o             \n                             ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:93: syntax error, unexpected IDENTIFIER\n    riscv::xlen_t csr_wdata, csr_rdata;\n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:103: syntax error, unexpected IDENTIFIER\n    riscv::status_rv_t    mstatus_q,  mstatus_d;\n    ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/csr_regfile.sv:114: syntax error, unexpected IDENTIFIER\n    riscv::xlen_t dpc_q,       dpc_d;\n    ^~~~~\n%Error: Exiting due to too many errors encountered; --error-limit=50\n"
module csr_regfile import ariane_pkg::*; #(
    parameter logic [63:0] DmBaseAddress   = 64'h0,
    parameter int          AsidWidth       = 1,
    parameter int unsigned NrCommitPorts   = 2,
    parameter int unsigned NrPMPEntries    = 8
) (
    input  logic                  clk_i,
    input  logic                  rst_ni,
    input  logic                  time_irq_i,

    output logic                  flush_o,
    output logic                  halt_csr_o,

    input  scoreboard_entry_t [NrCommitPorts-1:0] commit_instr_i,
    input  logic [NrCommitPorts-1:0]              commit_ack_i,

    input  logic[riscv::VLEN-1:0] boot_addr_i,
    input  logic[riscv::XLEN-1:0] hart_id_i,

    input exception_t             ex_i,

    input  fu_op                  csr_op_i,
    input  logic  [11:0]          csr_addr_i,
    input  logic[riscv::XLEN-1:0] csr_wdata_i,
    output logic[riscv::XLEN-1:0] csr_rdata_o,
    input  logic                  dirty_fp_state_i,
    input  logic                  csr_write_fflags_i,
    input  logic  [riscv::VLEN-1:0]  pc_i,
    output exception_t            csr_exception_o,



    output logic  [riscv::VLEN-1:0] epc_o,
    output logic                  eret_o,
    output logic  [riscv::VLEN-1:0] trap_vector_base_o,
    output riscv::priv_lvl_t      priv_lvl_o,

    output riscv::xs_t            fs_o,
    output logic [4:0]            fflags_o,
    output logic [2:0]            frm_o,
    output logic [6:0]            fprec_o,

    output irq_ctrl_t             irq_ctrl_o,

    output logic                  en_translation_o,
    output logic                  en_ld_st_translation_o,
    output riscv::priv_lvl_t      ld_st_priv_lvl_o,
    output logic                  sum_o,
    output logic                  mxr_o,
    output logic[riscv::PPNW-1:0] satp_ppn_o,
    output logic [AsidWidth-1:0] asid_o,

    input  logic [1:0]            irq_i,
    input  logic                  ipi_i,
    input  logic                  debug_req_i,
    output logic                  set_debug_pc_o,

    output logic                  tvm_o,
    output logic                  tw_o,
    output logic                  tsr_o,
    output logic                  debug_mode_o,
    output logic                  single_step_o,

    output logic                  icache_en_o,
    output logic                  dcache_en_o,

    output logic  [4:0]           perf_addr_o,
    output logic[riscv::XLEN-1:0] perf_data_o,
    input  logic[riscv::XLEN-1:0] perf_data_i,
    output logic                  perf_we_o,

    output riscv::pmpcfg_t [15:0] pmpcfg_o,
    output logic [15:0][riscv::PLEN-3:0] pmpaddr_o
);

    logic        read_access_exception, update_access_exception, privilege_violation;
    logic        csr_we, csr_read;
    riscv::xlen_t csr_wdata, csr_rdata;
    riscv::priv_lvl_t   trap_to_priv_lvl;

    logic        en_ld_st_translation_d, en_ld_st_translation_q;
    logic  mprv;
    logic  mret;
    logic  sret;
    logic  dret;

    logic  dirty_fp_state_csr;
    riscv::status_rv_t    mstatus_q,  mstatus_d;
    riscv::xlen_t         mstatus_extended;
    riscv::satp_t         satp_q, satp_d;
    riscv::dcsr_t         dcsr_q,     dcsr_d;
    riscv::csr_t  csr_addr;

    riscv::priv_lvl_t   priv_lvl_d, priv_lvl_q;

    logic        debug_mode_q, debug_mode_d;
    logic        mtvec_rst_load_q;

    riscv::xlen_t dpc_q,       dpc_d;
    riscv::xlen_t dscratch0_q, dscratch0_d;
    riscv::xlen_t dscratch1_q, dscratch1_d;
    riscv::xlen_t mtvec_q,     mtvec_d;
    riscv::xlen_t medeleg_q,   medeleg_d;
    riscv::xlen_t mideleg_q,   mideleg_d;
    riscv::xlen_t mip_q,       mip_d;
    riscv::xlen_t mie_q,       mie_d;
    riscv::xlen_t mcounteren_q,mcounteren_d;
    riscv::xlen_t mscratch_q,  mscratch_d;
    riscv::xlen_t mepc_q,      mepc_d;
    riscv::xlen_t mcause_q,    mcause_d;
    riscv::xlen_t mtval_q,     mtval_d;

    riscv::xlen_t stvec_q,     stvec_d;
    riscv::xlen_t scounteren_q,scounteren_d;
    riscv::xlen_t sscratch_q,  sscratch_d;
    riscv::xlen_t sepc_q,      sepc_d;
    riscv::xlen_t scause_q,    scause_d;
    riscv::xlen_t stval_q,     stval_d;
    riscv::xlen_t dcache_q,    dcache_d;
    riscv::xlen_t icache_q,    icache_d;

    logic        wfi_d,       wfi_q;

    riscv::xlen_t cycle_q,     cycle_d;
    riscv::xlen_t instret_q,   instret_d;

    riscv::pmpcfg_t [15:0]    pmpcfg_q,  pmpcfg_d;
    logic [15:0][riscv::PLEN-3:0]        pmpaddr_q,  pmpaddr_d;


    assign pmpcfg_o = pmpcfg_q[15:0];
    assign pmpaddr_o = pmpaddr_q;

    riscv::fcsr_t fcsr_q, fcsr_d;



    assign csr_addr = riscv::csr_t'(csr_addr_i);
    assign fs_o = mstatus_q.fs;



    assign mstatus_extended = riscv::IS_XLEN64 ? mstatus_q[riscv::XLEN-1:0] :
                              {mstatus_q.sd, mstatus_q.wpri3[7:0], mstatus_q[22:0]};

    always_comb begin : csr_read_process

        read_access_exception = 1'b0;
        csr_rdata = '0;
        perf_addr_o = csr_addr.address[4:0];

        if (csr_read) begin
            unique case (csr_addr.address)
                riscv::CSR_FFLAGS: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-5{1'b0}}, fcsr_q.fflags};
                    end
                end
                riscv::CSR_FRM: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-3{1'b0}}, fcsr_q.frm};
                    end
                end
                riscv::CSR_FCSR: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-8{1'b0}}, fcsr_q.frm, fcsr_q.fflags};
                    end
                end

                riscv::CSR_FTRAN: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-7{1'b0}}, fcsr_q.fprec};
                    end
                end

                riscv::CSR_DCSR:               csr_rdata = {{riscv::XLEN-32{1'b0}}, dcsr_q};
                riscv::CSR_DPC:                csr_rdata = dpc_q;
                riscv::CSR_DSCRATCH0:          csr_rdata = dscratch0_q;
                riscv::CSR_DSCRATCH1:          csr_rdata = dscratch1_q;

                riscv::CSR_TSELECT:;
                riscv::CSR_TDATA1:;
                riscv::CSR_TDATA2:;
                riscv::CSR_TDATA3:;

                riscv::CSR_SSTATUS: begin
                    csr_rdata = mstatus_extended & ariane_pkg::SMODE_STATUS_READ_MASK[riscv::XLEN-1:0];
                end
                riscv::CSR_SIE:                csr_rdata = mie_q & mideleg_q;
                riscv::CSR_SIP:                csr_rdata = mip_q & mideleg_q;
                riscv::CSR_STVEC:              csr_rdata = stvec_q;
                riscv::CSR_SCOUNTEREN:         csr_rdata = scounteren_q;
                riscv::CSR_SSCRATCH:           csr_rdata = sscratch_q;
                riscv::CSR_SEPC:               csr_rdata = sepc_q;
                riscv::CSR_SCAUSE:             csr_rdata = scause_q;
                riscv::CSR_STVAL:              csr_rdata = stval_q;
                riscv::CSR_SATP: begin

                    if (priv_lvl_o == riscv::PRIV_LVL_S && mstatus_q.tvm) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = satp_q;
                    end
                end

                riscv::CSR_MSTATUS:            csr_rdata = mstatus_extended;
                riscv::CSR_MISA:               csr_rdata = ISA_CODE;
                riscv::CSR_MEDELEG:            csr_rdata = medeleg_q;
                riscv::CSR_MIDELEG:            csr_rdata = mideleg_q;
                riscv::CSR_MIE:                csr_rdata = mie_q;
                riscv::CSR_MTVEC:              csr_rdata = mtvec_q;
                riscv::CSR_MCOUNTEREN:         csr_rdata = mcounteren_q;
                riscv::CSR_MSCRATCH:           csr_rdata = mscratch_q;
                riscv::CSR_MEPC:               csr_rdata = mepc_q;
                riscv::CSR_MCAUSE:             csr_rdata = mcause_q;
                riscv::CSR_MTVAL:              csr_rdata = mtval_q;
                riscv::CSR_MIP:                csr_rdata = mip_q;
                riscv::CSR_MVENDORID:          csr_rdata = '0;
                riscv::CSR_MARCHID:            csr_rdata = ARIANE_MARCHID;
                riscv::CSR_MIMPID:             csr_rdata = '0;
                riscv::CSR_MHARTID:            csr_rdata = hart_id_i;
                riscv::CSR_MCYCLE:             csr_rdata = cycle_q;
                riscv::CSR_MINSTRET:           csr_rdata = instret_q;

                riscv::CSR_CYCLE:              csr_rdata = cycle_q;
                riscv::CSR_INSTRET:            csr_rdata = instret_q;
                riscv::CSR_ML1_ICACHE_MISS,
                riscv::CSR_ML1_DCACHE_MISS,
                riscv::CSR_MITLB_MISS,
                riscv::CSR_MDTLB_MISS,
                riscv::CSR_MLOAD,
                riscv::CSR_MSTORE,
                riscv::CSR_MEXCEPTION,
                riscv::CSR_MEXCEPTION_RET,
                riscv::CSR_MBRANCH_JUMP,
                riscv::CSR_MCALL,
                riscv::CSR_MRET,
                riscv::CSR_MMIS_PREDICT,
                riscv::CSR_MSB_FULL,
                riscv::CSR_MIF_EMPTY,
                riscv::CSR_MHPM_COUNTER_17,
                riscv::CSR_MHPM_COUNTER_18,
                riscv::CSR_MHPM_COUNTER_19,
                riscv::CSR_MHPM_COUNTER_20,
                riscv::CSR_MHPM_COUNTER_21,
                riscv::CSR_MHPM_COUNTER_22,
                riscv::CSR_MHPM_COUNTER_23,
                riscv::CSR_MHPM_COUNTER_24,
                riscv::CSR_MHPM_COUNTER_25,
                riscv::CSR_MHPM_COUNTER_26,
                riscv::CSR_MHPM_COUNTER_27,
                riscv::CSR_MHPM_COUNTER_28,
                riscv::CSR_MHPM_COUNTER_29,
                riscv::CSR_MHPM_COUNTER_30,
                riscv::CSR_MHPM_COUNTER_31:           csr_rdata   = perf_data_i;

                riscv::CSR_DCACHE:           csr_rdata = dcache_q;
                riscv::CSR_ICACHE:           csr_rdata = icache_q;

                riscv::CSR_PMPCFG0:          csr_rdata = pmpcfg_q[7:0];
                riscv::CSR_PMPCFG2:          csr_rdata = pmpcfg_q[15:8];





                riscv::CSR_PMPADDR0:         csr_rdata = {10'b0, pmpaddr_q[0][riscv::PLEN-3:1], (pmpcfg_q[0].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR1:         csr_rdata = {10'b0, pmpaddr_q[1][riscv::PLEN-3:1], (pmpcfg_q[1].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR2:         csr_rdata = {10'b0, pmpaddr_q[2][riscv::PLEN-3:1], (pmpcfg_q[2].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR3:         csr_rdata = {10'b0, pmpaddr_q[3][riscv::PLEN-3:1], (pmpcfg_q[3].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR4:         csr_rdata = {10'b0, pmpaddr_q[4][riscv::PLEN-3:1], (pmpcfg_q[4].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR5:         csr_rdata = {10'b0, pmpaddr_q[5][riscv::PLEN-3:1], (pmpcfg_q[5].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR6:         csr_rdata = {10'b0, pmpaddr_q[6][riscv::PLEN-3:1], (pmpcfg_q[6].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR7:         csr_rdata = {10'b0, pmpaddr_q[7][riscv::PLEN-3:1], (pmpcfg_q[7].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR8:         csr_rdata = {10'b0, pmpaddr_q[8][riscv::PLEN-3:1], (pmpcfg_q[8].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR9:         csr_rdata = {10'b0, pmpaddr_q[9][riscv::PLEN-3:1], (pmpcfg_q[9].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR10:        csr_rdata = {10'b0, pmpaddr_q[10][riscv::PLEN-3:1], (pmpcfg_q[10].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR11:        csr_rdata = {10'b0, pmpaddr_q[11][riscv::PLEN-3:1], (pmpcfg_q[11].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR12:        csr_rdata = {10'b0, pmpaddr_q[12][riscv::PLEN-3:1], (pmpcfg_q[12].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR13:        csr_rdata = {10'b0, pmpaddr_q[13][riscv::PLEN-3:1], (pmpcfg_q[13].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR14:        csr_rdata = {10'b0, pmpaddr_q[14][riscv::PLEN-3:1], (pmpcfg_q[14].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR15:        csr_rdata = {10'b0, pmpaddr_q[15][riscv::PLEN-3:1], (pmpcfg_q[15].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                default: read_access_exception = 1'b1;
            endcase
        end
    end



    riscv::xlen_t mask;
    always_comb begin : csr_update
        automatic riscv::satp_t satp;
        automatic riscv::xlen_t instret;


        satp = satp_q;
        instret = instret_q;




        cycle_d = cycle_q;
        instret_d = instret_q;
        if (!debug_mode_q) begin

            for (int i = 0; i < NrCommitPorts; i++) begin
                if (commit_ack_i[i] && !ex_i.valid) instret++;
            end
            instret_d = instret;

            if (ENABLE_CYCLE_COUNT) cycle_d = cycle_q + 1'b1;
            else cycle_d = instret;
        end

        eret_o                  = 1'b0;
        flush_o                 = 1'b0;
        update_access_exception = 1'b0;

        set_debug_pc_o          = 1'b0;

        perf_we_o               = 1'b0;
        perf_data_o             = 'b0;

        fcsr_d                  = fcsr_q;

        priv_lvl_d              = priv_lvl_q;
        debug_mode_d            = debug_mode_q;
        dcsr_d                  = dcsr_q;
        dpc_d                   = dpc_q;
        dscratch0_d             = dscratch0_q;
        dscratch1_d             = dscratch1_q;
        mstatus_d               = mstatus_q;







        if (mtvec_rst_load_q) begin
            mtvec_d             = {{riscv::XLEN-riscv::VLEN{1'b0}}, boot_addr_i} + 'h40;
        end else begin
            mtvec_d             = mtvec_q;
        end

        medeleg_d               = medeleg_q;
        mideleg_d               = mideleg_q;
        mip_d                   = mip_q;
        mie_d                   = mie_q;
        mepc_d                  = mepc_q;
        mcause_d                = mcause_q;
        mcounteren_d            = mcounteren_q;
        mscratch_d              = mscratch_q;
        mtval_d                 = mtval_q;
        dcache_d                = dcache_q;
        icache_d                = icache_q;

        sepc_d                  = sepc_q;
        scause_d                = scause_q;
        stvec_d                 = stvec_q;
        scounteren_d            = scounteren_q;
        sscratch_d              = sscratch_q;
        stval_d                 = stval_q;
        satp_d                  = satp_q;

        en_ld_st_translation_d  = en_ld_st_translation_q;
        dirty_fp_state_csr      = 1'b0;

        pmpcfg_d                = pmpcfg_q;
        pmpaddr_d               = pmpaddr_q;


        if (csr_we) begin
            unique case (csr_addr.address)

                riscv::CSR_FFLAGS: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.fflags = csr_wdata[4:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FRM: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.frm    = csr_wdata[2:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FCSR: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d[7:0] = csr_wdata[7:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FTRAN: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.fprec = csr_wdata[6:0];

                        flush_o = 1'b1;
                    end
                end

                riscv::CSR_DCSR: begin
                    dcsr_d = csr_wdata[31:0];

                    dcsr_d.xdebugver = 4'h4;

                    dcsr_d.nmip      = 1'b0;
                    dcsr_d.stopcount = 1'b0;
                    dcsr_d.stoptime  = 1'b0;
                end
                riscv::CSR_DPC:                dpc_d = csr_wdata;
                riscv::CSR_DSCRATCH0:          dscratch0_d = csr_wdata;
                riscv::CSR_DSCRATCH1:          dscratch1_d = csr_wdata;

                riscv::CSR_TSELECT:;
                riscv::CSR_TDATA1:;
                riscv::CSR_TDATA2:;
                riscv::CSR_TDATA3:;

                riscv::CSR_SSTATUS: begin
                    mask = ariane_pkg::SMODE_STATUS_WRITE_MASK[riscv::XLEN-1:0];
                    mstatus_d = (mstatus_q & ~{{64-riscv::XLEN{1'b0}}, mask}) | {{64-riscv::XLEN{1'b0}}, (csr_wdata & mask)};

                    if (!FP_PRESENT) begin
                        mstatus_d.fs = riscv::Off;
                    end

                    flush_o = 1'b1;
                end


                riscv::CSR_SIE: begin

                    mie_d = (mie_q & ~mideleg_q) | (csr_wdata & mideleg_q);
                end

                riscv::CSR_SIP: begin

                    mask = riscv::MIP_SSIP & mideleg_q;
                    mip_d = (mip_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_STVEC:              stvec_d     = {csr_wdata[riscv::XLEN-1:2], 1'b0, csr_wdata[0]};
                riscv::CSR_SCOUNTEREN:         scounteren_d = {{riscv::XLEN-32{1'b0}}, csr_wdata[31:0]};
                riscv::CSR_SSCRATCH:           sscratch_d  = csr_wdata;
                riscv::CSR_SEPC:               sepc_d      = {csr_wdata[riscv::XLEN-1:1], 1'b0};
                riscv::CSR_SCAUSE:             scause_d    = csr_wdata;
                riscv::CSR_STVAL:              stval_d     = csr_wdata;

                riscv::CSR_SATP: begin

                    if (priv_lvl_o == riscv::PRIV_LVL_S && mstatus_q.tvm)
                        update_access_exception = 1'b1;
                    else begin
                        satp      = riscv::satp_t'(csr_wdata);

                        satp.asid = satp.asid & {{(riscv::ASIDW-AsidWidth){1'b0}}, {AsidWidth{1'b1}}};

                        if (riscv::vm_mode_t'(satp.mode) == riscv::ModeOff ||
                            riscv::vm_mode_t'(satp.mode) == riscv::MODE_SV) satp_d = satp;
                    end


                    flush_o = 1'b1;
                end

                riscv::CSR_MSTATUS: begin
                    mstatus_d      = {{64-riscv::XLEN{1'b0}}, csr_wdata};
                    mstatus_d.xs   = riscv::Off;
                    if (!FP_PRESENT) begin
                        mstatus_d.fs = riscv::Off;
                    end
                    mstatus_d.upie = 1'b0;
                    mstatus_d.uie  = 1'b0;

                    flush_o        = 1'b1;
                end

                riscv::CSR_MISA:;


                riscv::CSR_MEDELEG: begin
                    mask = (1 << riscv::INSTR_ADDR_MISALIGNED) |
                           (1 << riscv::BREAKPOINT) |
                           (1 << riscv::ENV_CALL_UMODE) |
                           (1 << riscv::INSTR_PAGE_FAULT) |
                           (1 << riscv::LOAD_PAGE_FAULT) |
                           (1 << riscv::STORE_PAGE_FAULT);
                    medeleg_d = (medeleg_q & ~mask) | (csr_wdata & mask);
                end


                riscv::CSR_MIDELEG: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP;
                    mideleg_d = (mideleg_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MIE: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP | riscv::MIP_MSIP | riscv::MIP_MTIP | riscv::MIP_MEIP;
                    mie_d = (mie_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MTVEC: begin
                    mtvec_d = {csr_wdata[riscv::XLEN-1:2], 1'b0, csr_wdata[0]};


                    if (csr_wdata[0]) mtvec_d = {csr_wdata[riscv::XLEN-1:8], 7'b0, csr_wdata[0]};
                end
                riscv::CSR_MCOUNTEREN:         mcounteren_d = {{riscv::XLEN-32{1'b0}}, csr_wdata[31:0]};

                riscv::CSR_MSCRATCH:           mscratch_d  = csr_wdata;
                riscv::CSR_MEPC:               mepc_d      = {csr_wdata[riscv::XLEN-1:1], 1'b0};
                riscv::CSR_MCAUSE:             mcause_d    = csr_wdata;
                riscv::CSR_MTVAL:              mtval_d     = csr_wdata;
                riscv::CSR_MIP: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP;
                    mip_d = (mip_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MCYCLE:             cycle_d     = csr_wdata;
                riscv::CSR_MINSTRET:           instret     = csr_wdata;
                riscv::CSR_ML1_ICACHE_MISS,
                riscv::CSR_ML1_DCACHE_MISS,
                riscv::CSR_MITLB_MISS,
                riscv::CSR_MDTLB_MISS,
                riscv::CSR_MLOAD,
                riscv::CSR_MSTORE,
                riscv::CSR_MEXCEPTION,
                riscv::CSR_MEXCEPTION_RET,
                riscv::CSR_MBRANCH_JUMP,
                riscv::CSR_MCALL,
                riscv::CSR_MRET,
                riscv::CSR_MMIS_PREDICT,
                riscv::CSR_MSB_FULL,
                riscv::CSR_MIF_EMPTY,
                riscv::CSR_MHPM_COUNTER_17,
                riscv::CSR_MHPM_COUNTER_18,
                riscv::CSR_MHPM_COUNTER_19,
                riscv::CSR_MHPM_COUNTER_20,
                riscv::CSR_MHPM_COUNTER_21,
                riscv::CSR_MHPM_COUNTER_22,
                riscv::CSR_MHPM_COUNTER_23,
                riscv::CSR_MHPM_COUNTER_24,
                riscv::CSR_MHPM_COUNTER_25,
                riscv::CSR_MHPM_COUNTER_26,
                riscv::CSR_MHPM_COUNTER_27,
                riscv::CSR_MHPM_COUNTER_28,
                riscv::CSR_MHPM_COUNTER_29,
                riscv::CSR_MHPM_COUNTER_30,
                riscv::CSR_MHPM_COUNTER_31: begin
                                        perf_data_o = csr_wdata;
                                        perf_we_o   = 1'b1;
                end

                riscv::CSR_DCACHE:             dcache_d    = {{riscv::XLEN-1{1'b0}}, csr_wdata[0]};
                riscv::CSR_ICACHE:             icache_d    = {{riscv::XLEN-1{1'b0}}, csr_wdata[0]};




                riscv::CSR_PMPCFG0:    for (int i = 0; i < (riscv::XLEN/8); i++) if (!pmpcfg_q[i].locked) pmpcfg_d[i]  = csr_wdata[i*8+:8];
                riscv::CSR_PMPCFG1: begin
                    if (riscv::XLEN == 32) begin
                        for (int i = 0; i < 4; i++) if (!pmpcfg_q[i+4].locked) pmpcfg_d[i+4]  = csr_wdata[i*8+:8];
                    end
                end
                riscv::CSR_PMPCFG2:    for (int i = 0; i < (riscv::XLEN/8); i++) if (!pmpcfg_q[i+8].locked) pmpcfg_d[i+8]  = csr_wdata[i*8+:8];
                riscv::CSR_PMPCFG3: begin
                    if (riscv::XLEN == 32) begin
                        for (int i = 0; i < 4; i++) if (!pmpcfg_q[i+12].locked) pmpcfg_d[i+12]  = csr_wdata[i*8+:8];
                    end
                end
                riscv::CSR_PMPADDR0:   if (!pmpcfg_q[ 0].locked && !(pmpcfg_q[ 1].locked && pmpcfg_q[ 1].addr_mode == riscv::TOR))  pmpaddr_d[0]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR1:   if (!pmpcfg_q[ 1].locked && !(pmpcfg_q[ 2].locked && pmpcfg_q[ 2].addr_mode == riscv::TOR))  pmpaddr_d[1]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR2:   if (!pmpcfg_q[ 2].locked && !(pmpcfg_q[ 3].locked && pmpcfg_q[ 3].addr_mode == riscv::TOR))  pmpaddr_d[2]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR3:   if (!pmpcfg_q[ 3].locked && !(pmpcfg_q[ 4].locked && pmpcfg_q[ 4].addr_mode == riscv::TOR))  pmpaddr_d[3]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR4:   if (!pmpcfg_q[ 4].locked && !(pmpcfg_q[ 5].locked && pmpcfg_q[ 5].addr_mode == riscv::TOR))  pmpaddr_d[4]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR5:   if (!pmpcfg_q[ 5].locked && !(pmpcfg_q[ 6].locked && pmpcfg_q[ 6].addr_mode == riscv::TOR))  pmpaddr_d[5]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR6:   if (!pmpcfg_q[ 6].locked && !(pmpcfg_q[ 7].locked && pmpcfg_q[ 7].addr_mode == riscv::TOR))  pmpaddr_d[6]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR7:   if (!pmpcfg_q[ 7].locked && !(pmpcfg_q[ 8].locked && pmpcfg_q[ 8].addr_mode == riscv::TOR))  pmpaddr_d[7]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR8:   if (!pmpcfg_q[ 8].locked && !(pmpcfg_q[ 9].locked && pmpcfg_q[ 9].addr_mode == riscv::TOR))  pmpaddr_d[8]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR9:   if (!pmpcfg_q[ 9].locked && !(pmpcfg_q[10].locked && pmpcfg_q[10].addr_mode == riscv::TOR))  pmpaddr_d[9]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR10:  if (!pmpcfg_q[10].locked && !(pmpcfg_q[11].locked && pmpcfg_q[11].addr_mode == riscv::TOR))  pmpaddr_d[10]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR11:  if (!pmpcfg_q[11].locked && !(pmpcfg_q[12].locked && pmpcfg_q[12].addr_mode == riscv::TOR))  pmpaddr_d[11]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR12:  if (!pmpcfg_q[12].locked && !(pmpcfg_q[13].locked && pmpcfg_q[13].addr_mode == riscv::TOR))  pmpaddr_d[12]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR13:  if (!pmpcfg_q[13].locked && !(pmpcfg_q[14].locked && pmpcfg_q[14].addr_mode == riscv::TOR))  pmpaddr_d[13]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR14:  if (!pmpcfg_q[14].locked && !(pmpcfg_q[15].locked && pmpcfg_q[15].addr_mode == riscv::TOR))  pmpaddr_d[14]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR15:  if (!pmpcfg_q[15].locked)  pmpaddr_d[15]  = csr_wdata[riscv::PLEN-3:0];
                default: update_access_exception = 1'b1;
            endcase
        end

        mstatus_d.sxl  = riscv::XLEN_64;
        mstatus_d.uxl  = riscv::XLEN_64;


        if (FP_PRESENT && (dirty_fp_state_csr || dirty_fp_state_i)) begin
            mstatus_d.fs = riscv::Dirty;
        end

        mstatus_d.sd   = (mstatus_q.xs == riscv::Dirty) | (mstatus_q.fs == riscv::Dirty);


        if (csr_write_fflags_i) begin
            fcsr_d.fflags = csr_wdata_i[4:0] | fcsr_q.fflags;
        end




        mip_d[riscv::IRQ_M_EXT] = irq_i[0];

        mip_d[riscv::IRQ_M_SOFT] = ipi_i;

        mip_d[riscv::IRQ_M_TIMER] = time_irq_i;






        trap_to_priv_lvl = riscv::PRIV_LVL_M;


        if (!debug_mode_q && ex_i.cause != riscv::DEBUG_REQUEST && ex_i.valid) begin

            flush_o   = 1'b0;




            if ((ex_i.cause[riscv::XLEN-1] && mideleg_q[ex_i.cause[$clog2(riscv::XLEN)-1:0]]) ||
                (~ex_i.cause[riscv::XLEN-1] && medeleg_q[ex_i.cause[$clog2(riscv::XLEN)-1:0]])) begin


                trap_to_priv_lvl = (priv_lvl_o == riscv::PRIV_LVL_M) ? riscv::PRIV_LVL_M : riscv::PRIV_LVL_S;
            end


            if (trap_to_priv_lvl == riscv::PRIV_LVL_S) begin

                mstatus_d.sie  = 1'b0;
                mstatus_d.spie = mstatus_q.sie;

                mstatus_d.spp  = priv_lvl_q[0];

                scause_d       = ex_i.cause;

                sepc_d         = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                stval_d        = (ariane_pkg::ZERO_TVAL
                                  && (ex_i.cause inside {
                                    riscv::ILLEGAL_INSTR,
                                    riscv::BREAKPOINT,
                                    riscv::ENV_CALL_UMODE,
                                    riscv::ENV_CALL_SMODE,
                                    riscv::ENV_CALL_MMODE
                                  } || ex_i.cause[riscv::XLEN-1])) ? '0 : ex_i.tval;

            end else begin

                mstatus_d.mie  = 1'b0;
                mstatus_d.mpie = mstatus_q.mie;

                mstatus_d.mpp  = priv_lvl_q;
                mcause_d       = ex_i.cause;

                mepc_d         = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                mtval_d        = (ariane_pkg::ZERO_TVAL
                                  && (ex_i.cause inside {
                                    riscv::ILLEGAL_INSTR,
                                    riscv::BREAKPOINT,
                                    riscv::ENV_CALL_UMODE,
                                    riscv::ENV_CALL_SMODE,
                                    riscv::ENV_CALL_MMODE
                                  } || ex_i.cause[riscv::XLEN-1])) ? '0 : ex_i.tval;
            end

            priv_lvl_d = trap_to_priv_lvl;
        end











        if (!debug_mode_q) begin
            dcsr_d.prv = priv_lvl_o;



            if (ex_i.valid && ex_i.cause == riscv::BREAKPOINT) begin
                dcsr_d.prv = priv_lvl_o;

                unique case (priv_lvl_o)
                    riscv::PRIV_LVL_M: begin
                        debug_mode_d = dcsr_q.ebreakm;
                        set_debug_pc_o = dcsr_q.ebreakm;
                    end
                    riscv::PRIV_LVL_S: begin
                        debug_mode_d = dcsr_q.ebreaks;
                        set_debug_pc_o = dcsr_q.ebreaks;
                    end
                    riscv::PRIV_LVL_U: begin
                        debug_mode_d = dcsr_q.ebreaku;
                        set_debug_pc_o = dcsr_q.ebreaku;
                    end
                    default:;
                endcase

                dpc_d = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};
                dcsr_d.cause = dm::CauseBreakpoint;
            end


            if (ex_i.valid && ex_i.cause == riscv::DEBUG_REQUEST) begin
                dcsr_d.prv = priv_lvl_o;

                dpc_d = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                debug_mode_d = 1'b1;

                set_debug_pc_o = 1'b1;

                dcsr_d.cause = dm::CauseRequest;
            end


            if (dcsr_q.step && commit_ack_i[0]) begin
                dcsr_d.prv = priv_lvl_o;

                if (commit_instr_i[0].fu == CTRL_FLOW) begin

                    dpc_d = {{riscv::XLEN-riscv::VLEN{commit_instr_i[0].bp.predict_address[riscv::VLEN-1]}}, commit_instr_i[0].bp.predict_address};

                end else if (ex_i.valid) begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{1'b0}},trap_vector_base_o};

                end else if (eret_o) begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{1'b0}},epc_o};

                end else begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{commit_instr_i[0].pc[riscv::VLEN-1]}}, commit_instr_i[0].pc + (commit_instr_i[0].is_compressed ? 'h2 : 'h4)};
                end
                debug_mode_d = 1'b1;
                set_debug_pc_o = 1'b1;
                dcsr_d.cause = dm::CauseSingleStep;
            end
        end

        if (debug_mode_q && ex_i.valid && ex_i.cause == riscv::BREAKPOINT) begin
            set_debug_pc_o = 1'b1;
        end






        if (mprv && riscv::vm_mode_t'(satp_q.mode) == riscv::MODE_SV && (mstatus_q.mpp != riscv::PRIV_LVL_M))
            en_ld_st_translation_d = 1'b1;
        else
            en_ld_st_translation_d = en_translation_o;

        ld_st_priv_lvl_o = (mprv) ? mstatus_q.mpp : priv_lvl_o;
        en_ld_st_translation_o = en_ld_st_translation_q;





        if (mret) begin

            eret_o = 1'b1;


            mstatus_d.mie  = mstatus_q.mpie;

            priv_lvl_d     = mstatus_q.mpp;

            mstatus_d.mpp  = riscv::PRIV_LVL_U;

            mstatus_d.mpie = 1'b1;
        end

        if (sret) begin

            eret_o = 1'b1;

            mstatus_d.sie  = mstatus_q.spie;

            priv_lvl_d     = riscv::priv_lvl_t'({1'b0, mstatus_q.spp});

            mstatus_d.spp  = 1'b0;

            mstatus_d.spie = 1'b1;
        end


        if (dret) begin

            eret_o = 1'b1;

            priv_lvl_d     = riscv::priv_lvl_t'(dcsr_q.prv);

            debug_mode_d = 1'b0;
        end
    end




    always_comb begin : csr_op_logic
        csr_wdata = csr_wdata_i;
        csr_we    = 1'b1;
        csr_read  = 1'b1;
        mret      = 1'b0;
        sret      = 1'b0;
        dret      = 1'b0;

        unique case (csr_op_i)
            CSR_WRITE: csr_wdata = csr_wdata_i;
            CSR_SET:   csr_wdata = csr_wdata_i | csr_rdata;
            CSR_CLEAR: csr_wdata = (~csr_wdata_i) & csr_rdata;
            CSR_READ:  csr_we    = 1'b0;
            SRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                sret     = 1'b1;
            end
            MRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                mret     = 1'b1;
            end
            DRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                dret     = 1'b1;
            end
            default: begin
                csr_we   = 1'b0;
                csr_read = 1'b0;
            end
        endcase

        if (privilege_violation) begin
            csr_we = 1'b0;
            csr_read = 1'b0;
        end
    end

    assign irq_ctrl_o.mie = mie_q;
    assign irq_ctrl_o.mip = mip_q;
    assign irq_ctrl_o.sie = mstatus_q.sie;
    assign irq_ctrl_o.mideleg = mideleg_q;
    assign irq_ctrl_o.global_enable = (~debug_mode_q)

                                    & (~dcsr_q.step | dcsr_q.stepie)
                                    & ((mstatus_q.mie & (priv_lvl_o == riscv::PRIV_LVL_M))
                                    | (priv_lvl_o != riscv::PRIV_LVL_M));

    always_comb begin : privilege_check



        privilege_violation = 1'b0;


        if (csr_op_i inside {CSR_WRITE, CSR_SET, CSR_CLEAR, CSR_READ}) begin
            if ((riscv::priv_lvl_t'(priv_lvl_o & csr_addr.csr_decode.priv_lvl) != csr_addr.csr_decode.priv_lvl)) begin
                privilege_violation = 1'b1;
            end

            if (csr_addr_i[11:4] == 8'h7b && !debug_mode_q) begin
                privilege_violation = 1'b1;
            end


            if (csr_addr_i inside {[riscv::CSR_CYCLE:riscv::CSR_HPM_COUNTER_31]}) begin
                unique case (csr_addr.csr_decode.priv_lvl)
                    riscv::PRIV_LVL_M: privilege_violation = 1'b0;
                    riscv::PRIV_LVL_S: privilege_violation = ~mcounteren_q[csr_addr_i[4:0]];
                    riscv::PRIV_LVL_U: privilege_violation = ~mcounteren_q[csr_addr_i[4:0]] & ~scounteren_q[csr_addr_i[4:0]];
                endcase
            end
        end
    end



    always_comb begin : exception_ctrl
        csr_exception_o = {
            '0, '0, 1'b0
        };





        if (update_access_exception || read_access_exception) begin
            csr_exception_o.cause = riscv::ILLEGAL_INSTR;


            csr_exception_o.valid = 1'b1;
        end

        if (privilege_violation) begin
          csr_exception_o.cause = riscv::ILLEGAL_INSTR;
          csr_exception_o.valid = 1'b1;
        end
    end




    always_comb begin : wfi_ctrl

        wfi_d = wfi_q;


        if (|mip_q || debug_req_i || irq_i[1]) begin
            wfi_d = 1'b0;


        end else if (!debug_mode_q && csr_op_i == WFI && !ex_i.valid) begin
            wfi_d = 1'b1;
        end
    end


    always_comb begin : priv_output
        trap_vector_base_o = {mtvec_q[riscv::VLEN-1:2], 2'b0};

        if (trap_to_priv_lvl == riscv::PRIV_LVL_S) begin
            trap_vector_base_o = {stvec_q[riscv::VLEN-1:2], 2'b0};
        end


        if (debug_mode_q) begin
            trap_vector_base_o = DmBaseAddress[riscv::VLEN-1:0] + dm::ExceptionAddress[riscv::VLEN-1:0];
        end




        if ((mtvec_q[0] || stvec_q[0]) && ex_i.cause[riscv::XLEN-1]) begin
            trap_vector_base_o[7:2] = ex_i.cause[5:0];
        end

        epc_o = mepc_q[riscv::VLEN-1:0];

        if (sret) begin
            epc_o = sepc_q[riscv::VLEN-1:0];
        end

        if (dret) begin
            epc_o = dpc_q[riscv::VLEN-1:0];
        end
    end




    always_comb begin



        csr_rdata_o = csr_rdata;

        unique case (csr_addr.address)
            riscv::CSR_MIP: csr_rdata_o = csr_rdata | (irq_i[1] << riscv::IRQ_S_EXT);

            riscv::CSR_SIP: begin
                csr_rdata_o = csr_rdata
                            | ((irq_i[1] & mideleg_q[riscv::IRQ_S_EXT]) << riscv::IRQ_S_EXT);
            end
            default:;
        endcase
    end


    assign priv_lvl_o       = (debug_mode_q) ? riscv::PRIV_LVL_M : priv_lvl_q;

    assign fflags_o         = fcsr_q.fflags;
    assign frm_o            = fcsr_q.frm;
    assign fprec_o          = fcsr_q.fprec;

    assign satp_ppn_o       = satp_q.ppn;
    assign asid_o           = satp_q.asid[AsidWidth-1:0];
    assign sum_o            = mstatus_q.sum;

    assign en_translation_o = (riscv::vm_mode_t'(satp_q.mode) == riscv::MODE_SV &&
                               priv_lvl_o != riscv::PRIV_LVL_M)
                              ? 1'b1
                              : 1'b0;
    assign mxr_o            = mstatus_q.mxr;
    assign tvm_o            = mstatus_q.tvm;
    assign tw_o             = mstatus_q.tw;
    assign tsr_o            = mstatus_q.tsr;
    assign halt_csr_o       = wfi_q;
`ifdef PITON_ARIANE
    assign icache_en_o      = icache_q[0];
`else
    assign icache_en_o      = icache_q[0] & (~debug_mode_q);
`endif
    assign dcache_en_o      = dcache_q[0];


    assign mprv             = (debug_mode_q && !dcsr_q.mprven) ? 1'b0 : mstatus_q.mprv;
    assign debug_mode_o     = debug_mode_q;
    assign single_step_o    = dcsr_q.step;


    always_ff @(posedge clk_i or negedge rst_ni) begin
        if (~rst_ni) begin
            priv_lvl_q             <= riscv::PRIV_LVL_M;

            fcsr_q                 <= '0;

`ifdef DROMAJO
            debug_mode_q           <= 1'b1;
`else
            debug_mode_q           <= 1'b0;
`endif
            dcsr_q                 <= '0;
            dcsr_q.prv             <= riscv::PRIV_LVL_M;
            dpc_q                  <= '0;
            dscratch0_q            <= {riscv::XLEN{1'b0}};
            dscratch1_q            <= {riscv::XLEN{1'b0}};

            mstatus_q              <= 64'b0;

            mtvec_rst_load_q       <= 1'b1;
            mtvec_q                <= '0;
            medeleg_q              <= {riscv::XLEN{1'b0}};
            mideleg_q              <= {riscv::XLEN{1'b0}};
            mip_q                  <= {riscv::XLEN{1'b0}};
            mie_q                  <= {riscv::XLEN{1'b0}};
            mepc_q                 <= {riscv::XLEN{1'b0}};
            mcause_q               <= {riscv::XLEN{1'b0}};
            mcounteren_q           <= {riscv::XLEN{1'b0}};
            mscratch_q             <= {riscv::XLEN{1'b0}};
            mtval_q                <= {riscv::XLEN{1'b0}};
            dcache_q               <= {{riscv::XLEN-1{1'b0}}, 1'b1};
            icache_q               <= {{riscv::XLEN-1{1'b0}}, 1'b1};

            sepc_q                 <= {riscv::XLEN{1'b0}};
            scause_q               <= {riscv::XLEN{1'b0}};
            stvec_q                <= {riscv::XLEN{1'b0}};
            scounteren_q           <= {riscv::XLEN{1'b0}};
            sscratch_q             <= {riscv::XLEN{1'b0}};
            stval_q                <= {riscv::XLEN{1'b0}};
            satp_q                 <= {riscv::XLEN{1'b0}};

            cycle_q                <= {riscv::XLEN{1'b0}};
            instret_q              <= {riscv::XLEN{1'b0}};

            en_ld_st_translation_q <= 1'b0;

            wfi_q                  <= 1'b0;

            pmpcfg_q               <= '0;
            pmpaddr_q              <= '0;
        end else begin
            priv_lvl_q             <= priv_lvl_d;

            fcsr_q                 <= fcsr_d;

            debug_mode_q           <= debug_mode_d;
            dcsr_q                 <= dcsr_d;
            dpc_q                  <= dpc_d;
            dscratch0_q            <= dscratch0_d;
            dscratch1_q            <= dscratch1_d;

            mstatus_q              <= mstatus_d;
            mtvec_rst_load_q       <= 1'b0;
            mtvec_q                <= mtvec_d;
            medeleg_q              <= medeleg_d;
            mideleg_q              <= mideleg_d;
            mip_q                  <= mip_d;
            mie_q                  <= mie_d;
            mepc_q                 <= mepc_d;
            mcause_q               <= mcause_d;
            mcounteren_q           <= mcounteren_d;
            mscratch_q             <= mscratch_d;
            mtval_q                <= mtval_d;
            dcache_q               <= dcache_d;
            icache_q               <= icache_d;

            sepc_q                 <= sepc_d;
            scause_q               <= scause_d;
            stvec_q                <= stvec_d;
            scounteren_q           <= scounteren_d;
            sscratch_q             <= sscratch_d;
            stval_q                <= stval_d;
            satp_q                 <= satp_d;

            cycle_q                <= cycle_d;
            instret_q              <= instret_d;

            en_ld_st_translation_q <= en_ld_st_translation_d;

            wfi_q                  <= wfi_d;

            for(int i = 0; i < 16; i++) begin
                if(i < NrPMPEntries) begin
                    pmpcfg_q[i] <= pmpcfg_d[i];
                    pmpaddr_q[i] <= pmpaddr_d[i];
                end else begin
                    pmpcfg_q[i] <= '0;
                    pmpaddr_q[i] <= '0;
                end
            end
        end
    end





    `ifndef VERILATOR

        assert property (
          @(posedge clk_i) !(eret_o && ex_i.valid))
        else begin $error("eret and exception should never be valid at the same time"); $stop(); end
    `endif

endmodule
module csr_regfile import ariane_pkg::*;
 #(
    parameter logic [63:0] DmBaseAddress   = 64'h0,
    parameter int          AsidWidth       = 1,
    parameter int unsigned NrCommitPorts   = 2,
    parameter int unsigned NrPMPEntries    = 8
) (
    input  logic                  clk_i,
    input  logic                  rst_ni,
    input  logic                  time_irq_i,

    output logic                  flush_o,
    output logic                  halt_csr_o,

    input  scoreboard_entry_t [NrCommitPorts-1:0] commit_instr_i,
    input  logic [NrCommitPorts-1:0]              commit_ack_i,

    input  logic[riscv::VLEN-1:0] boot_addr_i,
    input  logic[riscv::XLEN-1:0] hart_id_i,

    input exception_t             ex_i,

    input  fu_op                  csr_op_i,
    input  logic  [11:0]          csr_addr_i,
    input  logic[riscv::XLEN-1:0] csr_wdata_i,
    output logic[riscv::XLEN-1:0] csr_rdata_o,
    input  logic                  dirty_fp_state_i,
    input  logic                  csr_write_fflags_i,
    input  logic  [riscv::VLEN-1:0]  pc_i,
    output exception_t            csr_exception_o,



    output logic  [riscv::VLEN-1:0] epc_o,
    output logic                  eret_o,
    output logic  [riscv::VLEN-1:0] trap_vector_base_o,
    output riscv::priv_lvl_t      priv_lvl_o,

    output riscv::xs_t            fs_o,
    output logic [4:0]            fflags_o,
    output logic [2:0]            frm_o,
    output logic [6:0]            fprec_o,

    output irq_ctrl_t             irq_ctrl_o,

    output logic                  en_translation_o,
    output logic                  en_ld_st_translation_o,
    output riscv::priv_lvl_t      ld_st_priv_lvl_o,
    output logic                  sum_o,
    output logic                  mxr_o,
    output logic[riscv::PPNW-1:0] satp_ppn_o,
    output logic [AsidWidth-1:0] asid_o,

    input  logic [1:0]            irq_i,
    input  logic                  ipi_i,
    input  logic                  debug_req_i,
    output logic                  set_debug_pc_o,

    output logic                  tvm_o,
    output logic                  tw_o,
    output logic                  tsr_o,
    output logic                  debug_mode_o,
    output logic                  single_step_o,

    output logic                  icache_en_o,
    output logic                  dcache_en_o,

    output logic  [4:0]           perf_addr_o,
    output logic[riscv::XLEN-1:0] perf_data_o,
    input  logic[riscv::XLEN-1:0] perf_data_i,
    output logic                  perf_we_o,

    output riscv::pmpcfg_t [15:0] pmpcfg_o,
    output logic [15:0][riscv::PLEN-3:0] pmpaddr_o
);

    logic        read_access_exception, update_access_exception, privilege_violation;
    logic        csr_we, csr_read;
    riscv::xlen_t csr_wdata, csr_rdata;
    riscv::priv_lvl_t   trap_to_priv_lvl;

    logic        en_ld_st_translation_d, en_ld_st_translation_q;
    logic  mprv;
    logic  mret;
    logic  sret;
    logic  dret;

    logic  dirty_fp_state_csr;
    riscv::status_rv_t    mstatus_q,  mstatus_d;
    riscv::xlen_t         mstatus_extended;
    riscv::satp_t         satp_q, satp_d;
    riscv::dcsr_t         dcsr_q,     dcsr_d;
    riscv::csr_t  csr_addr;

    riscv::priv_lvl_t   priv_lvl_d, priv_lvl_q;

    logic        debug_mode_q, debug_mode_d;
    logic        mtvec_rst_load_q;

    riscv::xlen_t dpc_q,       dpc_d;
    riscv::xlen_t dscratch0_q, dscratch0_d;
    riscv::xlen_t dscratch1_q, dscratch1_d;
    riscv::xlen_t mtvec_q,     mtvec_d;
    riscv::xlen_t medeleg_q,   medeleg_d;
    riscv::xlen_t mideleg_q,   mideleg_d;
    riscv::xlen_t mip_q,       mip_d;
    riscv::xlen_t mie_q,       mie_d;
    riscv::xlen_t mcounteren_q,mcounteren_d;
    riscv::xlen_t mscratch_q,  mscratch_d;
    riscv::xlen_t mepc_q,      mepc_d;
    riscv::xlen_t mcause_q,    mcause_d;
    riscv::xlen_t mtval_q,     mtval_d;

    riscv::xlen_t stvec_q,     stvec_d;
    riscv::xlen_t scounteren_q,scounteren_d;
    riscv::xlen_t sscratch_q,  sscratch_d;
    riscv::xlen_t sepc_q,      sepc_d;
    riscv::xlen_t scause_q,    scause_d;
    riscv::xlen_t stval_q,     stval_d;
    riscv::xlen_t dcache_q,    dcache_d;
    riscv::xlen_t icache_q,    icache_d;

    logic        wfi_d,       wfi_q;

    riscv::xlen_t cycle_q,     cycle_d;
    riscv::xlen_t instret_q,   instret_d;

    riscv::pmpcfg_t [15:0]    pmpcfg_q,  pmpcfg_d;
    logic [15:0][riscv::PLEN-3:0]        pmpaddr_q,  pmpaddr_d;


    assign pmpcfg_o = pmpcfg_q[15:0];
    assign pmpaddr_o = pmpaddr_q;

    riscv::fcsr_t fcsr_q, fcsr_d;



    assign csr_addr = riscv::csr_t'(csr_addr_i);
    assign fs_o = mstatus_q.fs;



    assign mstatus_extended = riscv::IS_XLEN64 ? mstatus_q[riscv::XLEN-1:0] :
                              {mstatus_q.sd, mstatus_q.wpri3[7:0], mstatus_q[22:0]};

    always_comb begin : csr_read_process

        read_access_exception = 1'b0;
        csr_rdata = '0;
        perf_addr_o = csr_addr.address[4:0];

        if (csr_read) begin
            unique case (csr_addr.address)
                riscv::CSR_FFLAGS: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-5{1'b0}}, fcsr_q.fflags};
                    end
                end
                riscv::CSR_FRM: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-3{1'b0}}, fcsr_q.frm};
                    end
                end
                riscv::CSR_FCSR: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-8{1'b0}}, fcsr_q.frm, fcsr_q.fflags};
                    end
                end

                riscv::CSR_FTRAN: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = {{riscv::XLEN-7{1'b0}}, fcsr_q.fprec};
                    end
                end

                riscv::CSR_DCSR:               csr_rdata = {{riscv::XLEN-32{1'b0}}, dcsr_q};
                riscv::CSR_DPC:                csr_rdata = dpc_q;
                riscv::CSR_DSCRATCH0:          csr_rdata = dscratch0_q;
                riscv::CSR_DSCRATCH1:          csr_rdata = dscratch1_q;

                riscv::CSR_TSELECT:;
                riscv::CSR_TDATA1:;
                riscv::CSR_TDATA2:;
                riscv::CSR_TDATA3:;

                riscv::CSR_SSTATUS: begin
                    csr_rdata = mstatus_extended & ariane_pkg::SMODE_STATUS_READ_MASK[riscv::XLEN-1:0];
                end
                riscv::CSR_SIE:                csr_rdata = mie_q & mideleg_q;
                riscv::CSR_SIP:                csr_rdata = mip_q & mideleg_q;
                riscv::CSR_STVEC:              csr_rdata = stvec_q;
                riscv::CSR_SCOUNTEREN:         csr_rdata = scounteren_q;
                riscv::CSR_SSCRATCH:           csr_rdata = sscratch_q;
                riscv::CSR_SEPC:               csr_rdata = sepc_q;
                riscv::CSR_SCAUSE:             csr_rdata = scause_q;
                riscv::CSR_STVAL:              csr_rdata = stval_q;
                riscv::CSR_SATP: begin

                    if (priv_lvl_o == riscv::PRIV_LVL_S && mstatus_q.tvm) begin
                        read_access_exception = 1'b1;
                    end else begin
                        csr_rdata = satp_q;
                    end
                end

                riscv::CSR_MSTATUS:            csr_rdata = mstatus_extended;
                riscv::CSR_MISA:               csr_rdata = ISA_CODE;
                riscv::CSR_MEDELEG:            csr_rdata = medeleg_q;
                riscv::CSR_MIDELEG:            csr_rdata = mideleg_q;
                riscv::CSR_MIE:                csr_rdata = mie_q;
                riscv::CSR_MTVEC:              csr_rdata = mtvec_q;
                riscv::CSR_MCOUNTEREN:         csr_rdata = mcounteren_q;
                riscv::CSR_MSCRATCH:           csr_rdata = mscratch_q;
                riscv::CSR_MEPC:               csr_rdata = mepc_q;
                riscv::CSR_MCAUSE:             csr_rdata = mcause_q;
                riscv::CSR_MTVAL:              csr_rdata = mtval_q;
                riscv::CSR_MIP:                csr_rdata = mip_q;
                riscv::CSR_MVENDORID:          csr_rdata = '0;
                riscv::CSR_MARCHID:            csr_rdata = ARIANE_MARCHID;
                riscv::CSR_MIMPID:             csr_rdata = '0;
                riscv::CSR_MHARTID:            csr_rdata = hart_id_i;
                riscv::CSR_MCYCLE:             csr_rdata = cycle_q;
                riscv::CSR_MINSTRET:           csr_rdata = instret_q;

                riscv::CSR_CYCLE:              csr_rdata = cycle_q;
                riscv::CSR_INSTRET:            csr_rdata = instret_q;
                riscv::CSR_ML1_ICACHE_MISS,
                riscv::CSR_ML1_DCACHE_MISS,
                riscv::CSR_MITLB_MISS,
                riscv::CSR_MDTLB_MISS,
                riscv::CSR_MLOAD,
                riscv::CSR_MSTORE,
                riscv::CSR_MEXCEPTION,
                riscv::CSR_MEXCEPTION_RET,
                riscv::CSR_MBRANCH_JUMP,
                riscv::CSR_MCALL,
                riscv::CSR_MRET,
                riscv::CSR_MMIS_PREDICT,
                riscv::CSR_MSB_FULL,
                riscv::CSR_MIF_EMPTY,
                riscv::CSR_MHPM_COUNTER_17,
                riscv::CSR_MHPM_COUNTER_18,
                riscv::CSR_MHPM_COUNTER_19,
                riscv::CSR_MHPM_COUNTER_20,
                riscv::CSR_MHPM_COUNTER_21,
                riscv::CSR_MHPM_COUNTER_22,
                riscv::CSR_MHPM_COUNTER_23,
                riscv::CSR_MHPM_COUNTER_24,
                riscv::CSR_MHPM_COUNTER_25,
                riscv::CSR_MHPM_COUNTER_26,
                riscv::CSR_MHPM_COUNTER_27,
                riscv::CSR_MHPM_COUNTER_28,
                riscv::CSR_MHPM_COUNTER_29,
                riscv::CSR_MHPM_COUNTER_30,
                riscv::CSR_MHPM_COUNTER_31:           csr_rdata   = perf_data_i;

                riscv::CSR_DCACHE:           csr_rdata = dcache_q;
                riscv::CSR_ICACHE:           csr_rdata = icache_q;

                riscv::CSR_PMPCFG0:          csr_rdata = pmpcfg_q[7:0];
                riscv::CSR_PMPCFG2:          csr_rdata = pmpcfg_q[15:8];





                riscv::CSR_PMPADDR0:         csr_rdata = {10'b0, pmpaddr_q[0][riscv::PLEN-3:1], (pmpcfg_q[0].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR1:         csr_rdata = {10'b0, pmpaddr_q[1][riscv::PLEN-3:1], (pmpcfg_q[1].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR2:         csr_rdata = {10'b0, pmpaddr_q[2][riscv::PLEN-3:1], (pmpcfg_q[2].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR3:         csr_rdata = {10'b0, pmpaddr_q[3][riscv::PLEN-3:1], (pmpcfg_q[3].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR4:         csr_rdata = {10'b0, pmpaddr_q[4][riscv::PLEN-3:1], (pmpcfg_q[4].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR5:         csr_rdata = {10'b0, pmpaddr_q[5][riscv::PLEN-3:1], (pmpcfg_q[5].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR6:         csr_rdata = {10'b0, pmpaddr_q[6][riscv::PLEN-3:1], (pmpcfg_q[6].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR7:         csr_rdata = {10'b0, pmpaddr_q[7][riscv::PLEN-3:1], (pmpcfg_q[7].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR8:         csr_rdata = {10'b0, pmpaddr_q[8][riscv::PLEN-3:1], (pmpcfg_q[8].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR9:         csr_rdata = {10'b0, pmpaddr_q[9][riscv::PLEN-3:1], (pmpcfg_q[9].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR10:        csr_rdata = {10'b0, pmpaddr_q[10][riscv::PLEN-3:1], (pmpcfg_q[10].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR11:        csr_rdata = {10'b0, pmpaddr_q[11][riscv::PLEN-3:1], (pmpcfg_q[11].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR12:        csr_rdata = {10'b0, pmpaddr_q[12][riscv::PLEN-3:1], (pmpcfg_q[12].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR13:        csr_rdata = {10'b0, pmpaddr_q[13][riscv::PLEN-3:1], (pmpcfg_q[13].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR14:        csr_rdata = {10'b0, pmpaddr_q[14][riscv::PLEN-3:1], (pmpcfg_q[14].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                riscv::CSR_PMPADDR15:        csr_rdata = {10'b0, pmpaddr_q[15][riscv::PLEN-3:1], (pmpcfg_q[15].addr_mode[1] == 1'b1 ? 1'b1 : 1'b0)};
                default: read_access_exception = 1'b1;
            endcase
        end
    end



    riscv::xlen_t mask;
    always_comb begin : csr_update
        automatic riscv::satp_t satp;
        automatic riscv::xlen_t instret;


        satp = satp_q;
        instret = instret_q;




        cycle_d = cycle_q;
        instret_d = instret_q;
        if (!debug_mode_q) begin

            for (int i = 0; i < NrCommitPorts; i++) begin
                if (commit_ack_i[i] && !ex_i.valid) instret++;
            end
            instret_d = instret;

            if (ENABLE_CYCLE_COUNT) cycle_d = cycle_q + 1'b1;
            else cycle_d = instret;
        end

        eret_o                  = 1'b0;
        flush_o                 = 1'b0;
        update_access_exception = 1'b0;

        set_debug_pc_o          = 1'b0;

        perf_we_o               = 1'b0;
        perf_data_o             = 'b0;

        fcsr_d                  = fcsr_q;

        priv_lvl_d              = priv_lvl_q;
        debug_mode_d            = debug_mode_q;
        dcsr_d                  = dcsr_q;
        dpc_d                   = dpc_q;
        dscratch0_d             = dscratch0_q;
        dscratch1_d             = dscratch1_q;
        mstatus_d               = mstatus_q;







        if (mtvec_rst_load_q) begin
            mtvec_d             = {{riscv::XLEN-riscv::VLEN{1'b0}}, boot_addr_i} + 'h40;
        end else begin
            mtvec_d             = mtvec_q;
        end

        medeleg_d               = medeleg_q;
        mideleg_d               = mideleg_q;
        mip_d                   = mip_q;
        mie_d                   = mie_q;
        mepc_d                  = mepc_q;
        mcause_d                = mcause_q;
        mcounteren_d            = mcounteren_q;
        mscratch_d              = mscratch_q;
        mtval_d                 = mtval_q;
        dcache_d                = dcache_q;
        icache_d                = icache_q;

        sepc_d                  = sepc_q;
        scause_d                = scause_q;
        stvec_d                 = stvec_q;
        scounteren_d            = scounteren_q;
        sscratch_d              = sscratch_q;
        stval_d                 = stval_q;
        satp_d                  = satp_q;

        en_ld_st_translation_d  = en_ld_st_translation_q;
        dirty_fp_state_csr      = 1'b0;

        pmpcfg_d                = pmpcfg_q;
        pmpaddr_d               = pmpaddr_q;


        if (csr_we) begin
            unique case (csr_addr.address)

                riscv::CSR_FFLAGS: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.fflags = csr_wdata[4:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FRM: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.frm    = csr_wdata[2:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FCSR: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d[7:0] = csr_wdata[7:0];

                        flush_o = 1'b1;
                    end
                end
                riscv::CSR_FTRAN: begin
                    if (mstatus_q.fs == riscv::Off) begin
                        update_access_exception = 1'b1;
                    end else begin
                        dirty_fp_state_csr = 1'b1;
                        fcsr_d.fprec = csr_wdata[6:0];

                        flush_o = 1'b1;
                    end
                end

                riscv::CSR_DCSR: begin
                    dcsr_d = csr_wdata[31:0];

                    dcsr_d.xdebugver = 4'h4;

                    dcsr_d.nmip      = 1'b0;
                    dcsr_d.stopcount = 1'b0;
                    dcsr_d.stoptime  = 1'b0;
                end
                riscv::CSR_DPC:                dpc_d = csr_wdata;
                riscv::CSR_DSCRATCH0:          dscratch0_d = csr_wdata;
                riscv::CSR_DSCRATCH1:          dscratch1_d = csr_wdata;

                riscv::CSR_TSELECT:;
                riscv::CSR_TDATA1:;
                riscv::CSR_TDATA2:;
                riscv::CSR_TDATA3:;

                riscv::CSR_SSTATUS: begin
                    mask = ariane_pkg::SMODE_STATUS_WRITE_MASK[riscv::XLEN-1:0];
                    mstatus_d = (mstatus_q & ~{{64-riscv::XLEN{1'b0}}, mask}) | {{64-riscv::XLEN{1'b0}}, (csr_wdata & mask)};

                    if (!FP_PRESENT) begin
                        mstatus_d.fs = riscv::Off;
                    end

                    flush_o = 1'b1;
                end


                riscv::CSR_SIE: begin

                    mie_d = (mie_q & ~mideleg_q) | (csr_wdata & mideleg_q);
                end

                riscv::CSR_SIP: begin

                    mask = riscv::MIP_SSIP & mideleg_q;
                    mip_d = (mip_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_STVEC:              stvec_d     = {csr_wdata[riscv::XLEN-1:2], 1'b0, csr_wdata[0]};
                riscv::CSR_SCOUNTEREN:         scounteren_d = {{riscv::XLEN-32{1'b0}}, csr_wdata[31:0]};
                riscv::CSR_SSCRATCH:           sscratch_d  = csr_wdata;
                riscv::CSR_SEPC:               sepc_d      = {csr_wdata[riscv::XLEN-1:1], 1'b0};
                riscv::CSR_SCAUSE:             scause_d    = csr_wdata;
                riscv::CSR_STVAL:              stval_d     = csr_wdata;

                riscv::CSR_SATP: begin

                    if (priv_lvl_o == riscv::PRIV_LVL_S && mstatus_q.tvm)
                        update_access_exception = 1'b1;
                    else begin
                        satp      = riscv::satp_t'(csr_wdata);

                        satp.asid = satp.asid & {{(riscv::ASIDW-AsidWidth){1'b0}}, {AsidWidth{1'b1}}};

                        if (riscv::vm_mode_t'(satp.mode) == riscv::ModeOff ||
                            riscv::vm_mode_t'(satp.mode) == riscv::MODE_SV) satp_d = satp;
                    end


                    flush_o = 1'b1;
                end

                riscv::CSR_MSTATUS: begin
                    mstatus_d      = {{64-riscv::XLEN{1'b0}}, csr_wdata};
                    mstatus_d.xs   = riscv::Off;
                    if (!FP_PRESENT) begin
                        mstatus_d.fs = riscv::Off;
                    end
                    mstatus_d.upie = 1'b0;
                    mstatus_d.uie  = 1'b0;

                    flush_o        = 1'b1;
                end

                riscv::CSR_MISA:;


                riscv::CSR_MEDELEG: begin
                    mask = (1 << riscv::INSTR_ADDR_MISALIGNED) |
                           (1 << riscv::BREAKPOINT) |
                           (1 << riscv::ENV_CALL_UMODE) |
                           (1 << riscv::INSTR_PAGE_FAULT) |
                           (1 << riscv::LOAD_PAGE_FAULT) |
                           (1 << riscv::STORE_PAGE_FAULT);
                    medeleg_d = (medeleg_q & ~mask) | (csr_wdata & mask);
                end


                riscv::CSR_MIDELEG: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP;
                    mideleg_d = (mideleg_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MIE: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP | riscv::MIP_MSIP | riscv::MIP_MTIP | riscv::MIP_MEIP;
                    mie_d = (mie_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MTVEC: begin
                    mtvec_d = {csr_wdata[riscv::XLEN-1:2], 1'b0, csr_wdata[0]};


                    if (csr_wdata[0]) mtvec_d = {csr_wdata[riscv::XLEN-1:8], 7'b0, csr_wdata[0]};
                end
                riscv::CSR_MCOUNTEREN:         mcounteren_d = {{riscv::XLEN-32{1'b0}}, csr_wdata[31:0]};

                riscv::CSR_MSCRATCH:           mscratch_d  = csr_wdata;
                riscv::CSR_MEPC:               mepc_d      = {csr_wdata[riscv::XLEN-1:1], 1'b0};
                riscv::CSR_MCAUSE:             mcause_d    = csr_wdata;
                riscv::CSR_MTVAL:              mtval_d     = csr_wdata;
                riscv::CSR_MIP: begin
                    mask = riscv::MIP_SSIP | riscv::MIP_STIP | riscv::MIP_SEIP;
                    mip_d = (mip_q & ~mask) | (csr_wdata & mask);
                end

                riscv::CSR_MCYCLE:             cycle_d     = csr_wdata;
                riscv::CSR_MINSTRET:           instret     = csr_wdata;
                riscv::CSR_ML1_ICACHE_MISS,
                riscv::CSR_ML1_DCACHE_MISS,
                riscv::CSR_MITLB_MISS,
                riscv::CSR_MDTLB_MISS,
                riscv::CSR_MLOAD,
                riscv::CSR_MSTORE,
                riscv::CSR_MEXCEPTION,
                riscv::CSR_MEXCEPTION_RET,
                riscv::CSR_MBRANCH_JUMP,
                riscv::CSR_MCALL,
                riscv::CSR_MRET,
                riscv::CSR_MMIS_PREDICT,
                riscv::CSR_MSB_FULL,
                riscv::CSR_MIF_EMPTY,
                riscv::CSR_MHPM_COUNTER_17,
                riscv::CSR_MHPM_COUNTER_18,
                riscv::CSR_MHPM_COUNTER_19,
                riscv::CSR_MHPM_COUNTER_20,
                riscv::CSR_MHPM_COUNTER_21,
                riscv::CSR_MHPM_COUNTER_22,
                riscv::CSR_MHPM_COUNTER_23,
                riscv::CSR_MHPM_COUNTER_24,
                riscv::CSR_MHPM_COUNTER_25,
                riscv::CSR_MHPM_COUNTER_26,
                riscv::CSR_MHPM_COUNTER_27,
                riscv::CSR_MHPM_COUNTER_28,
                riscv::CSR_MHPM_COUNTER_29,
                riscv::CSR_MHPM_COUNTER_30,
                riscv::CSR_MHPM_COUNTER_31: begin
                                        perf_data_o = csr_wdata;
                                        perf_we_o   = 1'b1;
                end

                riscv::CSR_DCACHE:             dcache_d    = {{riscv::XLEN-1{1'b0}}, csr_wdata[0]};
                riscv::CSR_ICACHE:             icache_d    = {{riscv::XLEN-1{1'b0}}, csr_wdata[0]};




                riscv::CSR_PMPCFG0:    for (int i = 0; i < (riscv::XLEN/8); i++) if (!pmpcfg_q[i].locked) pmpcfg_d[i]  = csr_wdata[i*8+:8];
                riscv::CSR_PMPCFG1: begin
                    if (riscv::XLEN == 32) begin
                        for (int i = 0; i < 4; i++) if (!pmpcfg_q[i+4].locked) pmpcfg_d[i+4]  = csr_wdata[i*8+:8];
                    end
                end
                riscv::CSR_PMPCFG2:    for (int i = 0; i < (riscv::XLEN/8); i++) if (!pmpcfg_q[i+8].locked) pmpcfg_d[i+8]  = csr_wdata[i*8+:8];
                riscv::CSR_PMPCFG3: begin
                    if (riscv::XLEN == 32) begin
                        for (int i = 0; i < 4; i++) if (!pmpcfg_q[i+12].locked) pmpcfg_d[i+12]  = csr_wdata[i*8+:8];
                    end
                end
                riscv::CSR_PMPADDR0:   if (!pmpcfg_q[ 0].locked && !(pmpcfg_q[ 1].locked && pmpcfg_q[ 1].addr_mode == riscv::TOR))  pmpaddr_d[0]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR1:   if (!pmpcfg_q[ 1].locked && !(pmpcfg_q[ 2].locked && pmpcfg_q[ 2].addr_mode == riscv::TOR))  pmpaddr_d[1]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR2:   if (!pmpcfg_q[ 2].locked && !(pmpcfg_q[ 3].locked && pmpcfg_q[ 3].addr_mode == riscv::TOR))  pmpaddr_d[2]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR3:   if (!pmpcfg_q[ 3].locked && !(pmpcfg_q[ 4].locked && pmpcfg_q[ 4].addr_mode == riscv::TOR))  pmpaddr_d[3]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR4:   if (!pmpcfg_q[ 4].locked && !(pmpcfg_q[ 5].locked && pmpcfg_q[ 5].addr_mode == riscv::TOR))  pmpaddr_d[4]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR5:   if (!pmpcfg_q[ 5].locked && !(pmpcfg_q[ 6].locked && pmpcfg_q[ 6].addr_mode == riscv::TOR))  pmpaddr_d[5]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR6:   if (!pmpcfg_q[ 6].locked && !(pmpcfg_q[ 7].locked && pmpcfg_q[ 7].addr_mode == riscv::TOR))  pmpaddr_d[6]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR7:   if (!pmpcfg_q[ 7].locked && !(pmpcfg_q[ 8].locked && pmpcfg_q[ 8].addr_mode == riscv::TOR))  pmpaddr_d[7]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR8:   if (!pmpcfg_q[ 8].locked && !(pmpcfg_q[ 9].locked && pmpcfg_q[ 9].addr_mode == riscv::TOR))  pmpaddr_d[8]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR9:   if (!pmpcfg_q[ 9].locked && !(pmpcfg_q[10].locked && pmpcfg_q[10].addr_mode == riscv::TOR))  pmpaddr_d[9]   = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR10:  if (!pmpcfg_q[10].locked && !(pmpcfg_q[11].locked && pmpcfg_q[11].addr_mode == riscv::TOR))  pmpaddr_d[10]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR11:  if (!pmpcfg_q[11].locked && !(pmpcfg_q[12].locked && pmpcfg_q[12].addr_mode == riscv::TOR))  pmpaddr_d[11]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR12:  if (!pmpcfg_q[12].locked && !(pmpcfg_q[13].locked && pmpcfg_q[13].addr_mode == riscv::TOR))  pmpaddr_d[12]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR13:  if (!pmpcfg_q[13].locked && !(pmpcfg_q[14].locked && pmpcfg_q[14].addr_mode == riscv::TOR))  pmpaddr_d[13]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR14:  if (!pmpcfg_q[14].locked && !(pmpcfg_q[15].locked && pmpcfg_q[15].addr_mode == riscv::TOR))  pmpaddr_d[14]  = csr_wdata[riscv::PLEN-3:0];
                riscv::CSR_PMPADDR15:  if (!pmpcfg_q[15].locked)  pmpaddr_d[15]  = csr_wdata[riscv::PLEN-3:0];
                default: update_access_exception = 1'b1;
            endcase
        end

        mstatus_d.sxl  = riscv::XLEN_64;
        mstatus_d.uxl  = riscv::XLEN_64;


        if (FP_PRESENT && (dirty_fp_state_csr || dirty_fp_state_i)) begin
            mstatus_d.fs = riscv::Dirty;
        end

        mstatus_d.sd   = (mstatus_q.xs == riscv::Dirty) | (mstatus_q.fs == riscv::Dirty);


        if (csr_write_fflags_i) begin
            fcsr_d.fflags = csr_wdata_i[4:0] | fcsr_q.fflags;
        end




        mip_d[riscv::IRQ_M_EXT] = irq_i[0];

        mip_d[riscv::IRQ_M_SOFT] = ipi_i;

        mip_d[riscv::IRQ_M_TIMER] = time_irq_i;






        trap_to_priv_lvl = riscv::PRIV_LVL_M;


        if (!debug_mode_q && ex_i.cause != riscv::DEBUG_REQUEST && ex_i.valid) begin

            flush_o   = 1'b0;




            if ((ex_i.cause[riscv::XLEN-1] && mideleg_q[ex_i.cause[$clog2(riscv::XLEN)-1:0]]) ||
                (~ex_i.cause[riscv::XLEN-1] && medeleg_q[ex_i.cause[$clog2(riscv::XLEN)-1:0]])) begin


                trap_to_priv_lvl = (priv_lvl_o == riscv::PRIV_LVL_M) ? riscv::PRIV_LVL_M : riscv::PRIV_LVL_S;
            end


            if (trap_to_priv_lvl == riscv::PRIV_LVL_S) begin

                mstatus_d.sie  = 1'b0;
                mstatus_d.spie = mstatus_q.sie;

                mstatus_d.spp  = priv_lvl_q[0];

                scause_d       = ex_i.cause;

                sepc_d         = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                stval_d        = (ariane_pkg::ZERO_TVAL
                                  && (ex_i.cause inside {
                                    riscv::ILLEGAL_INSTR,
                                    riscv::BREAKPOINT,
                                    riscv::ENV_CALL_UMODE,
                                    riscv::ENV_CALL_SMODE,
                                    riscv::ENV_CALL_MMODE
                                  } || ex_i.cause[riscv::XLEN-1])) ? '0 : ex_i.tval;

            end else begin

                mstatus_d.mie  = 1'b0;
                mstatus_d.mpie = mstatus_q.mie;

                mstatus_d.mpp  = priv_lvl_q;
                mcause_d       = ex_i.cause;

                mepc_d         = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                mtval_d        = (ariane_pkg::ZERO_TVAL
                                  && (ex_i.cause inside {
                                    riscv::ILLEGAL_INSTR,
                                    riscv::BREAKPOINT,
                                    riscv::ENV_CALL_UMODE,
                                    riscv::ENV_CALL_SMODE,
                                    riscv::ENV_CALL_MMODE
                                  } || ex_i.cause[riscv::XLEN-1])) ? '0 : ex_i.tval;
            end

            priv_lvl_d = trap_to_priv_lvl;
        end











        if (!debug_mode_q) begin
            dcsr_d.prv = priv_lvl_o;



            if (ex_i.valid && ex_i.cause == riscv::BREAKPOINT) begin
                dcsr_d.prv = priv_lvl_o;

                unique case (priv_lvl_o)
                    riscv::PRIV_LVL_M: begin
                        debug_mode_d = dcsr_q.ebreakm;
                        set_debug_pc_o = dcsr_q.ebreakm;
                    end
                    riscv::PRIV_LVL_S: begin
                        debug_mode_d = dcsr_q.ebreaks;
                        set_debug_pc_o = dcsr_q.ebreaks;
                    end
                    riscv::PRIV_LVL_U: begin
                        debug_mode_d = dcsr_q.ebreaku;
                        set_debug_pc_o = dcsr_q.ebreaku;
                    end
                    default:;
                endcase

                dpc_d = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};
                dcsr_d.cause = dm::CauseBreakpoint;
            end


            if (ex_i.valid && ex_i.cause == riscv::DEBUG_REQUEST) begin
                dcsr_d.prv = priv_lvl_o;

                dpc_d = {{riscv::XLEN-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};

                debug_mode_d = 1'b1;

                set_debug_pc_o = 1'b1;

                dcsr_d.cause = dm::CauseRequest;
            end


            if (dcsr_q.step && commit_ack_i[0]) begin
                dcsr_d.prv = priv_lvl_o;

                if (commit_instr_i[0].fu == CTRL_FLOW) begin

                    dpc_d = {{riscv::XLEN-riscv::VLEN{commit_instr_i[0].bp.predict_address[riscv::VLEN-1]}}, commit_instr_i[0].bp.predict_address};

                end else if (ex_i.valid) begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{1'b0}},trap_vector_base_o};

                end else if (eret_o) begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{1'b0}},epc_o};

                end else begin
                    dpc_d = {{riscv::XLEN-riscv::VLEN{commit_instr_i[0].pc[riscv::VLEN-1]}}, commit_instr_i[0].pc + (commit_instr_i[0].is_compressed ? 'h2 : 'h4)};
                end
                debug_mode_d = 1'b1;
                set_debug_pc_o = 1'b1;
                dcsr_d.cause = dm::CauseSingleStep;
            end
        end

        if (debug_mode_q && ex_i.valid && ex_i.cause == riscv::BREAKPOINT) begin
            set_debug_pc_o = 1'b1;
        end






        if (mprv && riscv::vm_mode_t'(satp_q.mode) == riscv::MODE_SV && (mstatus_q.mpp != riscv::PRIV_LVL_M))
            en_ld_st_translation_d = 1'b1;
        else
            en_ld_st_translation_d = en_translation_o;

        ld_st_priv_lvl_o = (mprv) ? mstatus_q.mpp : priv_lvl_o;
        en_ld_st_translation_o = en_ld_st_translation_q;





        if (mret) begin

            eret_o = 1'b1;


            mstatus_d.mie  = mstatus_q.mpie;

            priv_lvl_d     = mstatus_q.mpp;

            mstatus_d.mpp  = riscv::PRIV_LVL_U;

            mstatus_d.mpie = 1'b1;
        end

        if (sret) begin

            eret_o = 1'b1;

            mstatus_d.sie  = mstatus_q.spie;

            priv_lvl_d     = riscv::priv_lvl_t'({1'b0, mstatus_q.spp});

            mstatus_d.spp  = 1'b0;

            mstatus_d.spie = 1'b1;
        end


        if (dret) begin

            eret_o = 1'b1;

            priv_lvl_d     = riscv::priv_lvl_t'(dcsr_q.prv);

            debug_mode_d = 1'b0;
        end
    end




    always_comb begin : csr_op_logic
        csr_wdata = csr_wdata_i;
        csr_we    = 1'b1;
        csr_read  = 1'b1;
        mret      = 1'b0;
        sret      = 1'b0;
        dret      = 1'b0;

        unique case (csr_op_i)
            CSR_WRITE: csr_wdata = csr_wdata_i;
            CSR_SET:   csr_wdata = csr_wdata_i | csr_rdata;
            CSR_CLEAR: csr_wdata = (~csr_wdata_i) & csr_rdata;
            CSR_READ:  csr_we    = 1'b0;
            SRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                sret     = 1'b1;
            end
            MRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                mret     = 1'b1;
            end
            DRET: begin

                csr_we   = 1'b0;
                csr_read = 1'b0;
                dret     = 1'b1;
            end
            default: begin
                csr_we   = 1'b0;
                csr_read = 1'b0;
            end
        endcase

        if (privilege_violation) begin
            csr_we = 1'b0;
            csr_read = 1'b0;
        end
    end

    assign irq_ctrl_o.mie = mie_q;
    assign irq_ctrl_o.mip = mip_q;
    assign irq_ctrl_o.sie = mstatus_q.sie;
    assign irq_ctrl_o.mideleg = mideleg_q;
    assign irq_ctrl_o.global_enable = (~debug_mode_q)

                                    & (~dcsr_q.step | dcsr_q.stepie)
                                    & ((mstatus_q.mie & (priv_lvl_o == riscv::PRIV_LVL_M))
                                    | (priv_lvl_o != riscv::PRIV_LVL_M));

    always_comb begin : privilege_check



        privilege_violation = 1'b0;


        if (csr_op_i inside {CSR_WRITE, CSR_SET, CSR_CLEAR, CSR_READ}) begin
            if ((riscv::priv_lvl_t'(priv_lvl_o & csr_addr.csr_decode.priv_lvl) != csr_addr.csr_decode.priv_lvl)) begin
                privilege_violation = 1'b1;
            end

            if (csr_addr_i[11:4] == 8'h7b && !debug_mode_q) begin
                privilege_violation = 1'b1;
            end


            if (csr_addr_i inside {[riscv::CSR_CYCLE:riscv::CSR_HPM_COUNTER_31]}) begin
                unique case (csr_addr.csr_decode.priv_lvl)
                    riscv::PRIV_LVL_M: privilege_violation = 1'b0;
                    riscv::PRIV_LVL_S: privilege_violation = ~mcounteren_q[csr_addr_i[4:0]];
                    riscv::PRIV_LVL_U: privilege_violation = ~mcounteren_q[csr_addr_i[4:0]] & ~scounteren_q[csr_addr_i[4:0]];
                endcase
            end
        end
    end



    always_comb begin : exception_ctrl
        csr_exception_o = {
            '0, '0, 1'b0
        };





        if (update_access_exception || read_access_exception) begin
            csr_exception_o.cause = riscv::ILLEGAL_INSTR;


            csr_exception_o.valid = 1'b1;
        end

        if (privilege_violation) begin
          csr_exception_o.cause = riscv::ILLEGAL_INSTR;
          csr_exception_o.valid = 1'b1;
        end
    end




    always_comb begin : wfi_ctrl

        wfi_d = wfi_q;


        if (|mip_q || debug_req_i || irq_i[1]) begin
            wfi_d = 1'b0;


        end else if (!debug_mode_q && csr_op_i == WFI && !ex_i.valid) begin
            wfi_d = 1'b1;
        end
    end


    always_comb begin : priv_output
        trap_vector_base_o = {mtvec_q[riscv::VLEN-1:2], 2'b0};

        if (trap_to_priv_lvl == riscv::PRIV_LVL_S) begin
            trap_vector_base_o = {stvec_q[riscv::VLEN-1:2], 2'b0};
        end


        if (debug_mode_q) begin
            trap_vector_base_o = DmBaseAddress[riscv::VLEN-1:0] + dm::ExceptionAddress[riscv::VLEN-1:0];
        end




        if ((mtvec_q[0] || stvec_q[0]) && ex_i.cause[riscv::XLEN-1]) begin
            trap_vector_base_o[7:2] = ex_i.cause[5:0];
        end

        epc_o = mepc_q[riscv::VLEN-1:0];

        if (sret) begin
            epc_o = sepc_q[riscv::VLEN-1:0];
        end

        if (dret) begin
            epc_o = dpc_q[riscv::VLEN-1:0];
        end
    end




    always_comb begin



        csr_rdata_o = csr_rdata;

        unique case (csr_addr.address)
            riscv::CSR_MIP: csr_rdata_o = csr_rdata | (irq_i[1] << riscv::IRQ_S_EXT);

            riscv::CSR_SIP: begin
                csr_rdata_o = csr_rdata
                            | ((irq_i[1] & mideleg_q[riscv::IRQ_S_EXT]) << riscv::IRQ_S_EXT);
            end
            default:;
        endcase
    end


    assign priv_lvl_o       = (debug_mode_q) ? riscv::PRIV_LVL_M : priv_lvl_q;

    assign fflags_o         = fcsr_q.fflags;
    assign frm_o            = fcsr_q.frm;
    assign fprec_o          = fcsr_q.fprec;

    assign satp_ppn_o       = satp_q.ppn;
    assign asid_o           = satp_q.asid[AsidWidth-1:0];
    assign sum_o            = mstatus_q.sum;

    assign en_translation_o = (riscv::vm_mode_t'(satp_q.mode) == riscv::MODE_SV &&
                               priv_lvl_o != riscv::PRIV_LVL_M)
                              ? 1'b1
                              : 1'b0;
    assign mxr_o            = mstatus_q.mxr;
    assign tvm_o            = mstatus_q.tvm;
    assign tw_o             = mstatus_q.tw;
    assign tsr_o            = mstatus_q.tsr;
    assign halt_csr_o       = wfi_q;
`ifdef PITON_ARIANE
    assign icache_en_o      = icache_q[0];
`else
    assign icache_en_o      = icache_q[0] & (~debug_mode_q);
`endif
    assign dcache_en_o      = dcache_q[0];


    assign mprv             = (debug_mode_q && !dcsr_q.mprven) ? 1'b0 : mstatus_q.mprv;
    assign debug_mode_o     = debug_mode_q;
    assign single_step_o    = dcsr_q.step;


    always_ff @(posedge clk_i or negedge rst_ni) begin
        if (~rst_ni) begin
            priv_lvl_q             <= riscv::PRIV_LVL_M;

            fcsr_q                 <= '0;

`ifdef DROMAJO
            debug_mode_q           <= 1'b1;
`else
            debug_mode_q           <= 1'b0;
`endif
            dcsr_q                 <= '0;
            dcsr_q.prv             <= riscv::PRIV_LVL_M;
            dpc_q                  <= '0;
            dscratch0_q            <= {riscv::XLEN{1'b0}};
            dscratch1_q            <= {riscv::XLEN{1'b0}};

            mstatus_q              <= 64'b0;

            mtvec_rst_load_q       <= 1'b1;
            mtvec_q                <= '0;
            medeleg_q              <= {riscv::XLEN{1'b0}};
            mideleg_q              <= {riscv::XLEN{1'b0}};
            mip_q                  <= {riscv::XLEN{1'b0}};
            mie_q                  <= {riscv::XLEN{1'b0}};
            mepc_q                 <= {riscv::XLEN{1'b0}};
            mcause_q               <= {riscv::XLEN{1'b0}};
            mcounteren_q           <= {riscv::XLEN{1'b0}};
            mscratch_q             <= {riscv::XLEN{1'b0}};
            mtval_q                <= {riscv::XLEN{1'b0}};
            dcache_q               <= {{riscv::XLEN-1{1'b0}}, 1'b1};
            icache_q               <= {{riscv::XLEN-1{1'b0}}, 1'b1};

            sepc_q                 <= {riscv::XLEN{1'b0}};
            scause_q               <= {riscv::XLEN{1'b0}};
            stvec_q                <= {riscv::XLEN{1'b0}};
            scounteren_q           <= {riscv::XLEN{1'b0}};
            sscratch_q             <= {riscv::XLEN{1'b0}};
            stval_q                <= {riscv::XLEN{1'b0}};
            satp_q                 <= {riscv::XLEN{1'b0}};

            cycle_q                <= {riscv::XLEN{1'b0}};
            instret_q              <= {riscv::XLEN{1'b0}};

            en_ld_st_translation_q <= 1'b0;

            wfi_q                  <= 1'b0;

            pmpcfg_q               <= '0;
            pmpaddr_q              <= '0;
        end else begin
            priv_lvl_q             <= priv_lvl_d;

            fcsr_q                 <= fcsr_d;

            debug_mode_q           <= debug_mode_d;
            dcsr_q                 <= dcsr_d;
            dpc_q                  <= dpc_d;
            dscratch0_q            <= dscratch0_d;
            dscratch1_q            <= dscratch1_d;

            mstatus_q              <= mstatus_d;
            mtvec_rst_load_q       <= 1'b0;
            mtvec_q                <= mtvec_d;
            medeleg_q              <= medeleg_d;
            mideleg_q              <= mideleg_d;
            mip_q                  <= mip_d;
            mie_q                  <= mie_d;
            mepc_q                 <= mepc_d;
            mcause_q               <= mcause_d;
            mcounteren_q           <= mcounteren_d;
            mscratch_q             <= mscratch_d;
            mtval_q                <= mtval_d;
            dcache_q               <= dcache_d;
            icache_q               <= icache_d;

            sepc_q                 <= sepc_d;
            scause_q               <= scause_d;
            stvec_q                <= stvec_d;
            scounteren_q           <= scounteren_d;
            sscratch_q             <= sscratch_d;
            stval_q                <= stval_d;
            satp_q                 <= satp_d;

            cycle_q                <= cycle_d;
            instret_q              <= instret_d;

            en_ld_st_translation_q <= en_ld_st_translation_d;

            wfi_q                  <= wfi_d;

            for(int i = 0; i < 16; i++) begin
                if(i < NrPMPEntries) begin
                    pmpcfg_q[i] <= pmpcfg_d[i];
                    pmpaddr_q[i] <= pmpaddr_d[i];
                end else begin
                    pmpcfg_q[i] <= '0;
                    pmpaddr_q[i] <= '0;
                end
            end
        end
    end





    `ifndef VERILATOR

        assert property (
          @(posedge clk_i) !(eret_o && ex_i.valid))
        else begin $error("eret and exception should never be valid at the same time"); $stop(); end
    `endif

endmodule