Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2019- RSD contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
//
// CSR Unit
//
`include "BasicMacros.sv"
import BasicTypes::*;
import MemoryMapTypes::*;
import CSR_UnitTypes::*;
import OpFormatTypes::*;
import SchedulerTypes::*;
import ActiveListIndexTypes::*;
module CSR_Unit(
CSR_UnitIF.CSR_Unit port,
PerformanceCounterIF.CSR perfCounter
);
CSR_BodyPath csrReg, csrNext;
DataPath rv;
CSR_ValuePath wv;
DataPath mcycle; // for debug
AddrPath jumpTarget;
CommitLaneCountPath regCommitNum;
// An external interrupt request is latched in the CSR, and an actual
// interrupt is triggered at the next cycle. So external interrupt code must be latched.
ExternalInterruptCodePath externalInterruptCodeReg;
always_ff@(posedge port.clk) begin
if (port.rst) begin
csrReg <= '0;
regCommitNum <= '0;
externalInterruptCodeReg <= '0;
end
else begin
csrReg <= csrNext;
regCommitNum <= port.commitNum;
externalInterruptCodeReg <= port.externalInterruptCode;
end
end
always_comb begin
mcycle = csrReg.mcycle;
// Read a CSR value
unique case (port.csrNumber)
CSR_NUM_MSTATUS: rv = csrReg.mstatus;
CSR_NUM_MIP: rv = csrReg.mip;
CSR_NUM_MIE: rv = csrReg.mie;
CSR_NUM_MCAUSE: rv = csrReg.mcause;
CSR_NUM_MTVEC: rv = csrReg.mtvec;
CSR_NUM_MTVAL: rv = csrReg.mtval;
CSR_NUM_MEPC: rv = csrReg.mepc;
CSR_NUM_MSCRATCH: rv = csrReg.mscratch;
CSR_NUM_MCYCLE: rv = csrReg.mcycle;
CSR_NUM_MINSTRET: rv = csrReg.minstret;
`ifndef RSD_DISABLE_PERFORMANCE_COUNTER
CSR_NUM_MHPMCOUNTER3: rv = perfCounter.perfCounter.numLoadMiss;
CSR_NUM_MHPMCOUNTER4: rv = perfCounter.perfCounter.numStoreMiss;
CSR_NUM_MHPMCOUNTER5: rv = perfCounter.perfCounter.numIC_Miss;
CSR_NUM_MHPMCOUNTER6: rv = perfCounter.perfCounter.numBranchPredMiss;
`endif
`ifdef RSD_MARCH_FP_PIPE
CSR_NUM_FFLAGS: rv = csrReg.fcsr.fflags;
CSR_NUM_FRM: rv = csrReg.fcsr.frm;
CSR_NUM_FCSR: rv = csrReg.fcsr;
`endif
default: rv = '0;
endcase
// Writeback
csrNext = csrReg;
// Update Cycles
csrNext.mcycle = csrNext.mcycle + 1;
csrNext.minstret = csrNext.minstret + regCommitNum;
wv = '0;
if (port.triggerInterrupt) begin
// Interrupt
csrNext.mstatus.MPIE = csrNext.mstatus.MIE; // MIE の古い値
csrNext.mstatus.MIE = 0; // グローバル割り込み許可を落とす
csrNext.mepc = ToAddrFromPC(port.interruptRetAddr); // 割り込み発生時の PC
csrNext.mtval = ToAddrFromPC(port.interruptRetAddr);// PC?
csrNext.mcause.isInterrupt = TRUE;
csrNext.mcause.code.interruptCode = port.interruptCode;
//$display("int: from %x", port.interruptRetAddr);
end
else if (port.triggerExcpt) begin
if (port.excptCause == EXEC_STATE_TRAP_MRET) begin
// MRET
csrNext.mstatus.MIE = csrNext.mstatus.MPIE; // MIE の古い値に戻す
//$display("mret: to %x", csrNext.mepc);
end
else begin
// Trap
csrNext.mstatus.MPIE = csrNext.mstatus.MIE; // MIE の古い値
csrNext.mstatus.MIE = 0; // グローバル割り込み許可を落とす
csrNext.mepc = ToAddrFromPC(port.excptCauseAddr); // 例外の発生元 PC を書き込む
csrNext.mtval = port.excptCauseDataAddr;// ECALL/EBREAK の場合は PC?
csrNext.mcause.isInterrupt = FALSE;
csrNext.mcause.code.trapCode = ToTrapCodeFromExecState(port.excptCause);
//$display("trap: from %x", csrNext.mepc);
end
end
else if (port.csrWE) begin
// Operation
unique case (port.csrCode)
CSR_WRITE: wv = port.csrWriteIn;
CSR_SET: wv = rv | port.csrWriteIn;
CSR_CLEAR: wv = rv & (~port.csrWriteIn);
default: wv = port.csrWriteIn; // ???
endcase
unique case (port.csrNumber)
CSR_NUM_MSTATUS: begin
//csrNext.mstatus.MIE = wv.mstatus.MIE;
//csrNext.mstatus.MPIE = wv.mstatus.MPIE;
csrNext.mstatus = wv;
//$display("mstatus: %x", wv);
end
// MIP
// > Only the bits corresponding to lower-privilege
// > software interrupts (USIP, SSIP), timer interrupts (UTIP,
// > STIP), and external interrupts (UEIP, SEIP) in mip are writable
// > through this CSR address; the remaining bits are read-only.
// Currently, only MTIP is supported and thus this is write only.
//CSR_NUM_MIP: csrNext.mip = wv;
CSR_NUM_MIE:begin
csrNext.mie = wv;
//$display("mie: %x", wv);
end
CSR_NUM_MCAUSE: csrNext.mcause = wv;
CSR_NUM_MTVEC: csrNext.mtvec = wv;
CSR_NUM_MTVAL: csrNext.mtval = wv;
// The low bit of mepc is always zero,
// as described in Chapter 3.1.19 of RISC-V Privileged Architectures.
CSR_NUM_MEPC: csrNext.mepc = {wv[31:1], 1'b0};
CSR_NUM_MSCRATCH: csrNext.mscratch = wv;
CSR_NUM_MCYCLE: csrNext.mcycle = wv;
CSR_NUM_MINSTRET: csrNext.minstret = wv;
`ifdef RSD_MARCH_FP_PIPE
CSR_NUM_FFLAGS: csrNext.fcsr.fflags = wv;
CSR_NUM_FRM: csrNext.fcsr.frm = Rounding_Mode'(wv);
CSR_NUM_FCSR: csrNext.fcsr = FFlags_Path'(wv);
`endif
default: wv = '0; // dummy
endcase
end
`ifdef RSD_MARCH_FP_PIPE
// write to fflags from FP-CM and Mem-EX(CSR) shouldn't occur at the same time.
else if(port.fflagsWE) begin
csrNext.fcsr.fflags = port.fflagsData;
end
port.fflags = csrReg.fcsr.fflags;
port.frm = csrReg.fcsr.frm;
`endif
csrNext.mip.MTIP = port.reqTimerInterrupt; // Timer interrupt request
csrNext.mip.MEIP = port.reqExternalInterrupt; // External interrupt request
port.externalInterruptCodeInCSR = externalInterruptCodeReg;
port.csrReadOut = rv;
if (port.excptCause == EXEC_STATE_TRAP_MRET) begin
port.excptTargetAddr = csrReg.mepc;
end
else begin
port.excptTargetAddr = {csrReg.mtvec.base, CSR_MTVEC_BASE_PADDING};
end
port.csrWholeOut = csrReg;
end
`RSD_ASSERT_CLK(
port.clk,
!(port.triggerExcpt && !(port.excptCause inside {
EXEC_STATE_TRAP_ECALL,
EXEC_STATE_TRAP_EBREAK,
EXEC_STATE_TRAP_MRET,
EXEC_STATE_FAULT_LOAD_MISALIGNED,
EXEC_STATE_FAULT_LOAD_VIOLATION,
EXEC_STATE_FAULT_STORE_MISALIGNED,
EXEC_STATE_FAULT_STORE_VIOLATION,
EXEC_STATE_FAULT_INSN_ILLEGAL,
EXEC_STATE_FAULT_INSN_VIOLATION,
EXEC_STATE_FAULT_INSN_MISALIGNED
})),
"Invalid exception cause is passed"
);
`RSD_ASSERT_CLK(
port.clk,
!(
(port.triggerExcpt && port.csrWE) ||
(port.triggerInterrupt && port.csrWE) ||
(port.triggerExcpt && port.triggerInterrupt)
),
"CSR update, trap or interrupt are performed at the same cycle"
);
endmodule : CSR_Unit
7b65f6ba0This file is pinned to the selected release. Download the original to open it in your design tool.