blob: 346c9dc7c21d0d35500775c1375c8b4834ddf6a1 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package kelvin
import chisel3._
import chisel3.util._
import common._
object Csr {
def apply(p: Parameters): Csr = {
return Module(new Csr(p))
}
}
case class CsrOp() {
val CSRRW = 0
val CSRRS = 1
val CSRRC = 2
val Entries = 3
}
class CsrInIO(p: Parameters) extends Bundle {
val value = Input(Vec(12, UInt(32.W)))
}
class CsrOutIO(p: Parameters) extends Bundle {
val value = Output(Vec(8, UInt(32.W)))
}
class CsrInOutIO(p: Parameters) extends Bundle {
val in = new CsrInIO(p)
val out = new CsrOutIO(p)
}
class CsrBruIO(p: Parameters) extends Bundle {
val in = new Bundle {
val mode = Valid(Bool())
val mcause = Valid(UInt(32.W))
val mepc = Valid(UInt(32.W))
val mtval = Valid(UInt(32.W))
val halt = Output(Bool())
val fault = Output(Bool())
}
val out = new Bundle {
val mode = Input(Bool())
val mepc = Input(UInt(32.W))
val mtvec = Input(UInt(32.W))
}
def defaults() = {
out.mode := false.B
out.mepc := 0.U
out.mtvec := 0.U
}
}
class CsrIO(p: Parameters) extends Bundle {
val valid = Input(Bool())
val addr = Input(UInt(5.W))
val index = Input(UInt(12.W))
val op = Input(UInt(new CsrOp().Entries.W))
}
class Csr(p: Parameters) extends Module {
val io = IO(new Bundle {
// Reset and shutdown.
val csr = new CsrInOutIO(p)
// Decode cycle.
val req = new CsrIO(p)
// Execute cycle.
val rs1 = Flipped(new RegfileReadDataIO)
val rd = Flipped(new RegfileWriteDataIO)
val bru = Flipped(new CsrBruIO(p))
// Vector core.
val vcore = Input(new Bundle { val undef = Bool() })
// Pipeline Control.
val halted = Output(Bool())
val fault = Output(Bool())
})
val csr = new CsrOp()
val valid = RegInit(false.B)
val addr = Reg(UInt(5.W))
val index = Reg(UInt(12.W))
val op = RegInit(0.U(csr.Entries.W))
// Pipeline Control.
val halted = RegInit(false.B)
val fault = RegInit(false.B)
// Machine(0)/User(1) Mode.
val mode = RegInit(false.B)
// CSRs parallel loaded when(reset).
val mpc = Reg(UInt(32.W))
val msp = Reg(UInt(32.W))
val mcause = Reg(UInt(32.W))
val mtval = Reg(UInt(32.W))
val mcontext0 = Reg(UInt(32.W))
val mcontext1 = Reg(UInt(32.W))
val mcontext2 = Reg(UInt(32.W))
val mcontext3 = Reg(UInt(32.W))
val mcontext4 = Reg(UInt(32.W))
val mcontext5 = Reg(UInt(32.W))
val mcontext6 = Reg(UInt(32.W))
val mcontext7 = Reg(UInt(32.W))
// CSRs with initialization.
val fflags = RegInit(0.U(5.W))
val frm = RegInit(0.U(3.W))
val mie = RegInit(0.U(1.W))
val mtvec = RegInit(0.U(32.W))
val mscratch = RegInit(0.U(32.W))
val mepc = RegInit(0.U(32.W))
val mhartid = RegInit(0.U(32.W))
val mcycle = RegInit(0.U(64.W))
// 32-bit MXLEN, I,M,X extensions
val misa = RegInit(0x40801100.U(32.W))
// Kelvin-specific ISA register.
val kisa = RegInit(0.U(32.W))
// 0x426 - Google's Vendor ID
val mvendorid = RegInit(0x426.U(32.W))
// Unimplemented -- explicitly return zero.
val marchid = RegInit(0.U(1.W))
val mimpid = RegInit(0.U(1.W))
val fcsr = Cat(frm, fflags)
// Decode the Index.
val fflagsEn = index === 0x001.U
val frmEn = index === 0x002.U
val fcsrEn = index === 0x003.U
val misaEn = index === 0x301.U
val mieEn = index === 0x304.U
val mtvecEn = index === 0x305.U
val mscratchEn = index === 0x340.U
val mepcEn = index === 0x341.U
val mcauseEn = index === 0x342.U
val mtvalEn = index === 0x343.U
val mcontext0En = index === 0x7C0.U
val mcontext1En = index === 0x7C1.U
val mcontext2En = index === 0x7C2.U
val mcontext3En = index === 0x7C3.U
val mcontext4En = index === 0x7C4.U
val mcontext5En = index === 0x7C5.U
val mcontext6En = index === 0x7C6.U
val mcontext7En = index === 0x7C7.U
val mpcEn = index === 0x7E0.U
val mspEn = index === 0x7E1.U
// M-mode performance CSRs.
val mcycleEn = index === 0xB00.U
val mcyclehEn = index === 0xB80.U
// M-mode information CSRs.
val mvendoridEn = index === 0xF11.U
val marchidEn = index === 0xF12.U
val mimpidEn = index === 0xF13.U
val mhartidEn = index === 0xF14.U
// Start of custom CSRs.
val kisaEn = index === 0xFC0.U
// Control registers.
when (io.req.valid) {
valid := io.req.valid
addr := io.req.addr
index := io.req.index
op := io.req.op
} .elsewhen (valid) {
valid := false.B
addr := 0.U
index := 0.U
op := 0.U
}
// Pipeline Control.
when (io.bru.in.halt || io.vcore.undef) {
halted := true.B
}
when (io.bru.in.fault || io.vcore.undef) {
fault := true.B
}
io.halted := halted
io.fault := fault
assert(!(io.fault && !io.halted))
// Register state.
val rs1 = io.rs1.data
val rdata = MuxOR(fflagsEn, fflags) |
MuxOR(frmEn, frm) |
MuxOR(fcsrEn, fcsr) |
MuxOR(misaEn, misa) |
MuxOR(mieEn, mie) |
MuxOR(mtvecEn, mtvec) |
MuxOR(mscratchEn, mscratch) |
MuxOR(mepcEn, mepc) |
MuxOR(mcauseEn, mcause) |
MuxOR(mtvalEn, mtval) |
MuxOR(mcontext0En, mcontext0) |
MuxOR(mcontext1En, mcontext1) |
MuxOR(mcontext2En, mcontext2) |
MuxOR(mcontext3En, mcontext3) |
MuxOR(mcontext4En, mcontext4) |
MuxOR(mcontext5En, mcontext5) |
MuxOR(mcontext6En, mcontext6) |
MuxOR(mcontext7En, mcontext7) |
MuxOR(mpcEn, mpc) |
MuxOR(mspEn, msp) |
MuxOR(mcycleEn, mcycle(31,0)) |
MuxOR(mcyclehEn, mcycle(63,32)) |
MuxOR(mvendoridEn, mvendorid) |
MuxOR(marchidEn, marchid) |
MuxOR(mimpidEn, mimpid) |
MuxOR(mhartidEn, mhartid) |
MuxOR(kisaEn, kisa)
val wdata = MuxOR(op(csr.CSRRW), rs1) |
MuxOR(op(csr.CSRRS), rdata | rs1) |
MuxOR(op(csr.CSRRC), rdata & ~rs1)
when (valid) {
when (fflagsEn) { fflags := wdata }
when (frmEn) { frm := wdata }
when (fcsrEn) { fflags := wdata(4,0)
frm := wdata(7,5) }
when (mieEn) { mie := wdata }
when (mtvecEn) { mtvec := wdata }
when (mscratchEn) { mscratch := wdata }
when (mepcEn) { mepc := wdata }
when (mcauseEn) { mcause := wdata }
when (mtvalEn) { mtval := wdata }
when (mpcEn) { mpc := wdata }
when (mspEn) { msp := wdata }
when (mcontext0En) { mcontext0 := wdata }
when (mcontext1En) { mcontext1 := wdata }
when (mcontext2En) { mcontext2 := wdata }
when (mcontext3En) { mcontext3 := wdata }
when (mcontext4En) { mcontext4 := wdata }
when (mcontext5En) { mcontext5 := wdata }
when (mcontext6En) { mcontext6 := wdata }
when (mcontext7En) { mcontext7 := wdata }
}
// mcycle implementation
// If one of the enable signals for
// the register are true, overwrite the enabled half
// of the register.
// Increment the value of mcycle by 1.
val mcycle_th = Mux(mcyclehEn, wdata, mcycle(63,32))
val mcycle_tl = Mux(mcycleEn, wdata, mcycle(31,0))
val mcycle_t = Cat(mcycle_th, mcycle_tl)
mcycle := Mux(valid, mcycle_t, mcycle) + 1.U
when (io.bru.in.mode.valid) {
mode := io.bru.in.mode.bits
}
val firstFault = !mcause(31)
when (io.bru.in.mcause.valid && firstFault) {
mcause := io.bru.in.mcause.bits
}
when (io.bru.in.mtval.valid && firstFault) {
mtval := io.bru.in.mtval.bits
}
when (io.bru.in.mepc.valid) {
mepc := io.bru.in.mepc.bits
}
// This pattern of separate when() blocks requires resets after the data.
when (reset.asBool) {
mpc := io.csr.in.value(0)
msp := io.csr.in.value(1)
mcause := io.csr.in.value(2)
mtval := io.csr.in.value(3)
mcontext0 := io.csr.in.value(4)
mcontext1 := io.csr.in.value(5)
mcontext2 := io.csr.in.value(6)
mcontext3 := io.csr.in.value(7)
mcontext4 := io.csr.in.value(8)
mcontext5 := io.csr.in.value(9)
mcontext6 := io.csr.in.value(10)
mcontext7 := io.csr.in.value(11)
}
// Forwarding.
io.bru.out.mode := mode
io.bru.out.mepc := Mux(mepcEn, wdata, mepc)
io.bru.out.mtvec := Mux(mtvecEn, wdata, mtvec)
io.csr.out.value(0) := mpc
io.csr.out.value(1) := msp
io.csr.out.value(2) := mcause
io.csr.out.value(3) := mtval
io.csr.out.value(4) := mcontext0
io.csr.out.value(5) := mcontext1
io.csr.out.value(6) := mcontext2
io.csr.out.value(7) := mcontext3
// Write port.
io.rd.valid := valid
io.rd.addr := addr
io.rd.data := rdata
// Assertions.
assert(!(valid && !io.rs1.valid))
}