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)
|
val size = UInt(2 bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class DBusSimpleRsp() extends Bundle{
|
case class DBusSimpleRsp() extends Bundle with IMasterSlave{
|
||||||
val ready = Bool
|
val ready = Bool
|
||||||
val error = Bool
|
val error = Bool
|
||||||
val data = Bits(32 bit)
|
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]{
|
class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||||
|
|
||||||
var dCmd : Stream[DBusSimpleCmd] = null
|
var dBus : DBusSimpleBus = null
|
||||||
var dRsp : DBusSimpleRsp = null
|
|
||||||
|
|
||||||
object MemoryCtrlEnum extends SpinalEnum{
|
object MemoryCtrlEnum extends SpinalEnum{
|
||||||
val WR, RD = newElement()
|
val WR, RD = newElement()
|
||||||
|
@ -88,49 +101,50 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Bool
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
|
||||||
//Emit dCmd request
|
dBus = master(DBusSimpleBus()).setName("dBus")
|
||||||
|
|
||||||
|
//Emit dBus.cmd request
|
||||||
execute plug new Area{
|
execute plug new Area{
|
||||||
import execute._
|
import execute._
|
||||||
|
|
||||||
dCmd = master(Stream(DBusSimpleCmd())).setName("dCmd")
|
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.removeIt
|
||||||
dCmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.removeIt
|
dBus.cmd.wr := input(INSTRUCTION)(5)
|
||||||
dCmd.wr := input(INSTRUCTION)(5)
|
dBus.cmd.address := input(SRC_ADD_SUB).asUInt
|
||||||
dCmd.address := input(SRC_ADD_SUB).asUInt
|
dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
||||||
dCmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
dBus.cmd.payload.data := dBus.cmd.size.mux (
|
||||||
dCmd.payload.data := dCmd.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(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),
|
U(1) -> input(REG2)(15 downto 0) ## input(REG2)(15 downto 0),
|
||||||
default -> input(REG2)(31 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
|
arbitration.haltIt := True
|
||||||
}
|
}
|
||||||
|
|
||||||
insert(MEMORY_ADDRESS_LOW) := dCmd.address(1 downto 0)
|
insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0)
|
||||||
|
|
||||||
if(catchAddressMisaligned){
|
if(catchAddressMisaligned){
|
||||||
executeExceptionPort.code := (dCmd.wr ? U(6) | U(4)).resized
|
executeExceptionPort.code := (dBus.cmd.wr ? U(6) | U(4)).resized
|
||||||
executeExceptionPort.badAddr := dCmd.address
|
executeExceptionPort.badAddr := dBus.cmd.address
|
||||||
executeExceptionPort.valid := (arbitration.isValid && input(MEMORY_ENABLE)
|
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 {
|
memory plug new Area {
|
||||||
import memory._
|
import memory._
|
||||||
|
|
||||||
dRsp = in(DBusSimpleRsp()).setName("dRsp")
|
|
||||||
insert(MEMORY_READ_DATA) := dRsp.data
|
insert(MEMORY_READ_DATA) := dBus.rsp.data
|
||||||
arbitration.haltIt setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !dRsp.ready)
|
arbitration.haltIt setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.rsp.ready)
|
||||||
|
|
||||||
if(catchAccessFault){
|
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.code := 5
|
||||||
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt //Drived by IntAluPlugin
|
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
|
//Reformat read responses, REGFILE_WRITE_DATA overriding
|
||||||
|
|
|
@ -9,15 +9,29 @@ case class IBusSimpleCmd() extends Bundle{
|
||||||
val pc = UInt(32 bits)
|
val pc = UInt(32 bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class IBusSimpleRsp() extends Bundle{
|
case class IBusSimpleRsp() extends Bundle with IMasterSlave{
|
||||||
val ready = Bool
|
val ready = Bool
|
||||||
val error = Bool
|
val error = Bool
|
||||||
val inst = Bits(32 bits)
|
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]{
|
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||||
var iCmd : Stream[IBusSimpleCmd] = null
|
var iBus : IBusSimpleBus = null
|
||||||
var iRsp : IBusSimpleRsp = null
|
|
||||||
|
|
||||||
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||||
|
@ -34,18 +48,18 @@ class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean)
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
|
||||||
//Emit iCmd request
|
|
||||||
require(interfaceKeepData)
|
require(interfaceKeepData)
|
||||||
iCmd = master(Stream(IBusSimpleCmd())).setName("iCmd")
|
iBus = master(IBusSimpleBus()).setName("iBus")
|
||||||
iCmd.valid := prefetch.arbitration.isFiring //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
|
||||||
iCmd.pc := prefetch.output(PC)
|
|
||||||
prefetch.arbitration.haltIt setWhen(!iCmd.ready)
|
|
||||||
|
|
||||||
//Insert iRsp into INSTRUCTION
|
//Emit iBus.cmd request
|
||||||
iRsp = in(IBusSimpleRsp()).setName("iRsp")
|
iBus.cmd.valid := prefetch.arbitration.isFiring //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||||
fetch.insert(INSTRUCTION) := iRsp.inst
|
iBus.cmd.pc := prefetch.output(PC)
|
||||||
fetch.insert(IBUS_ACCESS_ERROR) := iRsp.error
|
prefetch.arbitration.haltIt setWhen(!iBus.cmd.ready)
|
||||||
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){
|
if(catchAccessFault){
|
||||||
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||||
|
|
|
@ -79,22 +79,22 @@ object TopLevel {
|
||||||
|
|
||||||
config.plugins ++= List(
|
config.plugins ++= List(
|
||||||
new PcManagerSimplePlugin(0x00000000l, false),
|
new PcManagerSimplePlugin(0x00000000l, false),
|
||||||
// new IBusSimplePlugin(
|
new IBusSimplePlugin(
|
||||||
// interfaceKeepData = true,
|
interfaceKeepData = true,
|
||||||
// catchAccessFault = true
|
catchAccessFault = true
|
||||||
// ),
|
|
||||||
new IBusCachedPlugin(
|
|
||||||
config = InstructionCacheConfig(
|
|
||||||
cacheSize =4096,
|
|
||||||
bytePerLine =32,
|
|
||||||
wayCount = 1,
|
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
|
||||||
cpuDataWidth = 32,
|
|
||||||
memDataWidth = 32,
|
|
||||||
catchAccessFault = true
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
|
// new IBusCachedPlugin(
|
||||||
|
// config = InstructionCacheConfig(
|
||||||
|
// cacheSize =4096,
|
||||||
|
// bytePerLine =32,
|
||||||
|
// wayCount = 1,
|
||||||
|
// wrappedMemAccess = true,
|
||||||
|
// addressWidth = 32,
|
||||||
|
// cpuDataWidth = 32,
|
||||||
|
// memDataWidth = 32,
|
||||||
|
// catchAccessFault = true
|
||||||
|
// )
|
||||||
|
// ),
|
||||||
new DecoderSimplePlugin(
|
new DecoderSimplePlugin(
|
||||||
catchIllegalInstruction = true
|
catchIllegalInstruction = true
|
||||||
),
|
),
|
||||||
|
|
|
@ -141,8 +141,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Workspace;
|
|
||||||
void fillSimELements(Workspace *ws);
|
|
||||||
|
|
||||||
class Workspace{
|
class Workspace{
|
||||||
public:
|
public:
|
||||||
|
@ -150,6 +149,8 @@ public:
|
||||||
vector<SimElement*> simElements;
|
vector<SimElement*> simElements;
|
||||||
Memory mem;
|
Memory mem;
|
||||||
string name;
|
string name;
|
||||||
|
uint64_t mTimeCmp = 0;
|
||||||
|
uint64_t mTime = 0;
|
||||||
VVexRiscv* top;
|
VVexRiscv* top;
|
||||||
int i;
|
int i;
|
||||||
uint32_t bootPc = -1;
|
uint32_t bootPc = -1;
|
||||||
|
@ -173,7 +174,7 @@ public:
|
||||||
regTraces.open (name + ".regTrace");
|
regTraces.open (name + ".regTrace");
|
||||||
memTraces.open (name + ".memTrace");
|
memTraces.open (name + ".memTrace");
|
||||||
logTraces.open (name + ".logTrace");
|
logTraces.open (name + ".logTrace");
|
||||||
fillSimELements(this);
|
fillSimELements();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Workspace(){
|
virtual ~Workspace(){
|
||||||
|
@ -190,7 +191,7 @@ public:
|
||||||
|
|
||||||
Workspace* bootAt(uint32_t pc) { bootPc = pc;}
|
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) {
|
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) {
|
||||||
assert(addr % 4 == 0);
|
assert(addr % 4 == 0);
|
||||||
*data = ( (mem[addr + 0] << 0)
|
*data = ( (mem[addr + 0] << 0)
|
||||||
|
@ -199,10 +200,66 @@ public:
|
||||||
| (mem[addr + 3] << 24));
|
| (mem[addr + 3] << 24));
|
||||||
*error = addr == 0xF00FFF60u;
|
*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 postReset() {}
|
||||||
virtual void checks(){}
|
virtual void checks(){}
|
||||||
virtual void pass(){ throw success();}
|
virtual void pass(){ throw success();}
|
||||||
virtual void fail(){ throw std::exception();}
|
virtual void fail(){ throw std::exception();}
|
||||||
|
virtual void fillSimELements();
|
||||||
void dump(int i){
|
void dump(int i){
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
if(i/2 >= TRACE_START) tfp->dump(i);
|
if(i/2 >= TRACE_START) tfp->dump(i);
|
||||||
|
@ -210,8 +267,7 @@ public:
|
||||||
}
|
}
|
||||||
Workspace* run(uint32_t timeout = 5000){
|
Workspace* run(uint32_t timeout = 5000){
|
||||||
// cout << "Start " << name << endl;
|
// cout << "Start " << name << endl;
|
||||||
uint64_t mTimeCmp = 0;
|
|
||||||
uint64_t mTime = 0;
|
|
||||||
currentTime = 4;
|
currentTime = 4;
|
||||||
// init trace dump
|
// init trace dump
|
||||||
Verilated::traceEverOn(true);
|
Verilated::traceEverOn(true);
|
||||||
|
@ -224,8 +280,6 @@ public:
|
||||||
// Reset
|
// Reset
|
||||||
top->clk = 0;
|
top->clk = 0;
|
||||||
top->reset = 0;
|
top->reset = 0;
|
||||||
top->dCmd_ready = 1;
|
|
||||||
top->dRsp_ready = 1;
|
|
||||||
|
|
||||||
for(SimElement* simElement : simElements) simElement->onReset();
|
for(SimElement* simElement : simElements) simElement->onReset();
|
||||||
|
|
||||||
|
@ -251,9 +305,6 @@ public:
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// run simulation for 100 clock periods
|
// 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) {
|
for (i = 16; i < timeout*2; i+=2) {
|
||||||
mTime = i/2;
|
mTime = i/2;
|
||||||
#ifdef CSR
|
#ifdef CSR
|
||||||
|
@ -275,63 +326,6 @@ public:
|
||||||
dump(i + 1);
|
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){
|
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
|
||||||
regTraces <<
|
regTraces <<
|
||||||
|
@ -358,17 +352,6 @@ public:
|
||||||
|
|
||||||
for(SimElement* simElement : simElements) simElement->postCycle();
|
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())
|
if (Verilated::gotFinish())
|
||||||
|
@ -411,27 +394,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void onReset(){
|
virtual void onReset(){
|
||||||
top->iCmd_ready = 1;
|
top->iBus_cmd_ready = 1;
|
||||||
top->iRsp_ready = 1;
|
top->iBus_rsp_ready = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void preCycle(){
|
virtual void preCycle(){
|
||||||
if (top->iCmd_valid && top->iCmd_ready && !pending) {
|
if (top->iBus_cmd_valid && top->iBus_cmd_ready && !pending) {
|
||||||
assertEq(top->iCmd_payload_pc & 3,0);
|
assertEq(top->iBus_cmd_payload_pc & 3,0);
|
||||||
pending = true;
|
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(){
|
virtual void postCycle(){
|
||||||
top->iRsp_ready = !pending;
|
top->iBus_rsp_ready = !pending;
|
||||||
if(pending && (!ws->iStall || VL_RANDOM_I(8) < 100)){
|
if(pending && (!ws->iStall || VL_RANDOM_I(7) < 100)){
|
||||||
top->iRsp_inst = inst_next;
|
top->iBus_rsp_inst = inst_next;
|
||||||
pending = false;
|
pending = false;
|
||||||
top->iRsp_ready = 1;
|
top->iBus_rsp_ready = 1;
|
||||||
top->iRsp_error = error_next;
|
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
|
#endif
|
||||||
|
@ -469,25 +452,72 @@ public:
|
||||||
virtual void postCycle(){
|
virtual void postCycle(){
|
||||||
bool error;
|
bool error;
|
||||||
top->iBus_rsp_valid = 0;
|
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);
|
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error);
|
||||||
top->iBus_rsp_payload_error = error;
|
top->iBus_rsp_payload_error = error;
|
||||||
pendingCount--;
|
pendingCount--;
|
||||||
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
||||||
top->iBus_rsp_valid = 1;
|
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
|
#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
|
#ifdef IBUS_SIMPLE
|
||||||
ws->simElements.push_back(new IBusSimple(ws));
|
simElements.push_back(new IBusSimple(this));
|
||||||
#endif
|
#endif
|
||||||
#ifdef IBUS_CACHED
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
IBUS=IBUS_CACHED
|
IBUS=IBUS_SIMPLE
|
||||||
DBUS=DBUS_SIMPLE
|
DBUS=DBUS_SIMPLE
|
||||||
TRACE=no
|
TRACE=no
|
||||||
TRACE_START=0
|
TRACE_START=0
|
||||||
|
|
Loading…
Reference in New Issue