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,
|
enableDifftest: Boolean = true,
|
||||||
traceConfig: TraceConfig = TraceConfig()
|
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