#60 Got the new data cache design passing all tests and running linux
This commit is contained in:
parent
fd4da77084
commit
8be40e637b
|
@ -33,6 +33,7 @@ case class ExceptionCause() extends Bundle{
|
||||||
|
|
||||||
trait ExceptionService{
|
trait ExceptionService{
|
||||||
def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause]
|
def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause]
|
||||||
|
def isExceptionPending() : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PrivilegeService{
|
trait PrivilegeService{
|
||||||
|
|
|
@ -96,45 +96,45 @@ object LinuxGen {
|
||||||
new DummyFencePlugin(), //TODO should be removed for design with caches
|
new DummyFencePlugin(), //TODO should be removed for design with caches
|
||||||
|
|
||||||
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
|
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
|
||||||
new IBusSimplePlugin(
|
// new IBusSimplePlugin(
|
||||||
resetVector = 0x80000000l,
|
|
||||||
cmdForkOnSecondStage = false,
|
|
||||||
cmdForkPersistence = false,
|
|
||||||
prediction = NONE,
|
|
||||||
historyRamSizeLog2 = 10,
|
|
||||||
catchAccessFault = true,
|
|
||||||
compressedGen = true,
|
|
||||||
busLatencyMin = 1,
|
|
||||||
injectorStage = true,
|
|
||||||
memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
|
|
||||||
portTlbSize = 4
|
|
||||||
)
|
|
||||||
),
|
|
||||||
|
|
||||||
//Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config
|
|
||||||
// new IBusCachedPlugin(
|
|
||||||
// resetVector = 0x80000000l,
|
// resetVector = 0x80000000l,
|
||||||
// compressedGen = true,
|
// cmdForkOnSecondStage = false,
|
||||||
|
// cmdForkPersistence = false,
|
||||||
// prediction = NONE,
|
// prediction = NONE,
|
||||||
// injectorStage = true,
|
// historyRamSizeLog2 = 10,
|
||||||
// config = InstructionCacheConfig(
|
|
||||||
// cacheSize = 4096,
|
|
||||||
// bytePerLine = 32,
|
|
||||||
// wayCount = 1,
|
|
||||||
// addressWidth = 32,
|
|
||||||
// cpuDataWidth = 32,
|
|
||||||
// memDataWidth = 32,
|
|
||||||
// catchIllegalAccess = true,
|
|
||||||
// catchAccessFault = true,
|
// catchAccessFault = true,
|
||||||
// asyncTagMemory = false,
|
// compressedGen = true,
|
||||||
// twoCycleRam = false,
|
// busLatencyMin = 1,
|
||||||
// twoCycleCache = true
|
// injectorStage = true,
|
||||||
// )
|
// memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
|
||||||
// ),
|
|
||||||
// memoryTranslatorPortConfig = MmuPortConfig(
|
|
||||||
// portTlbSize = 4
|
// portTlbSize = 4
|
||||||
// )
|
// )
|
||||||
// ),
|
// ),
|
||||||
|
|
||||||
|
//Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config
|
||||||
|
new IBusCachedPlugin(
|
||||||
|
resetVector = 0x80000000l,
|
||||||
|
compressedGen = true,
|
||||||
|
prediction = NONE,
|
||||||
|
injectorStage = true,
|
||||||
|
config = InstructionCacheConfig(
|
||||||
|
cacheSize = 4096,
|
||||||
|
bytePerLine = 32,
|
||||||
|
wayCount = 1,
|
||||||
|
addressWidth = 32,
|
||||||
|
cpuDataWidth = 32,
|
||||||
|
memDataWidth = 32,
|
||||||
|
catchIllegalAccess = true,
|
||||||
|
catchAccessFault = true,
|
||||||
|
asyncTagMemory = false,
|
||||||
|
twoCycleRam = false,
|
||||||
|
twoCycleCache = true
|
||||||
|
// )
|
||||||
|
),
|
||||||
|
memoryTranslatorPortConfig = MmuPortConfig(
|
||||||
|
portTlbSize = 4
|
||||||
|
)
|
||||||
|
),
|
||||||
// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))),
|
// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))),
|
||||||
// new DBusSimplePlugin(
|
// new DBusSimplePlugin(
|
||||||
// catchAddressMisaligned = true,
|
// catchAddressMisaligned = true,
|
||||||
|
@ -156,17 +156,16 @@ object LinuxGen {
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true,
|
||||||
atomicEntriesCount = 2
|
atomicEntriesCount = 1
|
||||||
)
|
|
||||||
// ),
|
|
||||||
// memoryTranslatorPortConfig = null
|
|
||||||
// memoryTranslatorPortConfig = MmuPortConfig(
|
|
||||||
// portTlbSize = 4
|
|
||||||
// )
|
// )
|
||||||
),
|
),
|
||||||
new StaticMemoryTranslatorPlugin(
|
memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
|
||||||
ioRange = _(31 downto 28) === 0xF
|
portTlbSize = 4
|
||||||
|
)
|
||||||
),
|
),
|
||||||
|
// new StaticMemoryTranslatorPlugin(
|
||||||
|
// ioRange = _(31 downto 28) === 0xF
|
||||||
|
// ),
|
||||||
// new MemoryTranslatorPlugin(
|
// new MemoryTranslatorPlugin(
|
||||||
// tlbSize = 32,
|
// tlbSize = 32,
|
||||||
// virtualRange = _(31 downto 28) === 0xC,
|
// virtualRange = _(31 downto 28) === 0xC,
|
||||||
|
@ -238,12 +237,12 @@ object LinuxGen {
|
||||||
new YamlPlugin("cpu0.yaml")
|
new YamlPlugin("cpu0.yaml")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// if(withMmu) config.plugins += new MmuPlugin(
|
if(withMmu) config.plugins += new MmuPlugin(
|
||||||
// virtualRange = a => True,
|
virtualRange = a => True,
|
||||||
// // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround)
|
// virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround)
|
||||||
// ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF),
|
ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF),
|
||||||
// allowUserIo = true
|
allowUserIo = true
|
||||||
// )
|
)
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||||
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||||
import spinal.lib.bus.simple._
|
import spinal.lib.bus.simple._
|
||||||
|
|
||||||
|
//TODO flush
|
||||||
|
|
||||||
case class DataCacheConfig(cacheSize : Int,
|
case class DataCacheConfig(cacheSize : Int,
|
||||||
bytePerLine : Int,
|
bytePerLine : Int,
|
||||||
wayCount : Int,
|
wayCount : Int,
|
||||||
|
@ -71,13 +73,12 @@ object DataCacheCpuExecute{
|
||||||
|
|
||||||
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val isStuck = Bool
|
|
||||||
val address = UInt(p.addressWidth bit)
|
val address = UInt(p.addressWidth bit)
|
||||||
// val haltIt = Bool
|
// val haltIt = Bool
|
||||||
val args = DataCacheCpuExecuteArgs(p)
|
val args = DataCacheCpuExecuteArgs(p)
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isStuck, args, address)
|
out(isValid, args, address)
|
||||||
// in(haltIt)
|
// in(haltIt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +112,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste
|
||||||
val isStuck = Bool
|
val isStuck = Bool
|
||||||
val isUser = Bool
|
val isUser = Bool
|
||||||
val haltIt = Bool
|
val haltIt = Bool
|
||||||
|
val isWrite = Bool
|
||||||
val data = Bits(p.cpuDataWidth bit)
|
val data = Bits(p.cpuDataWidth bit)
|
||||||
val address = UInt(p.addressWidth bit)
|
val address = UInt(p.addressWidth bit)
|
||||||
val mmuException, unalignedAccess , accessError = Bool
|
val mmuException, unalignedAccess , accessError = Bool
|
||||||
|
@ -120,7 +122,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid,isStuck,isUser, address)
|
out(isValid,isStuck,isUser, address)
|
||||||
in(haltIt, data, mmuException, unalignedAccess, accessError)
|
in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite)
|
||||||
outWithNull(clearAtomicEntries)
|
outWithNull(clearAtomicEntries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,8 +356,8 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val data = Mem(Bits(wordWidth bit), wayWordCount)
|
val data = Mem(Bits(wordWidth bit), wayWordCount)
|
||||||
|
|
||||||
//Reads
|
//Reads
|
||||||
val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.execute.isStuck)
|
val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck)
|
||||||
val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.execute.isStuck)
|
val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck)
|
||||||
|
|
||||||
//Writes
|
//Writes
|
||||||
when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){
|
when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){
|
||||||
|
@ -380,7 +382,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
dataWriteCmd.valid := False
|
dataWriteCmd.valid := False
|
||||||
dataWriteCmd.payload.assignDontCare()
|
dataWriteCmd.payload.assignDontCare()
|
||||||
|
|
||||||
when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){
|
when(io.cpu.execute.isValid && !io.cpu.memory.isStuck){
|
||||||
tagsReadCmd.valid := True
|
tagsReadCmd.valid := True
|
||||||
dataReadCmd.valid := True
|
dataReadCmd.valid := True
|
||||||
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
|
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
|
||||||
|
@ -460,7 +462,6 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val atomic = genAtomic generate new Area{
|
val atomic = genAtomic generate new Area{
|
||||||
case class AtomicEntry() extends Bundle{
|
case class AtomicEntry() extends Bundle{
|
||||||
val valid = Bool()
|
val valid = Bool()
|
||||||
val size = UInt(2 bits)
|
|
||||||
val address = UInt(addressWidth bits)
|
val address = UInt(addressWidth bits)
|
||||||
|
|
||||||
def init: this.type ={
|
def init: this.type ={
|
||||||
|
@ -470,10 +471,9 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
}
|
}
|
||||||
val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount)
|
val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount)
|
||||||
val entriesAllocCounter = Counter(atomicEntriesCount)
|
val entriesAllocCounter = Counter(atomicEntriesCount)
|
||||||
val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === io.cpu.writeBack.address).orR
|
val entriesHit = entries.map(e => e.valid && e.address === io.cpu.writeBack.address).orR
|
||||||
when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){
|
when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){
|
||||||
entries(entriesAllocCounter).valid := True
|
entries(entriesAllocCounter).valid := True
|
||||||
entries(entriesAllocCounter).size := request.size //TODO remove size stuff
|
|
||||||
entries(entriesAllocCounter).address := io.cpu.writeBack.address
|
entries(entriesAllocCounter).address := io.cpu.writeBack.address
|
||||||
when(!io.cpu.writeBack.isStuck){
|
when(!io.cpu.writeBack.isStuck){
|
||||||
entriesAllocCounter.increment()
|
entriesAllocCounter.increment()
|
||||||
|
@ -486,11 +486,11 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck)
|
val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck)
|
||||||
|
|
||||||
io.cpu.redo := mmuRsp.refilling
|
io.cpu.redo := False
|
||||||
io.cpu.writeBack.accessError := False
|
io.cpu.writeBack.accessError := False
|
||||||
io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False)
|
io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False)
|
||||||
io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (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.unalignedAccess := io.cpu.writeBack.isValid && (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.isWrite := request.wr
|
||||||
|
|
||||||
when(io.cpu.writeBack.isValid) {
|
when(io.cpu.writeBack.isValid) {
|
||||||
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
|
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
|
||||||
|
@ -503,6 +503,11 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
io.mem.cmd.data := request.data
|
io.mem.cmd.data := request.data
|
||||||
io.mem.cmd.length := 0
|
io.mem.cmd.length := 0
|
||||||
io.mem.cmd.last := True
|
io.mem.cmd.last := True
|
||||||
|
|
||||||
|
if(genAtomic) when(request.isAtomic && !atomic.entriesHit){
|
||||||
|
io.mem.cmd.valid := False
|
||||||
|
io.cpu.writeBack.haltIt := False
|
||||||
|
}
|
||||||
} otherwise {
|
} otherwise {
|
||||||
when(waysHit || request.wr) { //Do not require a cache refill ?
|
when(waysHit || request.wr) { //Do not require a cache refill ?
|
||||||
//Data cache update
|
//Data cache update
|
||||||
|
@ -524,6 +529,12 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
//On write to read colisions
|
//On write to read colisions
|
||||||
io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0
|
io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0
|
||||||
|
|
||||||
|
if(genAtomic) when(request.isAtomic && !atomic.entriesHit){
|
||||||
|
io.mem.cmd.valid := False
|
||||||
|
dataWriteCmd.valid := False
|
||||||
|
io.cpu.writeBack.haltIt := False
|
||||||
|
}
|
||||||
} otherwise { //Do refill
|
} otherwise { //Do refill
|
||||||
|
|
||||||
//Emit cmd
|
//Emit cmd
|
||||||
|
@ -554,6 +565,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
loaderValid := False
|
loaderValid := False
|
||||||
io.cpu.writeBack.haltIt := False
|
io.cpu.writeBack.haltIt := False
|
||||||
}
|
}
|
||||||
|
io.cpu.redo setWhen(io.cpu.writeBack.isValid && mmuRsp.refilling)
|
||||||
|
|
||||||
assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed")
|
assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed")
|
||||||
|
|
||||||
|
@ -561,9 +573,6 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
when(request.isAtomic && request.wr){
|
when(request.isAtomic && request.wr){
|
||||||
io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized
|
io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized
|
||||||
}
|
}
|
||||||
when(request.isAtomic && !atomic.entriesHit){
|
|
||||||
io.mem.cmd.mask := 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,6 +285,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
|
||||||
interface
|
interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exceptionPending : Bool = null
|
||||||
|
override def isExceptionPending(): Bool = exceptionPending
|
||||||
|
|
||||||
var jumpInterface : Flow[UInt] = null
|
var jumpInterface : Flow[UInt] = null
|
||||||
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
|
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
|
||||||
var externalInterruptS : Bool = null
|
var externalInterruptS : Bool = null
|
||||||
|
@ -378,7 +381,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
|
||||||
jumpInterface.valid := False
|
jumpInterface.valid := False
|
||||||
jumpInterface.payload.assignDontCare()
|
jumpInterface.payload.assignDontCare()
|
||||||
|
|
||||||
|
exceptionPending = False
|
||||||
timerInterrupt = in Bool() setName("timerInterrupt")
|
timerInterrupt = in Bool() setName("timerInterrupt")
|
||||||
externalInterrupt = in Bool() setName("externalInterrupt")
|
externalInterrupt = in Bool() setName("externalInterrupt")
|
||||||
softwareInterrupt = in Bool() setName("softwareInterrupt")
|
softwareInterrupt = in Bool() setName("softwareInterrupt")
|
||||||
|
@ -677,7 +680,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
|
||||||
else
|
else
|
||||||
exceptionValidsRegs(stageId) := False
|
exceptionValidsRegs(stageId) := False
|
||||||
}
|
}
|
||||||
if(stage != stages.last) when(stage.arbitration.isFlushed){
|
when(stage.arbitration.isFlushed){
|
||||||
exceptionValids(stageId) := False
|
exceptionValids(stageId) := False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -688,6 +691,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
|
||||||
|
|
||||||
//Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc)
|
//Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc)
|
||||||
stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last
|
stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last
|
||||||
|
exceptionPending setWhen(exceptionValidsRegs.orR)
|
||||||
} else null
|
} else null
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An
|
||||||
|
|
||||||
class DBusCachedPlugin(config : DataCacheConfig,
|
class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
memoryTranslatorPortConfig : Any = null,
|
memoryTranslatorPortConfig : Any = null,
|
||||||
csrInfo : Boolean = false) extends Plugin[VexRiscv]{
|
csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService {
|
||||||
import config._
|
import config._
|
||||||
var dBus : DataCacheMemBus = null
|
var dBus : DataCacheMemBus = null
|
||||||
var mmuBus : MemoryTranslatorBus = null
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
|
@ -28,11 +28,19 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
var privilegeService : PrivilegeService = null
|
var privilegeService : PrivilegeService = null
|
||||||
var redoBranch : Flow[UInt] = null
|
var redoBranch : Flow[UInt] = null
|
||||||
|
|
||||||
|
@dontName var dBusAccess : DBusAccess = null
|
||||||
|
override def newDBusAccess(): DBusAccess = {
|
||||||
|
assert(dBusAccess == null)
|
||||||
|
dBusAccess = DBusAccess()
|
||||||
|
dBusAccess
|
||||||
|
}
|
||||||
|
|
||||||
object MEMORY_ENABLE extends Stageable(Bool)
|
object MEMORY_ENABLE extends Stageable(Bool)
|
||||||
object MEMORY_MANAGMENT extends Stageable(Bool)
|
object MEMORY_MANAGMENT extends Stageable(Bool)
|
||||||
object MEMORY_WR extends Stageable(Bool)
|
object MEMORY_WR extends Stageable(Bool)
|
||||||
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
|
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
|
||||||
object MEMORY_ATOMIC extends Stageable(Bool)
|
object MEMORY_ATOMIC extends Stageable(Bool)
|
||||||
|
object IS_DBUS_SHARING extends Stageable(Bool())
|
||||||
|
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
import Riscv._
|
import Riscv._
|
||||||
|
@ -44,8 +52,9 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||||
SRC_USE_SUB_LESS -> False,
|
SRC_USE_SUB_LESS -> False,
|
||||||
MEMORY_ENABLE -> True,
|
MEMORY_ENABLE -> True,
|
||||||
RS1_USE -> True
|
RS1_USE -> True,
|
||||||
) ++ (if (catchSomething) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage
|
IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB
|
||||||
|
)
|
||||||
|
|
||||||
val loadActions = stdActions ++ List(
|
val loadActions = stdActions ++ List(
|
||||||
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
||||||
|
@ -143,7 +152,6 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
|
|
||||||
val size = input(INSTRUCTION)(13 downto 12).asUInt
|
val size = input(INSTRUCTION)(13 downto 12).asUInt
|
||||||
cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||||
cache.io.cpu.execute.isStuck := arbitration.isStuck
|
|
||||||
cache.io.cpu.execute.address := input(SRC_ADD).asUInt
|
cache.io.cpu.execute.address := input(SRC_ADD).asUInt
|
||||||
cache.io.cpu.execute.args.wr := input(MEMORY_WR)
|
cache.io.cpu.execute.args.wr := input(MEMORY_WR)
|
||||||
cache.io.cpu.execute.args.data := size.mux(
|
cache.io.cpu.execute.args.data := size.mux(
|
||||||
|
@ -194,7 +202,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
redoBranch.payload := input(PC)
|
redoBranch.payload := input(PC)
|
||||||
arbitration.flushAll setWhen(redoBranch.valid)
|
arbitration.flushAll setWhen(redoBranch.valid)
|
||||||
|
|
||||||
when(cache.io.cpu.writeBack.isValid) {
|
when(arbitration.isValid && input(MEMORY_ENABLE)) {
|
||||||
if (catchAccessError) when(cache.io.cpu.writeBack.accessError) {
|
if (catchAccessError) when(cache.io.cpu.writeBack.accessError) {
|
||||||
exceptionBus.valid := True
|
exceptionBus.valid := True
|
||||||
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized
|
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized
|
||||||
|
@ -235,6 +243,45 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Share access to the dBus (used by self refilled MMU)
|
||||||
|
val dBusSharing = (dBusAccess != null) generate pipeline plug new Area{
|
||||||
|
dBusAccess.cmd.ready := False
|
||||||
|
val forceDatapath = False
|
||||||
|
when(dBusAccess.cmd.valid){
|
||||||
|
decode.arbitration.haltByOther := True
|
||||||
|
when(!stagesFromExecute.map(_.arbitration.isValid).orR && !pipeline.service(classOf[ExceptionService]).isExceptionPending()){
|
||||||
|
when(!cache.io.cpu.redo) {
|
||||||
|
cache.io.cpu.execute.isValid := True
|
||||||
|
dBusAccess.cmd.ready := !execute.arbitration.isStuck
|
||||||
|
}
|
||||||
|
cache.io.cpu.execute.args.wr := dBusAccess.cmd.write
|
||||||
|
cache.io.cpu.execute.args.data := dBusAccess.cmd.data
|
||||||
|
cache.io.cpu.execute.args.size := dBusAccess.cmd.size
|
||||||
|
cache.io.cpu.execute.args.forceUncachedAccess := True //TODO Cached and redo management
|
||||||
|
if(genAtomic) cache.io.cpu.execute.args.isAtomic := False
|
||||||
|
cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes
|
||||||
|
forceDatapath := True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire
|
||||||
|
|
||||||
|
|
||||||
|
mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING))
|
||||||
|
cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING))
|
||||||
|
cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING))
|
||||||
|
dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && !cache.io.cpu.writeBack.haltIt
|
||||||
|
dBusAccess.rsp.data := cache.io.cpu.writeBack.data
|
||||||
|
dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError
|
||||||
|
|
||||||
|
component.addPrePopTask{() =>
|
||||||
|
when(forceDatapath){
|
||||||
|
execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits
|
||||||
|
}
|
||||||
|
memory.input(IS_DBUS_SHARING) init(False)
|
||||||
|
writeBack.input(IS_DBUS_SHARING) init(False)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(csrInfo){
|
if(csrInfo){
|
||||||
val csr = service(classOf[CsrPlugin])
|
val csr = service(classOf[CsrPlugin])
|
||||||
csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine))
|
csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine))
|
||||||
|
|
|
@ -21,6 +21,8 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService {
|
||||||
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
|
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
|
||||||
interface
|
interface
|
||||||
}
|
}
|
||||||
|
override def isExceptionPending(): Bool = False
|
||||||
|
|
||||||
|
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
import pipeline._
|
import pipeline._
|
||||||
|
|
|
@ -1316,6 +1316,16 @@ public:
|
||||||
if(isDBusCheckedRegion(addr)){
|
if(isDBusCheckedRegion(addr)){
|
||||||
CpuRef::MemWrite w;
|
CpuRef::MemWrite w;
|
||||||
w.address = addr;
|
w.address = addr;
|
||||||
|
while((mask & 1) == 0){
|
||||||
|
mask >>= 1;
|
||||||
|
w.address++;
|
||||||
|
w.data >>= 8;
|
||||||
|
}
|
||||||
|
switch(mask){
|
||||||
|
case 1: size = 0; break;
|
||||||
|
case 3: size = min(1u, size); break;
|
||||||
|
case 15: size = min(2u, size); break;
|
||||||
|
}
|
||||||
w.size = 1 << size;
|
w.size = 1 << size;
|
||||||
switch(size){
|
switch(size){
|
||||||
case 0: w.data = *data & 0xFF; break;
|
case 0: w.data = *data & 0xFF; break;
|
||||||
|
@ -3446,6 +3456,7 @@ int main(int argc, char **argv, char **env) {
|
||||||
// redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
|
// redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
|
||||||
// return 0;
|
// return 0;
|
||||||
|
|
||||||
|
redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
|
||||||
|
|
||||||
for(int idx = 0;idx < 1;idx++){
|
for(int idx = 0;idx < 1;idx++){
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue