Added MMU support into cacheless DBus IBus plugins (for testing purposes)
Probably full of bugs, need testing
This commit is contained in:
parent
ffa489d211
commit
c490838202
|
@ -684,11 +684,11 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
when(io.cpu.writeBack.isValid) {
|
when(io.cpu.writeBack.isValid) {
|
||||||
if (catchMemoryTranslationMiss) {
|
if (catchMemoryTranslationMiss) {
|
||||||
io.cpu.writeBack.mmuMiss := mmuRsp.miss
|
io.cpu.writeBack.mmuMiss := ??? //TODO mmuRsp.miss
|
||||||
}
|
}
|
||||||
switch(request.kind) {
|
switch(request.kind) {
|
||||||
is(MANAGMENT) {
|
is(MANAGMENT) {
|
||||||
when(delayedIsStuck && !mmuRsp.miss) {
|
when(delayedIsStuck && ???){ //TODO!mmuRsp.miss) {
|
||||||
when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) {
|
when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) {
|
||||||
io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready))
|
io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready))
|
||||||
victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty
|
victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty
|
||||||
|
@ -708,7 +708,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False
|
val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False
|
||||||
io.cpu.writeBack.illegalAccess := illegal
|
io.cpu.writeBack.illegalAccess := illegal
|
||||||
io.cpu.writeBack.unalignedAccess := unaligned
|
io.cpu.writeBack.unalignedAccess := unaligned
|
||||||
when((Bool(!catchMemoryTranslationMiss) || !mmuRsp.miss) && !illegal && !unaligned) {
|
when((Bool(!catchMemoryTranslationMiss) || ???) && !illegal && !unaligned) { //TODO !mmuRsp.miss
|
||||||
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
|
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
|
||||||
val memCmdSent = RegInit(False)
|
val memCmdSent = RegInit(False)
|
||||||
when(!victim.request.valid) {
|
when(!victim.request.valid) {
|
||||||
|
|
|
@ -411,7 +411,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
|
|
||||||
io.cpu.fetch.cacheMiss := !hit.valid
|
io.cpu.fetch.cacheMiss := !hit.valid
|
||||||
io.cpu.fetch.error := hit.error
|
io.cpu.fetch.error := hit.error
|
||||||
io.cpu.fetch.mmuMiss := mmuRsp.miss
|
io.cpu.fetch.mmuMiss := ??? //TODO mmuRsp.miss
|
||||||
io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser)
|
io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -441,7 +441,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
|
|
||||||
io.cpu.decode.cacheMiss := !hit.valid
|
io.cpu.decode.cacheMiss := !hit.valid
|
||||||
io.cpu.decode.error := hit.error
|
io.cpu.decode.error := hit.error
|
||||||
io.cpu.decode.mmuMiss := mmuRsp.miss
|
io.cpu.decode.mmuMiss := ??? //TODO mmuRsp.miss
|
||||||
io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser)
|
io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser)
|
||||||
io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
|
io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
|
||||||
})
|
})
|
||||||
|
|
|
@ -173,7 +173,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt)
|
arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt)
|
||||||
|
|
||||||
cache.io.cpu.memory.mmuBus <> mmuBus
|
cache.io.cpu.memory.mmuBus <> mmuBus
|
||||||
arbitration.haltItself setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
|
arbitration.haltItself setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBack plug new Area{
|
writeBack plug new Area{
|
||||||
|
|
|
@ -9,6 +9,8 @@ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||||
import spinal.lib.bus.simple._
|
import spinal.lib.bus.simple._
|
||||||
import vexriscv.ip.DataCacheMemCmd
|
import vexriscv.ip.DataCacheMemCmd
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
|
||||||
case class DBusSimpleCmd() extends Bundle{
|
case class DBusSimpleCmd() extends Bundle{
|
||||||
val wr = Bool
|
val wr = Bool
|
||||||
|
@ -202,7 +204,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
catchAccessFault : Boolean = false,
|
catchAccessFault : Boolean = false,
|
||||||
earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/
|
earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/
|
||||||
emitCmdInMemoryStage : Boolean = false,
|
emitCmdInMemoryStage : Boolean = false,
|
||||||
onlyLoadWords : Boolean = false) extends Plugin[VexRiscv]{
|
onlyLoadWords : Boolean = false,
|
||||||
|
memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService {
|
||||||
|
|
||||||
var dBus : DBusSimpleBus = null
|
var dBus : DBusSimpleBus = null
|
||||||
assert(!(emitCmdInMemoryStage && earlyInjection))
|
assert(!(emitCmdInMemoryStage && earlyInjection))
|
||||||
|
@ -211,9 +214,20 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
object MEMORY_READ_DATA extends Stageable(Bits(32 bits))
|
object MEMORY_READ_DATA extends Stageable(Bits(32 bits))
|
||||||
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
|
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
|
||||||
object ALIGNEMENT_FAULT extends Stageable(Bool)
|
object ALIGNEMENT_FAULT extends Stageable(Bool)
|
||||||
|
object MMU_RSP extends Stageable(MemoryTranslatorRsp())
|
||||||
|
|
||||||
var memoryExceptionPort : Flow[ExceptionCause] = null
|
var memoryExceptionPort : Flow[ExceptionCause] = null
|
||||||
var rspStage : Stage = null
|
var rspStage : Stage = null
|
||||||
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
|
var redoBranch : Flow[UInt] = null
|
||||||
|
val catchSomething = catchAccessFault || catchAddressMisaligned || memoryTranslatorPortConfig != null
|
||||||
|
|
||||||
|
var dBusAccess : DBusAccess = null
|
||||||
|
override def newDBusAccess(): DBusAccess = {
|
||||||
|
assert(dBusAccess == null)
|
||||||
|
dBusAccess = DBusAccess()
|
||||||
|
dBusAccess
|
||||||
|
}
|
||||||
|
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
import Riscv._
|
import Riscv._
|
||||||
|
@ -250,10 +264,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
|
|
||||||
|
|
||||||
rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory)
|
rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory)
|
||||||
if(catchAccessFault || catchAddressMisaligned) {
|
if(catchSomething) {
|
||||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||||
memoryExceptionPort = exceptionService.newExceptionPort(rspStage)
|
memoryExceptionPort = exceptionService.newExceptionPort(rspStage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(memoryTranslatorPortConfig != null) {
|
||||||
|
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig)
|
||||||
|
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.memory)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
|
@ -262,7 +281,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
|
|
||||||
dBus = master(DBusSimpleBus()).setName("dBus")
|
dBus = master(DBusSimpleBus()).setName("dBus")
|
||||||
|
|
||||||
|
|
||||||
//Emit dBus.cmd request
|
//Emit dBus.cmd request
|
||||||
val cmdStage = if(emitCmdInMemoryStage) memory else execute
|
val cmdStage = if(emitCmdInMemoryStage) memory else execute
|
||||||
cmdStage plug new Area{
|
cmdStage plug new Area{
|
||||||
|
@ -279,7 +297,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
|
|
||||||
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !input(ALIGNEMENT_FAULT) && !cmdSent
|
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !input(ALIGNEMENT_FAULT) && !cmdSent
|
||||||
dBus.cmd.wr := input(INSTRUCTION)(5)
|
dBus.cmd.wr := input(INSTRUCTION)(5)
|
||||||
dBus.cmd.address := input(SRC_ADD).asUInt
|
|
||||||
dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt
|
||||||
dBus.cmd.payload.data := dBus.cmd.size.mux (
|
dBus.cmd.payload.data := dBus.cmd.size.mux (
|
||||||
U(0) -> input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0),
|
U(0) -> input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0),
|
||||||
|
@ -302,6 +319,25 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000"
|
insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000"
|
||||||
insert(FORMAL_MEM_RMASK) := (dBus.cmd.valid && !dBus.cmd.wr) ? formalMask | B"0000"
|
insert(FORMAL_MEM_RMASK) := (dBus.cmd.valid && !dBus.cmd.wr) ? formalMask | B"0000"
|
||||||
insert(FORMAL_MEM_WDATA) := dBus.cmd.payload.data
|
insert(FORMAL_MEM_WDATA) := dBus.cmd.payload.data
|
||||||
|
|
||||||
|
val mmu = (mmuBus != null) generate new Area {
|
||||||
|
mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||||
|
mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt
|
||||||
|
mmuBus.cmd.bypassTranslation := False
|
||||||
|
dBus.cmd.address := mmuBus.rsp.physicalAddress
|
||||||
|
|
||||||
|
//do not emit memory request if MMU miss
|
||||||
|
when(mmuBus.cmd.isValid && (mmuBus.rsp.exception || mmuBus.rsp.refilling)){
|
||||||
|
dBus.cmd.valid := False
|
||||||
|
arbitration.haltItself := False
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(MMU_RSP) := mmuBus.rsp
|
||||||
|
}
|
||||||
|
|
||||||
|
val mmuLess = (mmuBus == null) generate new Area{
|
||||||
|
dBus.cmd.address := input(SRC_ADD).asUInt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Collect dBus.rsp read responses
|
//Collect dBus.rsp read responses
|
||||||
|
@ -312,26 +348,38 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
insert(MEMORY_READ_DATA) := dBus.rsp.data
|
insert(MEMORY_READ_DATA) := dBus.rsp.data
|
||||||
arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && !dBus.rsp.ready)
|
arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && !dBus.rsp.ready)
|
||||||
|
|
||||||
if(catchAccessFault || catchAddressMisaligned){
|
if(catchSomething) {
|
||||||
if(!catchAccessFault){
|
memoryExceptionPort.valid := False
|
||||||
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
|
memoryExceptionPort.code.assignDontCare()
|
||||||
memoryExceptionPort.valid := input(ALIGNEMENT_FAULT)
|
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt
|
||||||
} else if(!catchAddressMisaligned){
|
|
||||||
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
|
if(catchAccessFault) when(dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)) {
|
||||||
memoryExceptionPort.code := 5
|
memoryExceptionPort.valid := True
|
||||||
} else {
|
memoryExceptionPort.code := 5
|
||||||
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
|
|
||||||
memoryExceptionPort.code := 5
|
|
||||||
when(input(ALIGNEMENT_FAULT)){
|
|
||||||
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
|
|
||||||
memoryExceptionPort.valid := True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
when(!(arbitration.isValid && input(MEMORY_ENABLE) && (if(cmdStage == rspStage) !arbitration.isStuckByOthers else True))){
|
|
||||||
memoryExceptionPort.valid := False
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt //Drived by IntAluPlugin
|
if(catchAddressMisaligned) when(input(ALIGNEMENT_FAULT)){
|
||||||
|
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
|
||||||
|
memoryExceptionPort.valid := True
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memoryTranslatorPortConfig != null) {
|
||||||
|
redoBranch.valid := False
|
||||||
|
redoBranch.payload := input(PC)
|
||||||
|
|
||||||
|
when(input(MMU_RSP).refilling){
|
||||||
|
redoBranch.valid := True
|
||||||
|
memoryExceptionPort.valid := False
|
||||||
|
} elsewhen(input(MMU_RSP).exception) {
|
||||||
|
memoryExceptionPort.valid := True
|
||||||
|
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(15) | U(13)).resized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){
|
||||||
|
memoryExceptionPort.valid := False
|
||||||
|
redoBranch.valid := False
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -368,5 +416,42 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
||||||
//formal
|
//formal
|
||||||
insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA)
|
insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Share access to the dBus (used by self refilled MMU)
|
||||||
|
val dBusSharing = (dBusAccess != null) generate new Area{
|
||||||
|
val state = Reg(UInt(2 bits)) init(0)
|
||||||
|
dBusAccess.rsp.valid := False
|
||||||
|
dBusAccess.rsp.data := dBus.rsp.data
|
||||||
|
dBusAccess.rsp.error := dBus.rsp.error
|
||||||
|
|
||||||
|
switch(state){
|
||||||
|
is(0){
|
||||||
|
when(dBusAccess.cmd.valid){
|
||||||
|
decode.arbitration.haltItself := True
|
||||||
|
when(!stages.dropWhile(_ != execute).map(_.arbitration.isValid).orR){
|
||||||
|
state := 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is(1){
|
||||||
|
decode.arbitration.haltItself := True
|
||||||
|
dBus.cmd.valid := True
|
||||||
|
dBus.cmd.address := dBusAccess.cmd.address
|
||||||
|
dBus.cmd.wr := dBusAccess.cmd.write
|
||||||
|
dBus.cmd.data := dBusAccess.cmd.data
|
||||||
|
dBus.cmd.size := dBusAccess.cmd.size
|
||||||
|
when(dBus.cmd.ready){
|
||||||
|
state := (dBusAccess.cmd.write ? U(0) | U(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is(2){
|
||||||
|
decode.arbitration.haltItself := True
|
||||||
|
when(dBus.rsp.ready){
|
||||||
|
dBusAccess.rsp.valid := True
|
||||||
|
state := 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,5 +605,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={
|
||||||
|
iBusRsp.stages.dropWhile(_ != stage).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -223,7 +223,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
||||||
|
|
||||||
if (mmuBus != null) {
|
if (mmuBus != null) {
|
||||||
cache.io.cpu.fetch.mmuBus <> mmuBus
|
cache.io.cpu.fetch.mmuBus <> mmuBus
|
||||||
(if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
|
(if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss
|
||||||
} else {
|
} else {
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
|
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
||||||
|
@ -231,8 +231,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
??? //TODO
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.hit := False
|
// cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
||||||
|
// cache.io.cpu.fetch.mmuBus.rsp.hit := False
|
||||||
}
|
}
|
||||||
|
|
||||||
val flushStage = if(memory != null) memory else execute
|
val flushStage = if(memory != null) memory else execute
|
||||||
|
|
|
@ -166,7 +166,8 @@ class IBusSimplePlugin(resetVector : BigInt,
|
||||||
pendingMax : Int = 7,
|
pendingMax : Int = 7,
|
||||||
injectorStage : Boolean = true,
|
injectorStage : Boolean = true,
|
||||||
rspHoldValue : Boolean = false,
|
rspHoldValue : Boolean = false,
|
||||||
singleInstructionPipeline : Boolean = false
|
singleInstructionPipeline : Boolean = false,
|
||||||
|
memoryTranslatorPortConfig : Any = null
|
||||||
) extends IBusFetcherImpl(
|
) extends IBusFetcherImpl(
|
||||||
resetVector = resetVector,
|
resetVector = resetVector,
|
||||||
keepPcPlus4 = keepPcPlus4,
|
keepPcPlus4 = keepPcPlus4,
|
||||||
|
@ -181,15 +182,23 @@ class IBusSimplePlugin(resetVector : BigInt,
|
||||||
|
|
||||||
var iBus : IBusSimpleBus = null
|
var iBus : IBusSimpleBus = null
|
||||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||||
|
val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault
|
||||||
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
|
var redoBranch : Flow[UInt] = null
|
||||||
|
|
||||||
if(rspHoldValue) assert(busLatencyMin <= 1)
|
if(rspHoldValue) assert(busLatencyMin <= 1)
|
||||||
|
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
super.setup(pipeline)
|
super.setup(pipeline)
|
||||||
iBus = master(IBusSimpleBus(false)).setName("iBus")
|
iBus = master(IBusSimpleBus(false)).setName("iBus")
|
||||||
|
|
||||||
if(catchAccessFault) {
|
if(catchSomething) {
|
||||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
decodeExceptionPort = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.decode,1)
|
||||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
}
|
||||||
|
|
||||||
|
if(memoryTranslatorPortConfig != null) {
|
||||||
|
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig)
|
||||||
|
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,9 +215,12 @@ class IBusSimplePlugin(resetVector : BigInt,
|
||||||
val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt
|
val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt
|
||||||
pendingCmd := pendingCmdNext
|
pendingCmd := pendingCmdNext
|
||||||
|
|
||||||
|
def cmdForkStage = if(!cmdForkPersistence || !cmdForkOnSecondStage) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1)
|
||||||
|
|
||||||
|
|
||||||
val cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area {
|
val cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area {
|
||||||
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
|
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
|
||||||
def stage = iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0)
|
def stage = cmdForkStage
|
||||||
stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready))
|
stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready))
|
||||||
if(singleInstructionPipeline) {
|
if(singleInstructionPipeline) {
|
||||||
cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR
|
cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR
|
||||||
|
@ -217,16 +229,33 @@ class IBusSimplePlugin(resetVector : BigInt,
|
||||||
}else {
|
}else {
|
||||||
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
|
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
|
||||||
}
|
}
|
||||||
cmd.pc := stage.input.payload(31 downto 2) @@ "00"
|
|
||||||
} else new Area{
|
} else new Area{
|
||||||
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
|
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
|
||||||
def stage = iBusRsp.stages(1)
|
def stage = cmdForkStage
|
||||||
val pendingFull = pendingCmd === pendingMax
|
val pendingFull = pendingCmd === pendingMax
|
||||||
val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready)
|
val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready)
|
||||||
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
|
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
|
||||||
stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired))
|
stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired))
|
||||||
cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired
|
cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired
|
||||||
cmd.pc := stage.input.payload(31 downto 2) @@ "00"
|
}
|
||||||
|
|
||||||
|
val mmu = (mmuBus != null) generate new Area {
|
||||||
|
mmuBus.cmd.isValid := cmdForkStage.input.valid
|
||||||
|
mmuBus.cmd.virtualAddress := cmdForkStage.input.payload
|
||||||
|
mmuBus.cmd.bypassTranslation := False
|
||||||
|
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00"
|
||||||
|
|
||||||
|
//do not emit memory request if MMU miss
|
||||||
|
when(mmuBus.rsp.exception || mmuBus.rsp.refilling){
|
||||||
|
cmdForkStage.halt := False
|
||||||
|
cmd.valid := False
|
||||||
|
}
|
||||||
|
|
||||||
|
val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mmuLess = (mmuBus == null) generate new Area{
|
||||||
|
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00"
|
||||||
}
|
}
|
||||||
|
|
||||||
val rspJoin = new Area {
|
val rspJoin = new Area {
|
||||||
|
@ -261,22 +290,35 @@ class IBusSimplePlugin(resetVector : BigInt,
|
||||||
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
|
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
|
||||||
|
|
||||||
|
|
||||||
var issueDetected = False
|
|
||||||
val join = Stream(FetchRsp())
|
val join = Stream(FetchRsp())
|
||||||
|
val exceptionDetected = False
|
||||||
|
val redoRequired = False
|
||||||
join.valid := stages.last.output.valid && rspBufferOutput.valid
|
join.valid := stages.last.output.valid && rspBufferOutput.valid
|
||||||
join.payload := fetchRsp
|
join.payload := fetchRsp
|
||||||
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
|
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
|
||||||
rspBufferOutput.ready := join.fire
|
rspBufferOutput.ready := join.fire
|
||||||
output << join.haltWhen(issueDetected)
|
output << join.haltWhen(exceptionDetected || redoRequired)
|
||||||
|
|
||||||
if(catchAccessFault){
|
if(memoryTranslatorPortConfig != null){
|
||||||
|
redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling)
|
||||||
|
redoBranch.valid := redoRequired && iBusRsp.readyForError
|
||||||
|
redoBranch.payload := stages.last.input.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
if(catchSomething){
|
||||||
decodeExceptionPort.valid := False
|
decodeExceptionPort.valid := False
|
||||||
decodeExceptionPort.code := 1
|
decodeExceptionPort.code.assignDontCare()
|
||||||
decodeExceptionPort.badAddr := join.pc
|
decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ?
|
||||||
when(join.valid && join.rsp.error && !issueDetected){
|
|
||||||
issueDetected \= True
|
if(catchAccessFault) when(join.valid && join.rsp.error){
|
||||||
decodeExceptionPort.valid := iBusRsp.readyForError
|
decodeExceptionPort.code := 1
|
||||||
|
exceptionDetected := True
|
||||||
}
|
}
|
||||||
|
if(memoryTranslatorPortConfig != null) when(stages.last.input.valid && mmu.joinCtx.exception){
|
||||||
|
decodeExceptionPort.code := 12
|
||||||
|
exceptionDetected := True
|
||||||
|
}
|
||||||
|
decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,8 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
||||||
port.bus.rsp.allowWrite := cacheLine.allowWrite
|
port.bus.rsp.allowWrite := cacheLine.allowWrite
|
||||||
port.bus.rsp.allowExecute := cacheLine.allowExecute
|
port.bus.rsp.allowExecute := cacheLine.allowExecute
|
||||||
port.bus.rsp.allowUser := cacheLine.allowUser
|
port.bus.rsp.allowUser := cacheLine.allowUser
|
||||||
port.bus.rsp.hit := cacheHit
|
???
|
||||||
|
// port.bus.rsp.hit := cacheHit
|
||||||
// port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss)
|
// port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss)
|
||||||
} otherwise {
|
} otherwise {
|
||||||
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
|
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
|
||||||
|
@ -121,10 +122,12 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
||||||
port.bus.rsp.allowWrite := True
|
port.bus.rsp.allowWrite := True
|
||||||
port.bus.rsp.allowExecute := True
|
port.bus.rsp.allowExecute := True
|
||||||
port.bus.rsp.allowUser := True
|
port.bus.rsp.allowUser := True
|
||||||
port.bus.rsp.hit := True
|
???
|
||||||
|
// port.bus.rsp.hit := True
|
||||||
}
|
}
|
||||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||||
port.bus.rsp.miss := sharedMiss
|
???
|
||||||
|
// port.bus.rsp.miss := sharedMiss
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,15 @@ import spinal.lib._
|
||||||
|
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
trait DBusAccessService{
|
||||||
|
def newDBusAccess() : DBusAccess
|
||||||
|
}
|
||||||
|
|
||||||
case class DBusAccessCmd() extends Bundle {
|
case class DBusAccessCmd() extends Bundle {
|
||||||
val address = UInt(32 bits)
|
val address = UInt(32 bits)
|
||||||
val size = UInt(2 bits)
|
val size = UInt(2 bits)
|
||||||
val write = Bool
|
val write = Bool
|
||||||
val writeData = Bits(32 bits)
|
val data = Bits(32 bits)
|
||||||
val writeMask = Bits(4 bits)
|
val writeMask = Bits(4 bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +60,7 @@ class MmuPlugin(virtualRange : UInt => Bool,
|
||||||
decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True))
|
decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True))
|
||||||
|
|
||||||
|
|
||||||
dBus = ???
|
dBus = pipeline.service(classOf[DBusAccessService]).newDBusAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
|
@ -81,7 +85,7 @@ class MmuPlugin(virtualRange : UInt => Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
val core = pipeline plug new Area {
|
val core = pipeline plug new Area {
|
||||||
val ports = for (port <- sortedPortsInfo yield new Area {
|
val ports = for (port <- sortedPortsInfo) yield new Area {
|
||||||
val id = port.id
|
val id = port.id
|
||||||
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
|
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
|
||||||
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
|
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
|
||||||
|
@ -144,7 +148,7 @@ class MmuPlugin(virtualRange : UInt => Bool,
|
||||||
dBus.cmd.write := False
|
dBus.cmd.write := False
|
||||||
dBus.cmd.size := 2
|
dBus.cmd.size := 2
|
||||||
dBus.cmd.address.assignDontCare()
|
dBus.cmd.address.assignDontCare()
|
||||||
dBus.cmd.writeData.assignDontCare()
|
dBus.cmd.data.assignDontCare()
|
||||||
dBus.cmd.writeMask.assignDontCare()
|
dBus.cmd.writeMask.assignDontCare()
|
||||||
switch(state){
|
switch(state){
|
||||||
is(State.IDLE){
|
is(State.IDLE){
|
||||||
|
|
|
@ -33,8 +33,9 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
|
||||||
port.bus.rsp.allowExecute := True
|
port.bus.rsp.allowExecute := True
|
||||||
port.bus.rsp.allowUser := True
|
port.bus.rsp.allowUser := True
|
||||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||||
port.bus.rsp.miss := False
|
???
|
||||||
port.bus.rsp.hit := True
|
// port.bus.rsp.miss := False
|
||||||
|
// port.bus.rsp.hit := True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue