feat: implement privileged mode support

This commit is contained in:
abnerhexu
2026-06-29 07:00:55 +00:00
parent a32db39c80
commit b6afa61e66
89 changed files with 49571 additions and 43647 deletions

View File

@@ -5,20 +5,42 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
val io = IO(new Bundle {
val cmd = Input(new CsrCommand(p))
val readAddr = Input(UInt(12.W))
val currentPriv = Input(UInt(2.W))
val rdata = Output(UInt(p.xlen.W))
val readIllegal = Output(Bool())
val writeIllegal = Output(Bool())
val illegal = Output(Bool())
val trap = Input(Bool())
val trapPc = Input(UInt(p.xlen.W))
val trapCause = Input(UInt(p.xlen.W))
val trapTval = Input(UInt(p.xlen.W))
val trapTargetPriv = Input(UInt(2.W))
val trapIsInterrupt = Input(Bool())
val trapVector = Output(UInt(p.xlen.W))
val xret = Input(Bool())
val xretIsMret = Input(Bool())
val satp = Output(UInt(p.xlen.W))
val mtvec = Output(UInt(p.xlen.W))
val mepc = Output(UInt(p.xlen.W))
val stvec = Output(UInt(p.xlen.W))
val sepc = Output(UInt(p.xlen.W))
val medeleg = Output(UInt(p.xlen.W))
val mideleg = Output(UInt(p.xlen.W))
val mie = Output(UInt(p.xlen.W))
val mip = Output(UInt(p.xlen.W))
val mstatus = Output(UInt(p.xlen.W))
})
val cycle = RegInit(0.U(p.xlen.W))
val instret = RegInit(0.U(p.xlen.W))
val mcountinhibit = RegInit(0.U(p.xlen.W))
val suppressInstretIncrement = WireDefault(false.B)
val suppressInstretAfterWrite = RegInit(false.B)
dontTouch(suppressInstretIncrement)
val mstatus = RegInit(0.U(p.xlen.W))
val misa = RegInit("h800000000014112d".U(p.xlen.W))
val misa = RegInit(Privileged.MISA_RV64_IMASU)
val mtvecReg = RegInit(0.U(p.xlen.W))
val mscratch = RegInit(0.U(p.xlen.W))
val mepcReg = RegInit(0.U(p.xlen.W))
val mcause = RegInit(0.U(p.xlen.W))
val mtval = RegInit(0.U(p.xlen.W))
@@ -26,7 +48,14 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
val mideleg = RegInit(0.U(p.xlen.W))
val mie = RegInit(0.U(p.xlen.W))
val mip = RegInit(0.U(p.xlen.W))
val sstatus = RegInit(0.U(p.xlen.W))
val mcounteren = RegInit(0.U(p.xlen.W))
val pmpcfg0 = RegInit(0.U(p.xlen.W))
val pmpaddr0 = RegInit(0.U(p.xlen.W))
val tdata1 = RegInit(0.U(p.xlen.W))
val tdata2 = RegInit(0.U(p.xlen.W))
val tcontrol = RegInit(0.U(p.xlen.W))
val mnstatus = RegInit(0.U(p.xlen.W))
val scounteren = RegInit(0.U(p.xlen.W))
val stvec = RegInit(0.U(p.xlen.W))
val sepc = RegInit(0.U(p.xlen.W))
val scause = RegInit(0.U(p.xlen.W))
@@ -35,59 +64,116 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
val satpReg = RegInit(0.U(p.xlen.W))
cycle := cycle + 1.U
when(!mcountinhibit(2) && !suppressInstretIncrement && !suppressInstretAfterWrite) {
instret := instret + 1.U
}
io.satp := satpReg
io.mtvec := mtvecReg
io.mepc := mepcReg
io.stvec := stvec
io.sepc := sepc
io.medeleg := medeleg
io.mideleg := mideleg
io.mie := mie
io.mip := mip
io.mstatus := mstatus
val readAllowed = CSRPermission.readAllowed(io.readAddr, io.currentPriv)
val writeAllowed = CSRPermission.writeAllowed(io.cmd.addr, io.currentPriv)
val readIllegal = !readAllowed
val writeIllegal = io.cmd.valid && io.cmd.cmd =/= 0.U && !writeAllowed
val xlenStatusMask = "h0000000f00000000".U(p.xlen.W)
val rv64XlenStatus = "h0000000a00000000".U(p.xlen.W)
val mstatusView = (mstatus & ~xlenStatusMask) | rv64XlenStatus
val sstatusMask = "h00000002000de162".U(p.xlen.W)
val sstatusView = mstatusView & sstatusMask
val r = WireDefault(0.U(p.xlen.W))
switch(io.readAddr) {
is("h300".U) { r := mstatus }
is("h301".U) { r := misa }
is("h302".U) { r := medeleg }
is("h303".U) { r := mideleg }
is("h304".U) { r := mie }
is("h305".U) { r := mtvecReg }
is("h341".U) { r := mepcReg }
is("h342".U) { r := mcause }
is("h343".U) { r := mtval }
is("h344".U) { r := mip }
is("h100".U) { r := sstatus }
is("h105".U) { r := stvec }
is("h140".U) { r := sscratch }
is("h141".U) { r := sepc }
is("h142".U) { r := scause }
is("h143".U) { r := stval }
is("h180".U) { r := satpReg }
is("hf14".U) { r := 0.U }
is("hc00".U) { r := cycle }
is("hc01".U) { r := 0.U }
is("hc02".U) { r := instret }
is(Privileged.CSR_MSTATUS) { r := mstatusView }
is(Privileged.CSR_MISA) { r := misa }
is(Privileged.CSR_MEDELEG) { r := medeleg }
is(Privileged.CSR_MIDELEG) { r := mideleg }
is(Privileged.CSR_MIE) { r := mie }
is(Privileged.CSR_MTVEC) { r := mtvecReg }
is(Privileged.CSR_MCOUNTEREN) { r := mcounteren }
is(Privileged.CSR_MCOUNTINHIBIT) { r := mcountinhibit }
is(Privileged.CSR_MSCRATCH) { r := mscratch }
is(Privileged.CSR_MEPC) { r := mepcReg }
is(Privileged.CSR_MCAUSE) { r := mcause }
is(Privileged.CSR_MTVAL) { r := mtval }
is(Privileged.CSR_MIP) { r := mip }
is(Privileged.CSR_PMPCFG0) { r := pmpcfg0 }
is(Privileged.CSR_PMPADDR0) { r := pmpaddr0 }
is(Privileged.CSR_TSELECT) { r := 1.U }
is(Privileged.CSR_TDATA1) { r := tdata1 }
is(Privileged.CSR_TDATA2) { r := tdata2 }
is(Privileged.CSR_TCONTROL) { r := tcontrol }
is(Privileged.CSR_MNSTATUS) { r := mnstatus }
is(Privileged.CSR_SSTATUS) { r := sstatusView }
is(Privileged.CSR_SIE) { r := mie & mideleg }
is(Privileged.CSR_STVEC) { r := stvec }
is(Privileged.CSR_SCOUNTEREN) { r := scounteren }
is(Privileged.CSR_SSCRATCH) { r := sscratch }
is(Privileged.CSR_SEPC) { r := sepc }
is(Privileged.CSR_SCAUSE) { r := scause }
is(Privileged.CSR_STVAL) { r := stval }
is(Privileged.CSR_SIP) { r := mip & mideleg }
is(Privileged.CSR_SATP) { r := satpReg }
is(Privileged.CSR_MVENDORID) { r := 0.U }
is(Privileged.CSR_MARCHID) { r := 0.U }
is(Privileged.CSR_MIMPID) { r := 0.U }
is(Privileged.CSR_MHARTID) { r := 0.U }
is(Privileged.CSR_MINSTRET) { r := instret }
is(Privileged.CSR_CYCLE) { r := cycle }
is(Privileged.CSR_TIME) { r := cycle }
is(Privileged.CSR_INSTRET) { r := instret }
}
io.rdata := r
io.rdata := Mux(readAllowed, r, 0.U)
io.readIllegal := readIllegal
io.writeIllegal := writeIllegal
io.illegal := readIllegal || writeIllegal
val writeOld = WireDefault(0.U(p.xlen.W))
switch(io.cmd.addr) {
is("h300".U) { writeOld := mstatus }
is("h301".U) { writeOld := misa }
is("h302".U) { writeOld := medeleg }
is("h303".U) { writeOld := mideleg }
is("h304".U) { writeOld := mie }
is("h305".U) { writeOld := mtvecReg }
is("h341".U) { writeOld := mepcReg }
is("h342".U) { writeOld := mcause }
is("h343".U) { writeOld := mtval }
is("h344".U) { writeOld := mip }
is("h100".U) { writeOld := sstatus }
is("h105".U) { writeOld := stvec }
is("h140".U) { writeOld := sscratch }
is("h141".U) { writeOld := sepc }
is("h142".U) { writeOld := scause }
is("h143".U) { writeOld := stval }
is("h180".U) { writeOld := satpReg }
is("hf14".U) { writeOld := 0.U }
is("hc00".U) { writeOld := cycle }
is("hc01".U) { writeOld := 0.U }
is("hc02".U) { writeOld := instret }
is(Privileged.CSR_MSTATUS) { writeOld := mstatusView }
is(Privileged.CSR_MISA) { writeOld := misa }
is(Privileged.CSR_MEDELEG) { writeOld := medeleg }
is(Privileged.CSR_MIDELEG) { writeOld := mideleg }
is(Privileged.CSR_MIE) { writeOld := mie }
is(Privileged.CSR_MTVEC) { writeOld := mtvecReg }
is(Privileged.CSR_MCOUNTEREN) { writeOld := mcounteren }
is(Privileged.CSR_MCOUNTINHIBIT) { writeOld := mcountinhibit }
is(Privileged.CSR_MSCRATCH) { writeOld := mscratch }
is(Privileged.CSR_MEPC) { writeOld := mepcReg }
is(Privileged.CSR_MCAUSE) { writeOld := mcause }
is(Privileged.CSR_MTVAL) { writeOld := mtval }
is(Privileged.CSR_MIP) { writeOld := mip }
is(Privileged.CSR_PMPCFG0) { writeOld := pmpcfg0 }
is(Privileged.CSR_PMPADDR0) { writeOld := pmpaddr0 }
is(Privileged.CSR_TSELECT) { writeOld := 1.U }
is(Privileged.CSR_TDATA1) { writeOld := tdata1 }
is(Privileged.CSR_TDATA2) { writeOld := tdata2 }
is(Privileged.CSR_TCONTROL) { writeOld := tcontrol }
is(Privileged.CSR_MNSTATUS) { writeOld := mnstatus }
is(Privileged.CSR_SSTATUS) { writeOld := sstatusView }
is(Privileged.CSR_SIE) { writeOld := mie & mideleg }
is(Privileged.CSR_STVEC) { writeOld := stvec }
is(Privileged.CSR_SCOUNTEREN) { writeOld := scounteren }
is(Privileged.CSR_SSCRATCH) { writeOld := sscratch }
is(Privileged.CSR_SEPC) { writeOld := sepc }
is(Privileged.CSR_SCAUSE) { writeOld := scause }
is(Privileged.CSR_STVAL) { writeOld := stval }
is(Privileged.CSR_SIP) { writeOld := mip & mideleg }
is(Privileged.CSR_SATP) { writeOld := satpReg }
is(Privileged.CSR_MVENDORID) { writeOld := 0.U }
is(Privileged.CSR_MARCHID) { writeOld := 0.U }
is(Privileged.CSR_MIMPID) { writeOld := 0.U }
is(Privileged.CSR_MHARTID) { writeOld := 0.U }
is(Privileged.CSR_MINSTRET) { writeOld := instret }
is(Privileged.CSR_CYCLE) { writeOld := cycle }
is(Privileged.CSR_TIME) { writeOld := cycle }
is(Privileged.CSR_INSTRET) { writeOld := instret }
}
val operand = Mux(io.cmd.cmd(2), io.cmd.zimm, io.cmd.rs1)
@@ -97,29 +183,82 @@ class CSRFile(p: CoreParams = CoreParams()) extends Module {
3.U -> (writeOld & ~operand)
))
when(io.cmd.valid && io.cmd.cmd =/= 0.U) {
when(io.cmd.valid && io.cmd.cmd =/= 0.U && writeAllowed) {
switch(io.cmd.addr) {
is("h300".U) { mstatus := next }
is("h302".U) { medeleg := next }
is("h303".U) { mideleg := next }
is("h304".U) { mie := next }
is("h305".U) { mtvecReg := next }
is("h341".U) { mepcReg := next }
is("h342".U) { mcause := next }
is("h343".U) { mtval := next }
is("h344".U) { mip := next }
is("h100".U) { sstatus := next }
is("h105".U) { stvec := next }
is("h140".U) { sscratch := next }
is("h141".U) { sepc := next }
is("h142".U) { scause := next }
is("h143".U) { stval := next }
is("h180".U) { satpReg := next }
is(Privileged.CSR_MSTATUS) { mstatus := next }
is(Privileged.CSR_MEDELEG) { medeleg := next }
is(Privileged.CSR_MIDELEG) { mideleg := next }
is(Privileged.CSR_MIE) { mie := next }
is(Privileged.CSR_MTVEC) { mtvecReg := next }
is(Privileged.CSR_MCOUNTEREN) { mcounteren := next }
is(Privileged.CSR_MCOUNTINHIBIT) { mcountinhibit := next & 4.U }
is(Privileged.CSR_MSCRATCH) { mscratch := next }
is(Privileged.CSR_MEPC) { mepcReg := next }
is(Privileged.CSR_MCAUSE) { mcause := next }
is(Privileged.CSR_MTVAL) { mtval := next }
is(Privileged.CSR_MIP) { mip := next }
is(Privileged.CSR_PMPCFG0) { pmpcfg0 := next }
is(Privileged.CSR_PMPADDR0) { pmpaddr0 := next }
is(Privileged.CSR_TDATA1) { tdata1 := next }
is(Privileged.CSR_TDATA2) { tdata2 := next }
is(Privileged.CSR_TCONTROL) { tcontrol := next }
is(Privileged.CSR_MNSTATUS) { mnstatus := next }
is(Privileged.CSR_SSTATUS) { mstatus := (mstatus & ~sstatusMask) | (next & sstatusMask) }
is(Privileged.CSR_SIE) { mie := (mie & ~mideleg) | (next & mideleg) }
is(Privileged.CSR_STVEC) { stvec := next }
is(Privileged.CSR_SCOUNTEREN) { scounteren := next }
is(Privileged.CSR_SSCRATCH) { sscratch := next }
is(Privileged.CSR_SEPC) { sepc := next }
is(Privileged.CSR_SCAUSE) { scause := next }
is(Privileged.CSR_STVAL) { stval := next }
is(Privileged.CSR_SIP) { mip := (mip & ~mideleg) | (next & mideleg) }
is(Privileged.CSR_SATP) { satpReg := next }
is(Privileged.CSR_MINSTRET) {
instret := next
suppressInstretIncrement := true.B
suppressInstretAfterWrite := true.B
}
}
}
when(suppressInstretAfterWrite) {
suppressInstretAfterWrite := false.B
}
val trapToS = io.trapTargetPriv === Privileged.PRV_S
io.trapVector := Mux(trapToS, stvec, mtvecReg)
val bitMie = 1.U(p.xlen.W) << 3
val bitMpie = 1.U(p.xlen.W) << 7
val mppMask = 3.U(p.xlen.W) << 11
val bitSie = 1.U(p.xlen.W) << 1
val bitSpie = 1.U(p.xlen.W) << 5
val bitSpp = 1.U(p.xlen.W) << 8
when(io.trap) {
mepcReg := io.trapPc
mcause := io.trapCause
when(trapToS) {
sepc := io.trapPc
scause := io.trapCause
stval := io.trapTval
val withSpie = Mux((mstatus & bitSie) =/= 0.U, mstatus | bitSpie, mstatus & ~bitSpie)
val withSieCleared = withSpie & ~bitSie
val withSpp = Mux(io.currentPriv === Privileged.PRV_S, withSieCleared | bitSpp, withSieCleared & ~bitSpp)
mstatus := withSpp
}.otherwise {
mepcReg := io.trapPc
mcause := io.trapCause
mtval := io.trapTval
val withMpie = Mux((mstatus & bitMie) =/= 0.U, mstatus | bitMpie, mstatus & ~bitMpie)
val withMieCleared = withMpie & ~bitMie
mstatus := (withMieCleared & ~mppMask) | (io.currentPriv.pad(p.xlen) << 11)
}
}.elsewhen(io.xret) {
when(io.xretIsMret) {
val withMie = Mux((mstatus & bitMpie) =/= 0.U, mstatus | bitMie, mstatus & ~bitMie)
val withMpie = withMie | bitMpie
mstatus := withMpie & ~mppMask
}.otherwise {
val withSie = Mux((mstatus & bitSpie) =/= 0.U, mstatus | bitSie, mstatus & ~bitSie)
val withSpie = withSie | bitSpie
mstatus := withSpie & ~bitSpp
}
}
}

View File

@@ -0,0 +1,63 @@
import chisel3._
object CSRPermission {
private val machineCsrs = Set(
0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x340, 0x341, 0x342, 0x343, 0x344,
0x320, 0x3a0, 0x3b0, 0x744, 0x7a0, 0x7a1, 0x7a2, 0x7a5, 0xb02,
0xf11, 0xf12, 0xf13, 0xf14)
private val supervisorCsrs = Set(0x100, 0x104, 0x105, 0x106, 0x140, 0x141, 0x142, 0x143, 0x144, 0x180)
private val counterCsrs = Set(0xc00, 0xc01, 0xc02)
private val readOnlyCsrs = Set(0xf11, 0xf12, 0xf13, 0xf14) ++ counterCsrs
def implementedLit(addr: BigInt): Boolean =
machineCsrs(addr.toInt) || supervisorCsrs(addr.toInt) || counterCsrs(addr.toInt)
def readAllowedLit(addr: BigInt, priv: BigInt): Boolean =
implementedLit(addr) && {
if (machineCsrs(addr.toInt)) priv == 3
else if (supervisorCsrs(addr.toInt)) priv != 0
else true
}
def writeAllowedLit(addr: BigInt, priv: BigInt): Boolean =
readAllowedLit(addr, priv) && !readOnlyCsrs(addr.toInt)
private def isMachine(addr: UInt): Bool =
addr === Privileged.CSR_MSTATUS || addr === Privileged.CSR_MISA ||
addr === Privileged.CSR_MEDELEG || addr === Privileged.CSR_MIDELEG ||
addr === Privileged.CSR_MIE || addr === Privileged.CSR_MTVEC ||
addr === Privileged.CSR_MCOUNTEREN || addr === Privileged.CSR_MSCRATCH || addr === Privileged.CSR_MEPC ||
addr === Privileged.CSR_MCAUSE || addr === Privileged.CSR_MTVAL ||
addr === Privileged.CSR_MIP || addr === Privileged.CSR_PMPCFG0 ||
addr === Privileged.CSR_PMPADDR0 || addr === Privileged.CSR_TSELECT ||
addr === Privileged.CSR_TDATA1 || addr === Privileged.CSR_TDATA2 ||
addr === Privileged.CSR_TCONTROL || addr === Privileged.CSR_MNSTATUS ||
addr === Privileged.CSR_MCOUNTINHIBIT || addr === Privileged.CSR_MINSTRET ||
addr === Privileged.CSR_MVENDORID || addr === Privileged.CSR_MARCHID ||
addr === Privileged.CSR_MIMPID || addr === Privileged.CSR_MHARTID
private def isSupervisor(addr: UInt): Bool =
addr === Privileged.CSR_SSTATUS || addr === Privileged.CSR_SIE ||
addr === Privileged.CSR_STVEC || addr === Privileged.CSR_SSCRATCH ||
addr === Privileged.CSR_SCOUNTEREN || addr === Privileged.CSR_SEPC || addr === Privileged.CSR_SCAUSE ||
addr === Privileged.CSR_STVAL || addr === Privileged.CSR_SIP ||
addr === Privileged.CSR_SATP
private def isCounter(addr: UInt): Bool =
addr === Privileged.CSR_CYCLE || addr === Privileged.CSR_TIME ||
addr === Privileged.CSR_INSTRET
private def isReadOnly(addr: UInt): Bool =
addr === Privileged.CSR_MVENDORID || addr === Privileged.CSR_MARCHID ||
addr === Privileged.CSR_MIMPID || addr === Privileged.CSR_MHARTID ||
isCounter(addr)
def implemented(addr: UInt): Bool = isMachine(addr) || isSupervisor(addr) || isCounter(addr)
def readAllowed(addr: UInt, priv: UInt): Bool =
implemented(addr) && Mux(isMachine(addr), priv === Privileged.PRV_M,
Mux(isSupervisor(addr), priv =/= Privileged.PRV_U, true.B))
def writeAllowed(addr: UInt, priv: UInt): Bool =
readAllowed(addr, priv) && !isReadOnly(addr)
}

View File

@@ -2,20 +2,14 @@ import chisel3._
class PrivilegeControl(p: CoreParams = CoreParams()) extends Module {
val io = IO(new Bundle {
val trap = Input(Bool())
val mret = Input(Bool())
val sret = Input(Bool())
val privilege = Output(UInt(2.W))
val nextPriv = Input(UInt(2.W))
val setPriv = Input(Bool())
val priv = Output(UInt(2.W))
})
val mode = RegInit(3.U(2.W))
when(io.trap) {
mode := 3.U
}.elsewhen(io.mret) {
mode := 0.U
}.elsewhen(io.sret) {
mode := 0.U
val privReg = RegInit(Privileged.PRV_M)
when(io.setPriv) {
privReg := io.nextPriv
}
io.privilege := mode
io.priv := privReg
}

View File

@@ -0,0 +1,47 @@
import chisel3._
import chisel3.util._
object PrivilegeTransitions {
private def delegated(cause: UInt, delegation: UInt): Bool = delegation(cause(5, 0))
def trapTargetPriv(
currentPriv: UInt,
cause: UInt,
isInterrupt: Bool,
medeleg: UInt,
mideleg: UInt): UInt = {
val delegation = Mux(isInterrupt, mideleg, medeleg)
val toSupervisor = currentPriv =/= Privileged.PRV_M && delegated(cause, delegation)
Mux(toSupervisor, Privileged.PRV_S, Privileged.PRV_M)
}
def mretNextPriv(mstatus: UInt): UInt = mstatus(12, 11)
def sretNextPriv(mstatus: UInt): UInt = Mux(mstatus(8), Privileged.PRV_S, Privileged.PRV_U)
def xretTargetPc(isMret: Bool, mepc: UInt, sepc: UInt): UInt =
Mux(isMret, mepc, sepc)
def xretNextPriv(isMret: Bool, mstatus: UInt): UInt =
Mux(isMret, mretNextPriv(mstatus), sretNextPriv(mstatus))
def trapTargetPrivLit(
currentPriv: BigInt,
cause: BigInt,
isInterrupt: Boolean,
medeleg: BigInt,
mideleg: BigInt): BigInt = {
val delegation = if (isInterrupt) mideleg else medeleg
val delegated = ((delegation >> cause.toInt) & 1) == 1
if (currentPriv != Privileged.PRV_M.litValue && delegated) Privileged.PRV_S.litValue
else Privileged.PRV_M.litValue
}
def mretNextPrivLit(mstatus: BigInt): BigInt = (mstatus >> 11) & 3
def sretNextPrivLit(mstatus: BigInt): BigInt =
if (((mstatus >> 8) & 1) == 1) Privileged.PRV_S.litValue else Privileged.PRV_U.litValue
def xretTargetPcLit(isMret: Boolean, mepc: BigInt, sepc: BigInt): BigInt =
if (isMret) mepc else sepc
}