spinal.lib.bus.regif.BusIf.scala Maven / Gradle / Ivy
The newest version!
package spinal.lib.bus.regif
import spinal.core._
import spinal.lib._
import spinal.lib.bus.localbus.{MemBus, MinBus}
import spinal.lib.bus.misc.SizeMapping
import scala.collection.mutable.HashMap
import scala.collection.mutable.ListBuffer
trait BusIf extends BusIfBase {
val bus: Bundle
type B <: this.type
private val SliceInsts = ListBuffer[RegSlice]()
private var regPtr: BigInt = 0
protected var readDefaultValue: BigInt = 0
protected var grpId: Int = 1
protected def grpIdInc(): Unit = (grpId += 1)
private val secureLogicDict = HashMap[Bool, Bool]()
def getOrCreateSecLogic(key: Bool, logic: Bool): Bool = {
secureLogicDict.getOrElseUpdate(key, logic)
}
def regSlicesNotReuse: List[RegSlice] = slices.filter(_.reuseTag.id == 0)
def reuseGroups: Map[String, List[RegSlice]] = slices.filter(_.reuseTag.id != 0).groupBy(_.reuseTag.partName)
def reuseGroupsById: Map[String, Map[Int, List[RegSlice]]] = reuseGroups.map {case(name, slices) => (name, slices.groupBy(_.reuseTag.id)) }
def repeatGroupsHead: Map[String, List[RegSlice]] = reuseGroupsById.map(t => t._1 -> t._2.head._2)
def repeatGroupsBase: Map[String, List[RegSlice]] = reuseGroupsById.map(t => t._1 -> t._2.map(_._2.head).toList.sortBy(_.reuseTag.id))
def busName = bus.getClass.getSimpleName
def newGrpTag(name: String) = {
val ret = GrpTag(grpId, name)
this.grpIdInc()
ret
}
// protected var partIdFlag: Boolean = false
protected var blockId: Int = 1
protected def blockIdInc(): Unit = (blockId += 1)
def resetBlockTag(): Unit = {
currentBlockTag = ReuseTag(0, "")
}
private var currentBlockTag = ReuseTag(0, "")
def getCurrentBlockTag = currentBlockTag
def newBlockTag(instName: String)(partName: String) = {
val ret = ReuseTag(blockId, partName, regPtr, instName)
this.blockIdInc()
currentBlockTag = ret
ret
}
def RegAndFifos = SliceInsts.filter(!_.isInstanceOf[RamInst]).toList
def RegInsts = SliceInsts.filter(_.isInstanceOf[RegInst]).map(_.asInstanceOf[RegInst])
def RamInsts = SliceInsts.filter(_.isInstanceOf[RamInst]).map(_.asInstanceOf[RamInst])
def FifoInsts = SliceInsts.filter(_.isInstanceOf[FifoInst]).map(_.asInstanceOf[FifoInst])
def orderdRegInsts = SliceInsts.sortBy(_.addr)
def getModuleName: String
def setReservedAddressReadValue(value: BigInt) = readDefaultValue = value
def getReservedAddressReadValue = readDefaultValue
def defualtReadBits = B(readDefaultValue, busDataWidth bits)
def slices= SliceInsts.toList
def hasBlock = SliceInsts.filter(_.reuseTag.id != 0).nonEmpty
def docPath: String = GlobalData.get.phaseContext.config.targetDirectory
val regPre: String
private val regAddressHistory = ListBuffer[BigInt]()
private val regAddressMap = ListBuffer[SizeMapping]()
def addressUsed(addr: BigInt) = regAddressHistory.contains(addr)
def getAddrMap = regAddressHistory.toList.map("0x"+_.hexString()) ++ regAddressMap.map(_.toString)
private def attachAddr(addr: BigInt) = {
val ret = regAddressMap.filter(t => (addr <= t.end) && (addr >= t.base))
if(regAddressHistory.contains(addr)){
SpinalError(s"Address: ${regPtr.hexString(16)} already used before, check please!")
} else if(!ret.isEmpty){
SpinalError(s"${ret.head} overlap with 0x${addr.hexString()}")
} else {
regAddressHistory.append(addr)
}
}
private def attachAddr(sizemap: SizeMapping) = {
val ret = regAddressMap.filter(_.overlap(sizemap))
val t = regAddressHistory.filter(t => (t <= sizemap.end) && (t >= sizemap.base))
if(!ret.isEmpty){
SpinalError(s"${ret.head} overlap with ${sizemap}")
} else if(!t.isEmpty){
SpinalError(s"0x${t.head.hexString()} overlap with ${sizemap}")
} else {
regAddressMap.append(sizemap)
}
}
def getRegPtr(): BigInt = regPtr
/*Attention: Should user make address no conflict them selves*/
def regPtrReAnchorAt(pos: BigInt) = {
require(pos % (busDataWidth/8) ==0, s"Address Postion need allign datawidth ${busDataWidth/8} byte")
regPtr = pos
}
private def checkLastNA(): Unit = SliceInsts.foreach(_.checkLast)
private def regNameUpdate(): Unit = {
val words = "\\w*".r
val pre = regPre match{
case "" => ""
case words(_*) => regPre + "_"
case _ => SpinalError(s"${regPre} should be Valid naming : '[A-Za-z0-9_]+'")
}
RegInsts.foreach(t => t.setName(s"${pre}${t.getName()}"))
}
private var isChecked: Boolean = false
def preCheck(): Unit = {
if(!isChecked){
checkLastNA()
regNameUpdate()
isChecked = true
}
}
component.addPrePopTask(() => {
this.readGenerator()
})
def regPart(name: String)(block : => Unit) = {
this.newBlockTag(name)(name)
block
this.resetBlockTag()
}
def newRegAt(address: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName) = {
assert(address % wordAddressInc == 0, s"located Position not align by wordAddressInc: ${wordAddressInc}")
val reg = createReg(symbol.name, address, doc, sec, grp)
regPtr = address + wordAddressInc
reg
}
def newReg(doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName) = {
val res = createReg(symbol.name.toLowerCase(), regPtr, doc, sec, grp)
regPtr += wordAddressInc
res
}
@deprecated("type error fix", "2024.06.03")
def creatReg(name: String, addr: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null) = createReg(name, addr, doc, sec, grp)
def createReg(name: String, addr: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null) = {
val ret = new RegInst(name, addr, doc, this, sec, grp)
SliceInsts += ret
attachAddr(regPtr)
ret
}
def newRAM(size: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName) = {
val res = createRAM(symbol.name.toLowerCase(), regPtr, size, doc, sec, grp)
regPtr += scala.math.ceil(size.toDouble/wordAddressInc).toLong * wordAddressInc
res
}
def newRAMAt(address: BigInt, size: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName) = {
assert(address % wordAddressInc == 0, s"located Position not align by wordAddressInc: ${wordAddressInc}")
val res = createRAM(symbol.name, address, size, doc, sec, grp)
regPtr = address + scala.math.ceil(size.toDouble/wordAddressInc).toLong * wordAddressInc
res
}
def createRAM(name: String, addr: BigInt, size: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null) = {
val ret = new RamInst(name, addr, size, doc, sec, grp)(this)
SliceInsts += ret
attachAddr(SizeMapping(addr, size))
ret
}
def newWrFifo(doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName): WrFifoInst = {
val res = createWrFifo(symbol.name.toLowerCase(), regPtr, doc, sec, grp)
regPtr += wordAddressInc
res
}
def newWrFifoAt(address: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName) = {
assert(address % wordAddressInc == 0, s"located Position not align by wordAddressInc: ${wordAddressInc}")
val res = createWrFifo(symbol.name.toLowerCase(), address, doc, sec, grp)
regPtr = address + wordAddressInc
res
}
def createWrFifo(name: String, addr: BigInt, Doc: String, sec: Secure = null, grp: GrpTag = null) = {
val ret = new WrFifoInst(name, addr, Doc, sec, grp)( this)
SliceInsts += ret
attachAddr(addr)
ret
}
def createRdFifo(name: String, addr: BigInt, Doc: String, sec: Secure = null, grp: GrpTag = null): RdFifoInst = {
val ret = new RdFifoInst(name, addr, Doc, sec, grp)(this)
SliceInsts += ret
attachAddr(addr)
ret
}
def newRdFifo(doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName): RdFifoInst = {
val res = createRdFifo(symbol.name.toLowerCase(), regPtr, doc, sec, grp)
regPtr += wordAddressInc
res
}
def newRdFifoAt(address: BigInt, doc: String, sec: Secure = null, grp: GrpTag = null)(implicit symbol: SymbolName): RdFifoInst = {
assert(address % wordAddressInc == 0, s"located Position not align by wordAddressInc: ${wordAddressInc}")
val res = createRdFifo(symbol.name.toLowerCase(), address, doc, sec, grp)
regPtr = address + wordAddressInc
res
}
def newGrp(maxSize: BigInt, doc: String, sec: Secure = null)(implicit symbol: SymbolName) = {
createGrp(symbol.name, regPtr, maxSize, doc, sec)
}
def newGrpAt(address: BigInt, maxSize: BigInt, doc: String, sec: Secure = null)(implicit symbol: SymbolName) = {
createGrp(symbol.name, address, maxSize, doc, sec)
}
def createGrp(name: String, addr: BigInt, maxSize: BigInt, doc: String, sec: Secure = null) = {
val grp = this.newGrpTag(name)
val ret = RegSliceGrp(addr, maxSize, doc, sec, grp)(this)
ret
}
def accept(doc: BusIfDoc) = {
preCheck()
doc.generate(this)
}
def gen(doc: BusIfDoc) = {
preCheck()
doc.generate(this)
}
def genBaseDocs(docname: String, prefix: String = "") = {
this.accept(DocHtml(docname))
this.accept(DocJson(docname))
this.accept(DocRalf(docname))
this.accept(DocCHeader(docname, prefix))
this.accept(DocSVHeader(docname, prefix))
}
private def regReadPart() = {
switch(readAddress()) {
RegAndFifos.foreach{ (x: RegSlice) =>
if(!x.allIsNA) x.readGenerator()
}
default {
reg_rdata := readDefaultValue
//Reserved Address Set False, True is too much strict for software
if (withStrb) {
reg_rderr := False
} else {
val alignreadhit = readAddress.take(log2Up(wordAddressInc)).orR
reg_rderr := Mux(alignreadhit, True, False)
}
}
}
}
private def regReadGenerator() = {
when(askRead){
regReadPart()
}.otherwise{
//do not keep readData after read for the reason of security risk
reg_rdata := readDefaultValue
reg_rderr := False
}
}
private def readGenerator(): Unit = {
this.regReadGenerator()
val mux = WhenBuilder()
RamInsts.foreach{ ram =>
mux.when(ram.ram_rdvalid) {
bus_rderr := False
bus_rdata := ram.readBits
}
}
mux.otherwise {
bus_rderr := reg_rderr
bus_rdata := reg_rdata
}
}
}