parent
26597f78cd
commit
2f384364d8
|
@ -0,0 +1,533 @@
|
|||
package SpinalRiscv.Plugin
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
|
||||
|
||||
|
||||
class DBusCachedPlugin {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
case class DataCacheConfig( cacheSize : Int,
|
||||
bytePerLine : Int,
|
||||
wayCount : Int,
|
||||
addressWidth : Int,
|
||||
cpuDataWidth : Int,
|
||||
memDataWidth : Int){
|
||||
def burstSize = bytePerLine*8/memDataWidth
|
||||
val burstLength = bytePerLine/(memDataWidth/8)
|
||||
}
|
||||
|
||||
object DataCacheCpuCmdKind extends SpinalEnum{
|
||||
val MEMORY,FLUSH,EVICT = newElement()
|
||||
}
|
||||
|
||||
object DataCacheCpuExecute{
|
||||
implicit def implArgs(that : DataCacheCpuExecute) = that.args
|
||||
}
|
||||
|
||||
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||
val isValid = Bool
|
||||
val isStuck = Bool
|
||||
val haltIt = Bool
|
||||
val args = DataCacheCpuExecuteArgs(p)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStuck, args)
|
||||
in(haltIt)
|
||||
}
|
||||
}
|
||||
|
||||
case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
|
||||
val kind = DataCacheCpuCmdKind()
|
||||
val wr = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val data = Bits(p.cpuDataWidth bit)
|
||||
val mask = Bits(p.cpuDataWidth/8 bit)
|
||||
val bypass = Bool
|
||||
val all = Bool //Address should be zero when "all" is used
|
||||
}
|
||||
|
||||
case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||
val isValid = Bool
|
||||
val isStall = Bool
|
||||
val haltIt = Bool
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStall)
|
||||
in(haltIt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||
val isValid = Bool
|
||||
val haltIt = Bool
|
||||
val data = Bits(p.cpuDataWidth bit)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid)
|
||||
in(haltIt, data)
|
||||
}
|
||||
}
|
||||
|
||||
case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||
val execute = DataCacheCpuExecute(p)
|
||||
val memory = DataCacheCpuMemory(p)
|
||||
val writeBack = DataCacheCpuWriteBack(p)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(execute)
|
||||
master(memory)
|
||||
master(writeBack)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{
|
||||
val wr = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val data = Bits(p.memDataWidth bits)
|
||||
val mask = Bits(p.memDataWidth/8 bits)
|
||||
val length = UInt(log2Up(p.burstLength+1) bit)
|
||||
}
|
||||
case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{
|
||||
val data = Bits(p.memDataWidth bit)
|
||||
}
|
||||
|
||||
case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||
val cmd = Stream (DataCacheMemCmd(p))
|
||||
val rsp = Flow (DataCacheMemRsp(p))
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DataCache(p : DataCacheConfig) extends Component{
|
||||
import p._
|
||||
assert(wayCount == 1)
|
||||
assert(cpuDataWidth == memDataWidth)
|
||||
|
||||
val io = new Bundle{
|
||||
val cpu = slave(DataCacheCpuBus(p))
|
||||
val mem = master(DataCacheMemBus(p))
|
||||
val flushDone = out Bool //It pulse at the same time than the manager.request.fire
|
||||
}
|
||||
val haltCpu = False
|
||||
val lineWidth = bytePerLine*8
|
||||
val lineCount = cacheSize/bytePerLine
|
||||
val wordWidth = Math.max(memDataWidth,cpuDataWidth)
|
||||
val wordWidthLog2 = log2Up(wordWidth)
|
||||
val wordPerLine = lineWidth/wordWidth
|
||||
val bytePerWord = wordWidth/8
|
||||
val wayLineCount = lineCount/wayCount
|
||||
val wayLineLog2 = log2Up(wayLineCount)
|
||||
val wayWordCount = wayLineCount * wordPerLine
|
||||
val memTransactionPerLine = p.bytePerLine / (p.memDataWidth/8)
|
||||
|
||||
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
||||
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
||||
val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord)
|
||||
|
||||
|
||||
class LineInfo() extends Bundle{
|
||||
val used = Bool
|
||||
val dirty = Bool
|
||||
val address = UInt(tagRange.length bit)
|
||||
}
|
||||
|
||||
val tagsReadCmd = UInt(log2Up(wayLineCount) bits)
|
||||
val tagsWriteCmd = Flow(new Bundle{
|
||||
val way = UInt(log2Up(wayCount) bits)
|
||||
val address = UInt(log2Up(wayLineCount) bits)
|
||||
val data = new LineInfo()
|
||||
})
|
||||
|
||||
val tagsWriteLastCmd = RegNext(tagsWriteCmd)
|
||||
|
||||
val dataReadCmd = UInt(log2Up(wayWordCount) bits)
|
||||
val dataWriteCmd = Flow(new Bundle{
|
||||
val way = UInt(log2Up(wayCount) bits)
|
||||
val address = UInt(log2Up(wayWordCount) bits)
|
||||
val data = Bits(wordWidth bits)
|
||||
val mask = Bits(wordWidth/8 bits)
|
||||
})
|
||||
|
||||
tagsWriteCmd.valid := False
|
||||
tagsWriteCmd.payload.assignDontCare()
|
||||
dataWriteCmd.valid := False
|
||||
dataWriteCmd.payload.assignDontCare()
|
||||
io.mem.cmd.valid := False
|
||||
io.mem.cmd.payload.assignDontCare()
|
||||
|
||||
|
||||
|
||||
|
||||
val ways = Array.tabulate(wayCount)(id => new Area{
|
||||
val tags = Mem(new LineInfo(),wayLineCount)
|
||||
val data = Mem(Bits(wordWidth bit),wayWordCount)
|
||||
|
||||
when(tagsWriteCmd.valid && tagsWriteCmd.way === id){
|
||||
tags(tagsWriteCmd.address) := tagsWriteCmd.data
|
||||
}
|
||||
when(dataWriteCmd.valid && dataWriteCmd.way === id){
|
||||
data.write(
|
||||
address = dataWriteCmd.address,
|
||||
data = dataWriteCmd.data,
|
||||
mask = dataWriteCmd.mask
|
||||
)
|
||||
}
|
||||
val dataReadRsp = data.readSync(dataReadCmd)
|
||||
})
|
||||
|
||||
val dataReadedValue = Vec(id => RegNext(ways(id).dataReadRsp),ways.length)
|
||||
|
||||
|
||||
|
||||
|
||||
val victim = new Area{
|
||||
val requestIn = Stream(cloneable(new Bundle{
|
||||
val way = UInt(log2Up(wayCount) bits)
|
||||
val address = UInt(p.addressWidth bits)
|
||||
}))
|
||||
requestIn.valid := False
|
||||
requestIn.payload.assignDontCare()
|
||||
|
||||
val request = requestIn.stage()
|
||||
request.ready := False
|
||||
|
||||
val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << 1) // << 1 because of cyclone II issue, should be removed //.add(new AttributeString("ramstyle","M4K"))
|
||||
|
||||
//Send line read commands to fill the buffer
|
||||
val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
|
||||
val dataReadCmdOccure = False
|
||||
val dataReadCmdOccureLast = RegNext(dataReadCmdOccure)
|
||||
|
||||
when(request.valid && !readLineCmdCounter.msb){
|
||||
readLineCmdCounter := readLineCmdCounter + 1
|
||||
//dataReadCmd := request.address(lineRange.high downto wordRange.low) Done in the manager
|
||||
dataReadCmdOccure := True
|
||||
}
|
||||
|
||||
//Fill the buffer with line read responses
|
||||
val readLineRspCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
|
||||
when(readLineCmdCounter >= 2 && !readLineRspCounter.msb && Delay(dataReadCmdOccure,2)){
|
||||
buffer(readLineRspCounter.resized) := dataReadedValue(request.way)
|
||||
readLineRspCounter := readLineRspCounter + 1
|
||||
}
|
||||
|
||||
//Send buffer read commands
|
||||
val bufferReadCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
|
||||
val bufferReadStream = Stream(buffer.addressType)
|
||||
bufferReadStream.valid := readLineRspCounter > bufferReadCounter
|
||||
bufferReadStream.payload := bufferReadCounter.resized
|
||||
when(bufferReadStream.fire){
|
||||
bufferReadCounter := bufferReadCounter + 1
|
||||
}
|
||||
val bufferReaded = buffer.streamReadSync(bufferReadStream).stage
|
||||
bufferReaded.ready := False
|
||||
|
||||
//Send memory writes from bufffer read responses
|
||||
val bufferReadedCounter = Reg(UInt(log2Up(memTransactionPerLine) bits)) init(0)
|
||||
val memCmdAlreadyUsed = False
|
||||
when(bufferReaded.valid) {
|
||||
io.mem.cmd.valid := True
|
||||
io.mem.cmd.wr := True
|
||||
io.mem.cmd.address := request.address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
|
||||
io.mem.cmd.length := p.burstLength
|
||||
io.mem.cmd.data := bufferReaded.payload
|
||||
io.mem.cmd.mask := (1<<(wordWidth/8))-1
|
||||
|
||||
when(!memCmdAlreadyUsed && io.mem.cmd.ready){
|
||||
bufferReaded.ready := True
|
||||
bufferReadedCounter := bufferReadedCounter + 1
|
||||
when(bufferReadedCounter === bufferReadedCounter.maxValue){
|
||||
request.ready := True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val counter = Counter(memTransactionPerLine)
|
||||
when(request.ready){
|
||||
readLineCmdCounter.msb := False
|
||||
readLineRspCounter.msb := False
|
||||
bufferReadCounter.msb := False
|
||||
}
|
||||
}
|
||||
|
||||
val manager = new Area {
|
||||
io.flushDone := False
|
||||
|
||||
io.cpu.execute.haltIt := False
|
||||
val request = RegNextWhen(io.cpu.execute.args, !io.cpu.execute.isStuck)
|
||||
|
||||
//Evict the cache after reset
|
||||
val requestValid = io.cpu.memory.isValid || RegNextWhen(False, !io.cpu.memory.isStall, True)
|
||||
request.kind.getDrivingReg.init(DataCacheCpuCmdKind.EVICT)
|
||||
request.all.getDrivingReg.init(True)
|
||||
request.address.getDrivingReg.init(0)
|
||||
|
||||
io.cpu.memory.haltIt := requestValid
|
||||
|
||||
val waysHitValid = False
|
||||
val waysHitOneHot = Bits(wayCount bits)
|
||||
val waysHitId = OHToUInt(waysHitOneHot)
|
||||
val waysHitInfo = new LineInfo().assignDontCare()
|
||||
|
||||
//delayedXX are used to relax logic timings in flush and evict modes
|
||||
val delayedValid = RegNext(io.cpu.memory.isStall) init(False)
|
||||
val delayedWaysHitValid = RegNext(waysHitValid)
|
||||
val delayedWaysHitId = RegNext(waysHitId)
|
||||
|
||||
val waysReadAddress = Mux(io.cpu.memory.isStall, request.address, io.cpu.execute.address)
|
||||
tagsReadCmd := waysReadAddress(lineRange)
|
||||
dataReadCmd := waysReadAddress(lineRange.high downto wordRange.low)
|
||||
when(victim.dataReadCmdOccure){
|
||||
dataReadCmd := victim.request.address(lineRange) @@ victim.readLineCmdCounter(victim.readLineCmdCounter.high-1 downto 0)
|
||||
}
|
||||
val waysRead = for ((way,id) <- ways.zipWithIndex) yield new Area {
|
||||
val tag = way.tags.readSync(tagsReadCmd)
|
||||
//Write first
|
||||
when(tagsWriteLastCmd.valid && tagsWriteLastCmd.way === id && tagsWriteLastCmd.address === RegNext(waysReadAddress(lineRange))){
|
||||
tag := tagsWriteLastCmd.data
|
||||
}
|
||||
waysHitOneHot(id) := tag.used && tag.address === request.address(tagRange)
|
||||
when(waysHitOneHot(id)) {
|
||||
waysHitValid := True
|
||||
waysHitInfo := tag
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val writebackWayId = U(0) //Only one way compatible
|
||||
val writebackWayInfo = Vec(waysRead.map(_.tag))(writebackWayId)
|
||||
|
||||
val cpuRspIn = Stream(wrap(new Bundle{
|
||||
val fromBypass = Bool
|
||||
val wayId = UInt(log2Up(wayCount) bits)
|
||||
}))
|
||||
|
||||
cpuRspIn.valid := False
|
||||
cpuRspIn.fromBypass := False
|
||||
cpuRspIn.wayId := waysHitId
|
||||
|
||||
//Loader interface
|
||||
val loaderValid = False
|
||||
val loaderReady = False
|
||||
val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse
|
||||
|
||||
val victimSent = RegInit(False)
|
||||
victimSent := (victimSent || victim.requestIn.fire) && io.cpu.memory.isStall
|
||||
|
||||
val flushAllState = RegInit(False) //Used to keep logic timings fast
|
||||
val flushAllDone = RegNext(False) init(False)
|
||||
when(requestValid) {
|
||||
switch(request.kind) {
|
||||
import DataCacheCpuCmdKind._
|
||||
is(EVICT){
|
||||
when(request.all){
|
||||
tagsWriteCmd.valid := True
|
||||
tagsWriteCmd.way := 0
|
||||
tagsWriteCmd.address := request.address(lineRange)
|
||||
tagsWriteCmd.data.used := False
|
||||
when(request.address(lineRange) =/= lineCount-1){
|
||||
request.address.getDrivingReg(lineRange) := request.address(lineRange) + 1
|
||||
}otherwise{
|
||||
io.cpu.memory.haltIt := False
|
||||
}
|
||||
}otherwise{
|
||||
when(delayedValid) {
|
||||
when(delayedWaysHitValid) {
|
||||
tagsWriteCmd.valid := True
|
||||
tagsWriteCmd.way := delayedWaysHitId
|
||||
tagsWriteCmd.address := request.address(lineRange)
|
||||
tagsWriteCmd.data.used := False
|
||||
}
|
||||
io.cpu.memory.haltIt := False
|
||||
}
|
||||
}
|
||||
}
|
||||
is(FLUSH) {
|
||||
when(request.all) {
|
||||
when(!flushAllState){
|
||||
victim.requestIn.valid := waysRead(0).tag.used && waysRead(0).tag.dirty
|
||||
victim.requestIn.way := writebackWayId
|
||||
victim.requestIn.address := writebackWayInfo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
||||
|
||||
tagsWriteCmd.way := writebackWayId
|
||||
tagsWriteCmd.address := request.address(lineRange)
|
||||
tagsWriteCmd.data.used := False
|
||||
|
||||
when(!victim.requestIn.isStall) {
|
||||
request.address.getDrivingReg(lineRange) := request.address(lineRange) + 1
|
||||
flushAllDone := request.address(lineRange) === lineCount-1
|
||||
flushAllState := True
|
||||
tagsWriteCmd.valid := True
|
||||
}
|
||||
} otherwise{
|
||||
//Wait tag read
|
||||
flushAllState := False
|
||||
io.cpu.memory.haltIt.clearWhen(flushAllDone)
|
||||
io.flushDone := flushAllDone
|
||||
}
|
||||
} otherwise {
|
||||
when(delayedValid) {
|
||||
when(delayedWaysHitValid) {
|
||||
io.cpu.memory.haltIt.clearWhen(victim.requestIn.ready)
|
||||
|
||||
victim.requestIn.valid := True
|
||||
victim.requestIn.way := writebackWayId
|
||||
victim.requestIn.address := writebackWayInfo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
||||
|
||||
tagsWriteCmd.valid := victim.requestIn.ready
|
||||
tagsWriteCmd.way := writebackWayId
|
||||
tagsWriteCmd.address := request.address(lineRange)
|
||||
tagsWriteCmd.data.used := False
|
||||
} otherwise{
|
||||
io.cpu.memory.haltIt := False
|
||||
io.flushDone := True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is(MEMORY) {
|
||||
when(request.bypass) {
|
||||
when(!victim.request.valid) {
|
||||
//Can't insert mem cmd into a victim write burst
|
||||
io.mem.cmd.valid := !(!request.wr && !cpuRspIn.ready)
|
||||
io.mem.cmd.wr := request.wr
|
||||
io.mem.cmd.address := request.address(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit)
|
||||
io.mem.cmd.mask := request.mask
|
||||
io.mem.cmd.data := request.data
|
||||
io.mem.cmd.length := 1
|
||||
|
||||
cpuRspIn.valid := !request.wr && io.mem.cmd.fire
|
||||
cpuRspIn.fromBypass := True
|
||||
|
||||
io.cpu.memory.haltIt.clearWhen(io.mem.cmd.fire)
|
||||
} otherwise {
|
||||
io.cpu.memory.haltIt := True //TODO redondent ?
|
||||
}
|
||||
} otherwise {
|
||||
when(waysHitValid && !loadingDone) { // !loadingDone => don't solve the request directly after loader (data write to read latency)
|
||||
when(request.wr) {
|
||||
dataWriteCmd.valid := True
|
||||
dataWriteCmd.way := waysHitId
|
||||
dataWriteCmd.address := request.address(lineRange.high downto wordRange.low)
|
||||
dataWriteCmd.data := request.data
|
||||
dataWriteCmd.mask := request.mask
|
||||
|
||||
tagsWriteCmd.valid := True
|
||||
tagsWriteCmd.way := waysHitId
|
||||
tagsWriteCmd.address := request.address(lineRange)
|
||||
tagsWriteCmd.data.used := True
|
||||
tagsWriteCmd.data.dirty := True
|
||||
tagsWriteCmd.data.address := request.address(tagRange)
|
||||
io.cpu.memory.haltIt := False
|
||||
} otherwise {
|
||||
cpuRspIn.valid := !victim.dataReadCmdOccureLast
|
||||
io.cpu.memory.haltIt.clearWhen(cpuRspIn.ready && !victim.dataReadCmdOccureLast) //dataReadCmdOccure to avoid the case where flush,then read will victim use data read
|
||||
}
|
||||
} otherwise {
|
||||
io.cpu.memory.haltIt := True //Exit this state automaticly (tags read port write first logic) TODO redondent ?
|
||||
loaderValid := !loadingDone && !(!victimSent && victim.request.isStall) //Wait previous victim request to be completed
|
||||
when(writebackWayInfo.used && writebackWayInfo.dirty) {
|
||||
victim.requestIn.valid := !victimSent
|
||||
victim.requestIn.way := writebackWayId
|
||||
victim.requestIn.address := writebackWayInfo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val cpuRsp = cpuRspIn.m2sPipe()
|
||||
val cpuRspIsWaitingMemRsp = cpuRsp.valid && io.mem.rsp.valid
|
||||
io.cpu.writeBack.haltIt := io.cpu.memory.isValid && cpuRsp.isStall
|
||||
io.cpu.writeBack.data := Mux(cpuRsp.fromBypass,io.mem.rsp.data,dataReadedValue(cpuRsp.wayId))
|
||||
cpuRsp.ready := !(cpuRsp.fromBypass && !io.mem.rsp.valid)
|
||||
}
|
||||
|
||||
//The whole life of a loading task, the corresponding manager request is present
|
||||
val loader = new Area{
|
||||
val valid = RegNext(manager.loaderValid)
|
||||
val wayId = RegNext(manager.writebackWayId)
|
||||
val baseAddress = manager.request.address
|
||||
|
||||
val memCmdSent = RegInit(False)
|
||||
when(valid && !memCmdSent) {
|
||||
io.mem.cmd.valid := True
|
||||
io.mem.cmd.wr := False
|
||||
io.mem.cmd.address := baseAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
|
||||
io.mem.cmd.length := p.burstLength
|
||||
}
|
||||
|
||||
when(valid && io.mem.cmd.ready){
|
||||
memCmdSent := True
|
||||
}
|
||||
|
||||
when(valid && !memCmdSent) {
|
||||
victim.memCmdAlreadyUsed := True
|
||||
}
|
||||
|
||||
val counter = Counter(memTransactionPerLine)
|
||||
when(io.mem.rsp.valid && !manager.cpuRspIsWaitingMemRsp){
|
||||
dataWriteCmd.valid := True
|
||||
dataWriteCmd.way := wayId
|
||||
dataWriteCmd.address := baseAddress(lineRange) @@ counter
|
||||
dataWriteCmd.data := io.mem.rsp.data
|
||||
dataWriteCmd.mask := (1<<(wordWidth/8))-1
|
||||
counter.increment()
|
||||
}
|
||||
|
||||
when(counter.willOverflow){
|
||||
memCmdSent := False
|
||||
valid := False
|
||||
tagsWriteCmd.valid := True
|
||||
tagsWriteCmd.way := wayId
|
||||
tagsWriteCmd.address := baseAddress(lineRange)
|
||||
tagsWriteCmd.data.used := True
|
||||
tagsWriteCmd.data.dirty := False
|
||||
tagsWriteCmd.data.address := baseAddress(tagRange)
|
||||
manager.loaderReady := True
|
||||
}
|
||||
}
|
||||
|
||||
//Avoid read after write data hazard
|
||||
//TODO FIX it to not stall write after read ? , requestValid is pessimistic ?
|
||||
io.cpu.execute.haltIt := io.cpu.execute.address === manager.request.address && manager.requestValid && io.cpu.execute.isValid
|
||||
}
|
||||
|
||||
object DataCacheMain{
|
||||
def main(args: Array[String]) {
|
||||
|
||||
SpinalVhdl({
|
||||
implicit val p = DataCacheConfig(
|
||||
cacheSize =4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32)
|
||||
new WrapWithReg.Wrapper(new DataCache(p)).setDefinitionName("TopLevel")
|
||||
})
|
||||
// SpinalVhdl({
|
||||
// implicit val p = DataCacheConfig(
|
||||
// cacheSize =512,
|
||||
// bytePerLine =16,
|
||||
// wayCount = 1,
|
||||
// addressWidth = 12,
|
||||
// cpuDataWidth = 16,
|
||||
// memDataWidth = 16)
|
||||
// new DataCache(p)
|
||||
// })
|
||||
}
|
||||
}
|
|
@ -12,16 +12,29 @@ case class DBusSimpleCmd() extends Bundle{
|
|||
val size = UInt(2 bit)
|
||||
}
|
||||
|
||||
case class DBusSimpleRsp() extends Bundle{
|
||||
case class DBusSimpleRsp() extends Bundle with IMasterSlave{
|
||||
val ready = Bool
|
||||
val error = Bool
|
||||
val data = Bits(32 bit)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(ready,error,data)
|
||||
}
|
||||
}
|
||||
|
||||
case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
||||
val cmd = Stream(DBusSimpleCmd())
|
||||
val rsp = DBusSimpleRsp()
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||
|
||||
var dCmd : Stream[DBusSimpleCmd] = null
|
||||
var dRsp : DBusSimpleRsp = null
|
||||
var dBus : DBusSimpleBus = null
|
||||
|
||||
object MemoryCtrlEnum extends SpinalEnum{
|
||||
val WR, RD = newElement()
|
||||
|
@ -88,49 +101,50 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Bool
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
//Emit dCmd request
|
||||
dBus = master(DBusSimpleBus()).setName("dBus")
|
||||
|
||||
//Emit dBus.cmd request
|
||||
execute plug new Area{
|
||||
import execute._
|
||||
|
||||
dCmd = master(Stream(DBusSimpleCmd())).setName("dCmd")
|
||||
dCmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.removeIt
|
||||
dCmd.wr := input(INSTRUCTION)(5)
|
||||
dCmd.address := input(SRC_ADD_SUB).asUInt
|
||||
dCmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
||||
dCmd.payload.data := dCmd.size.mux (
|
||||
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.removeIt
|
||||
dBus.cmd.wr := input(INSTRUCTION)(5)
|
||||
dBus.cmd.address := input(SRC_ADD_SUB).asUInt
|
||||
dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
||||
dBus.cmd.payload.data := dBus.cmd.size.mux (
|
||||
U(0) -> input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0),
|
||||
U(1) -> input(REG2)(15 downto 0) ## input(REG2)(15 downto 0),
|
||||
default -> input(REG2)(31 downto 0)
|
||||
)
|
||||
when(arbitration.isValid && input(MEMORY_ENABLE) && !dCmd.ready){
|
||||
when(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.cmd.ready){
|
||||
arbitration.haltIt := True
|
||||
}
|
||||
|
||||
insert(MEMORY_ADDRESS_LOW) := dCmd.address(1 downto 0)
|
||||
insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0)
|
||||
|
||||
if(catchAddressMisaligned){
|
||||
executeExceptionPort.code := (dCmd.wr ? U(6) | U(4)).resized
|
||||
executeExceptionPort.badAddr := dCmd.address
|
||||
executeExceptionPort.code := (dBus.cmd.wr ? U(6) | U(4)).resized
|
||||
executeExceptionPort.badAddr := dBus.cmd.address
|
||||
executeExceptionPort.valid := (arbitration.isValid && input(MEMORY_ENABLE)
|
||||
&& ((dCmd.size === 2 && dCmd.address(1 downto 0) =/= 0) || (dCmd.size === 1 && dCmd.address(0 downto 0) =/= 0)))
|
||||
&& ((dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0)))
|
||||
}
|
||||
}
|
||||
|
||||
//Collect dRsp read responses
|
||||
//Collect dBus.rsp read responses
|
||||
memory plug new Area {
|
||||
import memory._
|
||||
|
||||
dRsp = in(DBusSimpleRsp()).setName("dRsp")
|
||||
insert(MEMORY_READ_DATA) := dRsp.data
|
||||
arbitration.haltIt setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !dRsp.ready)
|
||||
|
||||
insert(MEMORY_READ_DATA) := dBus.rsp.data
|
||||
arbitration.haltIt setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.rsp.ready)
|
||||
|
||||
if(catchAccessFault){
|
||||
memoryExceptionPort.valid := arbitration.isValid && input(MEMORY_ENABLE) && dRsp.ready && dRsp.error
|
||||
memoryExceptionPort.valid := arbitration.isValid && input(MEMORY_ENABLE) && dBus.rsp.ready && dBus.rsp.error
|
||||
memoryExceptionPort.code := 5
|
||||
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt //Drived by IntAluPlugin
|
||||
}
|
||||
|
||||
assert(!(dRsp.ready && input(MEMORY_ENABLE) && arbitration.isValid && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
|
||||
assert(!(dBus.rsp.ready && input(MEMORY_ENABLE) && arbitration.isValid && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
|
||||
}
|
||||
|
||||
//Reformat read responses, REGFILE_WRITE_DATA overriding
|
||||
|
|
|
@ -9,15 +9,29 @@ case class IBusSimpleCmd() extends Bundle{
|
|||
val pc = UInt(32 bits)
|
||||
}
|
||||
|
||||
case class IBusSimpleRsp() extends Bundle{
|
||||
case class IBusSimpleRsp() extends Bundle with IMasterSlave{
|
||||
val ready = Bool
|
||||
val error = Bool
|
||||
val inst = Bits(32 bits)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(ready,error,inst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class IBusSimpleBus() extends Bundle with IMasterSlave{
|
||||
var cmd = Stream(IBusSimpleCmd())
|
||||
var rsp = IBusSimpleRsp()
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||
var iCmd : Stream[IBusSimpleCmd] = null
|
||||
var iRsp : IBusSimpleRsp = null
|
||||
var iBus : IBusSimpleBus = null
|
||||
|
||||
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
|
@ -34,18 +48,18 @@ class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean)
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
//Emit iCmd request
|
||||
require(interfaceKeepData)
|
||||
iCmd = master(Stream(IBusSimpleCmd())).setName("iCmd")
|
||||
iCmd.valid := prefetch.arbitration.isFiring //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
iCmd.pc := prefetch.output(PC)
|
||||
prefetch.arbitration.haltIt setWhen(!iCmd.ready)
|
||||
iBus = master(IBusSimpleBus()).setName("iBus")
|
||||
|
||||
//Emit iBus.cmd request
|
||||
iBus.cmd.valid := prefetch.arbitration.isFiring //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
iBus.cmd.pc := prefetch.output(PC)
|
||||
prefetch.arbitration.haltIt setWhen(!iBus.cmd.ready)
|
||||
|
||||
//Insert iRsp into INSTRUCTION
|
||||
iRsp = in(IBusSimpleRsp()).setName("iRsp")
|
||||
fetch.insert(INSTRUCTION) := iRsp.inst
|
||||
fetch.insert(IBUS_ACCESS_ERROR) := iRsp.error
|
||||
fetch.arbitration.haltIt setWhen(fetch.arbitration.isValid && !iRsp.ready)
|
||||
//Insert iBus.rsp into INSTRUCTION
|
||||
fetch.insert(INSTRUCTION) := iBus.rsp.inst
|
||||
fetch.insert(IBUS_ACCESS_ERROR) := iBus.rsp.error
|
||||
fetch.arbitration.haltIt setWhen(fetch.arbitration.isValid && !iBus.rsp.ready)
|
||||
|
||||
if(catchAccessFault){
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||
|
|
|
@ -79,22 +79,22 @@ object TopLevel {
|
|||
|
||||
config.plugins ++= List(
|
||||
new PcManagerSimplePlugin(0x00000000l, false),
|
||||
// new IBusSimplePlugin(
|
||||
// interfaceKeepData = true,
|
||||
// catchAccessFault = true
|
||||
// ),
|
||||
new IBusCachedPlugin(
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize =4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchAccessFault = true
|
||||
)
|
||||
new IBusSimplePlugin(
|
||||
interfaceKeepData = true,
|
||||
catchAccessFault = true
|
||||
),
|
||||
// new IBusCachedPlugin(
|
||||
// config = InstructionCacheConfig(
|
||||
// cacheSize =4096,
|
||||
// bytePerLine =32,
|
||||
// wayCount = 1,
|
||||
// wrappedMemAccess = true,
|
||||
// addressWidth = 32,
|
||||
// cpuDataWidth = 32,
|
||||
// memDataWidth = 32,
|
||||
// catchAccessFault = true
|
||||
// )
|
||||
// ),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
),
|
||||
|
|
|
@ -141,8 +141,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class Workspace;
|
||||
void fillSimELements(Workspace *ws);
|
||||
|
||||
|
||||
class Workspace{
|
||||
public:
|
||||
|
@ -150,6 +149,8 @@ public:
|
|||
vector<SimElement*> simElements;
|
||||
Memory mem;
|
||||
string name;
|
||||
uint64_t mTimeCmp = 0;
|
||||
uint64_t mTime = 0;
|
||||
VVexRiscv* top;
|
||||
int i;
|
||||
uint32_t bootPc = -1;
|
||||
|
@ -173,7 +174,7 @@ public:
|
|||
regTraces.open (name + ".regTrace");
|
||||
memTraces.open (name + ".memTrace");
|
||||
logTraces.open (name + ".logTrace");
|
||||
fillSimELements(this);
|
||||
fillSimELements();
|
||||
}
|
||||
|
||||
virtual ~Workspace(){
|
||||
|
@ -190,7 +191,7 @@ public:
|
|||
|
||||
Workspace* bootAt(uint32_t pc) { bootPc = pc;}
|
||||
|
||||
virtual bool isAccessError(uint32_t addr) { return addr == 0xF00FFF60u; }
|
||||
|
||||
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) {
|
||||
assert(addr % 4 == 0);
|
||||
*data = ( (mem[addr + 0] << 0)
|
||||
|
@ -199,10 +200,66 @@ public:
|
|||
| (mem[addr + 3] << 24));
|
||||
*error = addr == 0xF00FFF60u;
|
||||
}
|
||||
virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint32_t *data, bool *error) {
|
||||
*error = addr == 0xF00FFF60u;
|
||||
if(wr){
|
||||
memTraces <<
|
||||
#ifdef TRACE_WITH_TIME
|
||||
(currentTime
|
||||
#ifdef REF
|
||||
-2
|
||||
#endif
|
||||
) <<
|
||||
#endif
|
||||
" : WRITE mem" << (1 << size) << "[" << addr << "] = " << *data << endl;
|
||||
for(uint32_t b = 0;b < (1 << size);b++){
|
||||
uint32_t offset = (addr+b)&0x3;
|
||||
*mem.get(addr + b) = *data >> (offset*8);
|
||||
}
|
||||
|
||||
switch(addr){
|
||||
case 0xF00FFF00u: {
|
||||
cout << mem[0xF00FFF00u];
|
||||
logTraces << (char)mem[0xF00FFF00u];
|
||||
break;
|
||||
}
|
||||
case 0xF00FFF20u: pass(); break;
|
||||
case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break;
|
||||
case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); /*cout << "mTimeCmp <= " << mTimeCmp << endl; */break;
|
||||
}
|
||||
}else{
|
||||
*data = VL_RANDOM_I(32);
|
||||
for(uint32_t b = 0;b < (1 << size);b++){
|
||||
uint32_t offset = (addr+b)&0x3;
|
||||
*data &= ~(0xFF << (offset*8));
|
||||
*data |= mem[addr + b] << (offset*8);
|
||||
}
|
||||
switch(addr){
|
||||
case 0xF00FFF10u:
|
||||
*data = i/2;
|
||||
break;
|
||||
case 0xF00FFF40u: *data = mTime; break;
|
||||
case 0xF00FFF44u: *data = mTime >> 32; break;
|
||||
case 0xF00FFF48u: *data = mTimeCmp; break;
|
||||
case 0xF00FFF4Cu: *data = mTimeCmp >> 32; break;
|
||||
}
|
||||
memTraces <<
|
||||
#ifdef TRACE_WITH_TIME
|
||||
(currentTime
|
||||
#ifdef REF
|
||||
-2
|
||||
#endif
|
||||
) <<
|
||||
#endif
|
||||
" : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl;
|
||||
|
||||
}
|
||||
}
|
||||
virtual void postReset() {}
|
||||
virtual void checks(){}
|
||||
virtual void pass(){ throw success();}
|
||||
virtual void fail(){ throw std::exception();}
|
||||
virtual void fillSimELements();
|
||||
void dump(int i){
|
||||
#ifdef TRACE
|
||||
if(i/2 >= TRACE_START) tfp->dump(i);
|
||||
|
@ -210,8 +267,7 @@ public:
|
|||
}
|
||||
Workspace* run(uint32_t timeout = 5000){
|
||||
// cout << "Start " << name << endl;
|
||||
uint64_t mTimeCmp = 0;
|
||||
uint64_t mTime = 0;
|
||||
|
||||
currentTime = 4;
|
||||
// init trace dump
|
||||
Verilated::traceEverOn(true);
|
||||
|
@ -224,8 +280,6 @@ public:
|
|||
// Reset
|
||||
top->clk = 0;
|
||||
top->reset = 0;
|
||||
top->dCmd_ready = 1;
|
||||
top->dRsp_ready = 1;
|
||||
|
||||
for(SimElement* simElement : simElements) simElement->onReset();
|
||||
|
||||
|
@ -251,9 +305,6 @@ public:
|
|||
|
||||
try {
|
||||
// run simulation for 100 clock periods
|
||||
uint32_t dRsp_inst_next = VL_RANDOM_I(32);
|
||||
bool dRsp_error_next = false;
|
||||
bool dRsp_ready_pending = false;
|
||||
for (i = 16; i < timeout*2; i+=2) {
|
||||
mTime = i/2;
|
||||
#ifdef CSR
|
||||
|
@ -275,63 +326,6 @@ public:
|
|||
dump(i + 1);
|
||||
|
||||
|
||||
if (top->dCmd_valid && top->dCmd_ready && ! dRsp_ready_pending) {
|
||||
dRsp_ready_pending = true;
|
||||
dRsp_inst_next = VL_RANDOM_I(32);
|
||||
uint32_t addr = top->dCmd_payload_address;
|
||||
dRsp_error_next = isAccessError(addr);
|
||||
if(top->dCmd_payload_wr){
|
||||
memTraces <<
|
||||
#ifdef TRACE_WITH_TIME
|
||||
(currentTime
|
||||
#ifdef REF
|
||||
-2
|
||||
#endif
|
||||
) <<
|
||||
#endif
|
||||
" : WRITE mem" << (1 << top->dCmd_payload_size) << "[" << addr << "] = " << top->dCmd_payload_data << endl;
|
||||
for(uint32_t b = 0;b < (1 << top->dCmd_payload_size);b++){
|
||||
uint32_t offset = (addr+b)&0x3;
|
||||
*mem.get(addr + b) = top->dCmd_payload_data >> (offset*8);
|
||||
}
|
||||
|
||||
switch(addr){
|
||||
case 0xF00FFF00u: {
|
||||
cout << mem[0xF00FFF00u];
|
||||
logTraces << (char)mem[0xF00FFF00u];
|
||||
break;
|
||||
}
|
||||
case 0xF00FFF20u: pass(); break;
|
||||
case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | top->dCmd_payload_data;break;
|
||||
case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)top->dCmd_payload_data) << 32); /*cout << "mTimeCmp <= " << mTimeCmp << endl; */break;
|
||||
}
|
||||
}else{
|
||||
for(uint32_t b = 0;b < (1 << top->dCmd_payload_size);b++){
|
||||
uint32_t offset = (addr+b)&0x3;
|
||||
dRsp_inst_next &= ~(0xFF << (offset*8));
|
||||
dRsp_inst_next |= mem[addr + b] << (offset*8);
|
||||
}
|
||||
switch(addr){
|
||||
case 0xF00FFF10u:
|
||||
dRsp_inst_next = i/2;
|
||||
break;
|
||||
case 0xF00FFF40u: dRsp_inst_next = mTime; break;
|
||||
case 0xF00FFF44u: dRsp_inst_next = mTime >> 32; break;
|
||||
case 0xF00FFF48u: dRsp_inst_next = mTimeCmp; break;
|
||||
case 0xF00FFF4Cu: dRsp_inst_next = mTimeCmp >> 32; break;
|
||||
}
|
||||
memTraces <<
|
||||
#ifdef TRACE_WITH_TIME
|
||||
(currentTime
|
||||
#ifdef REF
|
||||
-2
|
||||
#endif
|
||||
) <<
|
||||
#endif
|
||||
" : READ mem" << (1 << top->dCmd_payload_size) << "[" << addr << "] = " << dRsp_inst_next << endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
|
||||
regTraces <<
|
||||
|
@ -358,17 +352,6 @@ public:
|
|||
|
||||
for(SimElement* simElement : simElements) simElement->postCycle();
|
||||
|
||||
top->dRsp_ready = 0;
|
||||
if(dRsp_ready_pending && (!dStall || VL_RANDOM_I(8) < 100)){
|
||||
top->dRsp_data = dRsp_inst_next;
|
||||
dRsp_ready_pending = false;
|
||||
top->dRsp_ready = 1;
|
||||
top->dRsp_error = dRsp_error_next;
|
||||
} else{
|
||||
top->dRsp_data = VL_RANDOM_I(32);
|
||||
}
|
||||
|
||||
if(dStall) top->dCmd_ready = VL_RANDOM_I(8) < 100 && !dRsp_ready_pending;
|
||||
|
||||
|
||||
if (Verilated::gotFinish())
|
||||
|
@ -411,27 +394,27 @@ public:
|
|||
}
|
||||
|
||||
virtual void onReset(){
|
||||
top->iCmd_ready = 1;
|
||||
top->iRsp_ready = 1;
|
||||
top->iBus_cmd_ready = 1;
|
||||
top->iBus_rsp_ready = 1;
|
||||
}
|
||||
|
||||
virtual void preCycle(){
|
||||
if (top->iCmd_valid && top->iCmd_ready && !pending) {
|
||||
assertEq(top->iCmd_payload_pc & 3,0);
|
||||
if (top->iBus_cmd_valid && top->iBus_cmd_ready && !pending) {
|
||||
assertEq(top->iBus_cmd_payload_pc & 3,0);
|
||||
pending = true;
|
||||
ws->iBusAccess(top->iCmd_payload_pc,&inst_next,&error_next);
|
||||
ws->iBusAccess(top->iBus_cmd_payload_pc,&inst_next,&error_next);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void postCycle(){
|
||||
top->iRsp_ready = !pending;
|
||||
if(pending && (!ws->iStall || VL_RANDOM_I(8) < 100)){
|
||||
top->iRsp_inst = inst_next;
|
||||
top->iBus_rsp_ready = !pending;
|
||||
if(pending && (!ws->iStall || VL_RANDOM_I(7) < 100)){
|
||||
top->iBus_rsp_inst = inst_next;
|
||||
pending = false;
|
||||
top->iRsp_ready = 1;
|
||||
top->iRsp_error = error_next;
|
||||
top->iBus_rsp_ready = 1;
|
||||
top->iBus_rsp_error = error_next;
|
||||
}
|
||||
if(ws->iStall) top->iCmd_ready = VL_RANDOM_I(8) < 100 && !pending;
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && !pending;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
@ -469,25 +452,72 @@ public:
|
|||
virtual void postCycle(){
|
||||
bool error;
|
||||
top->iBus_rsp_valid = 0;
|
||||
if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(8) < 100)){
|
||||
if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(7) < 100)){
|
||||
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error);
|
||||
top->iBus_rsp_payload_error = error;
|
||||
pendingCount--;
|
||||
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
||||
top->iBus_rsp_valid = 1;
|
||||
}
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(8) < 100 && pendingCount == 0;
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
void fillSimELements(Workspace *ws){
|
||||
#ifdef DBUS_SIMPLE
|
||||
class DBusSimple : public SimElement{
|
||||
public:
|
||||
uint32_t data_next = VL_RANDOM_I(32);
|
||||
bool error_next = false;
|
||||
bool pending = false;
|
||||
|
||||
Workspace *ws;
|
||||
VVexRiscv* top;
|
||||
DBusSimple(Workspace* ws){
|
||||
this->ws = ws;
|
||||
this->top = ws->top;
|
||||
}
|
||||
|
||||
virtual void onReset(){
|
||||
top->dBus_cmd_ready = 1;
|
||||
top->dBus_rsp_ready = 1;
|
||||
}
|
||||
|
||||
virtual void preCycle(){
|
||||
if (top->dBus_cmd_valid && top->dBus_cmd_ready && !pending) {
|
||||
pending = true;
|
||||
data_next = top->dBus_cmd_payload_data;
|
||||
ws->dBusAccess(top->dBus_cmd_payload_address,top->dBus_cmd_payload_wr,top->dBus_cmd_payload_size,&data_next,&error_next);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void postCycle(){
|
||||
top->dBus_rsp_ready = 0;
|
||||
if(pending && (!ws->dStall || VL_RANDOM_I(7) < 100)){
|
||||
pending = false;
|
||||
top->dBus_rsp_ready = 1;
|
||||
top->dBus_rsp_data = data_next;
|
||||
top->dBus_rsp_error = error_next;
|
||||
} else{
|
||||
top->dBus_rsp_data = VL_RANDOM_I(32);
|
||||
}
|
||||
|
||||
if(ws->dStall) top->dBus_cmd_ready = VL_RANDOM_I(7) < 100 && !pending;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void Workspace::fillSimELements(){
|
||||
|
||||
#ifdef IBUS_SIMPLE
|
||||
ws->simElements.push_back(new IBusSimple(ws));
|
||||
simElements.push_back(new IBusSimple(this));
|
||||
#endif
|
||||
#ifdef IBUS_CACHED
|
||||
ws->simElements.push_back(new IBusCached(ws));
|
||||
simElements.push_back(new IBusCached(this));
|
||||
#endif
|
||||
#ifdef DBUS_SIMPLE
|
||||
simElements.push_back(new DBusSimple(this));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
IBUS=IBUS_CACHED
|
||||
IBUS=IBUS_SIMPLE
|
||||
DBUS=DBUS_SIMPLE
|
||||
TRACE=no
|
||||
TRACE_START=0
|
||||
|
|
Loading…
Reference in New Issue