npc,feat: add csr
This commit is contained in:
parent
ba18436c6c
commit
a5790308f0
4 changed files with 181 additions and 0 deletions
108
npc/core/src/main/scala/components/CSR.scala
Normal file
108
npc/core/src/main/scala/components/CSR.scala
Normal file
|
@ -0,0 +1,108 @@
|
|||
package flow.components
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util.log2Ceil
|
||||
import scala.reflect.runtime.universe._
|
||||
import cats.instances.MapInstances
|
||||
import dataclass.data
|
||||
import chisel3.util.experimental.decode.{decoder, TruthTable}
|
||||
import shapeless.HNil
|
||||
import flow.Params
|
||||
import chisel3.util.BitPat
|
||||
import chisel3.util.Fill
|
||||
|
||||
class CSRControlInterface extends Bundle {
|
||||
object csrRead extends ChiselEnum {
|
||||
val csrReadDisabled, csrReadEnabled = Value
|
||||
}
|
||||
|
||||
object csrWrite extends ChiselEnum {
|
||||
val csrWriteDisabled, csrWriteEnabled = Value
|
||||
}
|
||||
|
||||
val readEnable = Input(csrRead())
|
||||
val writeEnable = Input(csrWrite())
|
||||
|
||||
def ctrlBindPorts = {
|
||||
readEnable :: writeEnable :: HNil
|
||||
}
|
||||
}
|
||||
|
||||
class CSRCore(implicit val p: Params) extends Module {
|
||||
val control = IO(new CSRControlInterface)
|
||||
|
||||
val in = IO(new Bundle {
|
||||
val csrAddr = Input(UInt(p.csrAddrWidth))
|
||||
val writeData = Input(UInt(p.XLEN))
|
||||
})
|
||||
|
||||
val out = IO(new Bundle {
|
||||
val readData = Output(UInt(p.XLEN))
|
||||
val readValid = Output(Bool())
|
||||
})
|
||||
|
||||
implicit class fromChiselEnumToBool[T <: EnumType](x: T) {
|
||||
def B: Bool = {
|
||||
x.asUInt =/= 0.U
|
||||
}
|
||||
}
|
||||
|
||||
val nameToAddr = Map(
|
||||
"mstatus" -> 0x300,
|
||||
"mtvec" -> 0x305,
|
||||
"mie" -> 0x304,
|
||||
"mepc" -> 0x341,
|
||||
"mcause" -> 0x342,
|
||||
"mtval" -> 0x343,
|
||||
"mip" -> 0x344
|
||||
)
|
||||
val csrSize = nameToAddr.size
|
||||
|
||||
val addrToIndex = nameToAddr.zipWithIndex
|
||||
.map(x => {
|
||||
val (name: String, csrAddr: Int) = x._1
|
||||
val index = x._2
|
||||
|
||||
csrAddr -> index
|
||||
})
|
||||
.toMap
|
||||
val indexToAddr = addrToIndex.map(_.swap)
|
||||
|
||||
val csrIndexWidth = log2Ceil(csrSize).W
|
||||
|
||||
private val align = (x: UInt, w: Width) => BitPat(x.litValue.U(w))
|
||||
val csrIndex = decoder(
|
||||
in.csrAddr,
|
||||
TruthTable(
|
||||
addrToIndex.map(x =>
|
||||
// Addr Index
|
||||
(align(x._1.U, p.csrAddrWidth), align(x._2.U, csrIndexWidth))
|
||||
),
|
||||
align(addrToIndex.head._2.U, csrIndexWidth)
|
||||
)
|
||||
)
|
||||
|
||||
val csrIndexValid = !(
|
||||
csrIndex === BitPat(0.U) &&
|
||||
in.csrAddr =/= align(indexToAddr(0).U, p.csrAddrWidth)
|
||||
)
|
||||
|
||||
val regs = RegInit(VecInit(Seq.fill(csrSize)(0.U(p.XLEN))))
|
||||
|
||||
val regReadValue = regs(csrIndex)
|
||||
|
||||
val delayWriteData = RegNext(in.writeData, 0.U(p.XLEN))
|
||||
val delayWriteEnable = RegNext(control.writeEnable)
|
||||
|
||||
when(control.writeEnable.B) {
|
||||
regs(csrIndex) := delayWriteData
|
||||
}
|
||||
|
||||
when(control.readEnable.B) {
|
||||
out.readData := regReadValue
|
||||
out.readValid := true.B && csrIndexValid
|
||||
} otherwise {
|
||||
out.readData := 0.U(p.XLEN)
|
||||
out.readValid := false.B && csrIndexValid
|
||||
}
|
||||
}
|
|
@ -14,3 +14,9 @@ import io.circe.generic.JsonCodec
|
|||
enableDifftest: Boolean = true,
|
||||
traceConfig: TraceConfig = TraceConfig()
|
||||
)
|
||||
|
||||
import chisel3._
|
||||
case class Params(
|
||||
XLEN: Width,
|
||||
csrAddrWidth: Width = 12.W
|
||||
)
|
||||
|
|
59
npc/core/src/test/scala/CSR.scala
Normal file
59
npc/core/src/test/scala/CSR.scala
Normal file
|
@ -0,0 +1,59 @@
|
|||
package flow.tests
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import chiseltest.simulator.WriteVcdAnnotation
|
||||
|
||||
import flow.components.CSRCore
|
||||
import flow.tests.defaultParams
|
||||
|
||||
class CSRSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||
implicit val p: flow.Params = defaultParams()
|
||||
"should compile" in {
|
||||
test(new CSRCore) { c =>
|
||||
c.clock.step(1)
|
||||
}
|
||||
}
|
||||
"Write" - {
|
||||
"delayed" in {
|
||||
test(new CSRCore) { c =>
|
||||
val tv = BigInt("deadbeef", 16)
|
||||
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
||||
c.in.writeData.poke(tv)
|
||||
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
|
||||
c.clock.step(1)
|
||||
|
||||
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
|
||||
c.out.readData.expect(0)
|
||||
c.out.readValid.expect(1)
|
||||
|
||||
c.clock.step(1)
|
||||
c.out.readValid.expect(1)
|
||||
c.out.readData.expect(tv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Read" - {
|
||||
"controlled by readEnable" in {
|
||||
test(new CSRCore) { c =>
|
||||
val tv = BigInt("deadbeef", 16)
|
||||
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
||||
c.in.writeData.poke(tv)
|
||||
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
|
||||
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
|
||||
c.clock.step(1)
|
||||
|
||||
c.control.readEnable.poke(c.control.csrRead.csrReadDisabled)
|
||||
c.out.readData.expect(0)
|
||||
c.out.readValid.expect(0)
|
||||
|
||||
c.clock.step(1)
|
||||
c.out.readData.expect(0)
|
||||
c.out.readValid.expect(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
8
npc/core/src/test/scala/params.scala
Normal file
8
npc/core/src/test/scala/params.scala
Normal file
|
@ -0,0 +1,8 @@
|
|||
package flow.tests
|
||||
|
||||
import chisel3._
|
||||
import flow.Params
|
||||
|
||||
object defaultParams {
|
||||
def apply(): Params = new Params(XLEN = 32.W)
|
||||
}
|
Loading…
Reference in a new issue