Merge pull request #310 from ucb-bar/rxia-testharness-refactor
Resolve merge conflicts in testharness-refactor
This commit is contained in:
commit
7ff7076dab
2
chisel3
2
chisel3
@ -1 +1 @@
|
|||||||
Subproject commit 2ff229dac5f915e7f583cbf9cc8118674a4e52a5
|
Subproject commit dda64c1dee16b5da15ac690bd3cd6759c3d5c032
|
2
firrtl
2
firrtl
@ -1 +1 @@
|
|||||||
Subproject commit 7c38199ce7a5d9dd7e27ffbb9b2b2770b972ed94
|
Subproject commit 726c808375fe513c70376bf05e76dd938e578bf9
|
@ -139,7 +139,7 @@ class BaseCoreplexConfig extends Config (
|
|||||||
else new MESICoherence(site(L2DirectoryRepresentation))),
|
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1 /* MMIO */,
|
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1 /* MMIO */,
|
||||||
nCachingClients = site(NCachedTileLinkPorts),
|
nCachingClients = site(NCachedTileLinkPorts),
|
||||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||||
maxClientXacts = max_int(
|
maxClientXacts = max_int(
|
||||||
// L1 cache
|
// L1 cache
|
||||||
site(DCacheKey).nMSHRs + 1 /* IOMSHR */,
|
site(DCacheKey).nMSHRs + 1 /* IOMSHR */,
|
||||||
@ -170,7 +170,7 @@ class BaseCoreplexConfig extends Config (
|
|||||||
TileLinkParameters(
|
TileLinkParameters(
|
||||||
coherencePolicy = new MICoherence(
|
coherencePolicy = new MICoherence(
|
||||||
new NullRepresentation(site(NBanksPerMemoryChannel))),
|
new NullRepresentation(site(NBanksPerMemoryChannel))),
|
||||||
nManagers = site(GlobalAddrMap).get.subMap("io").numSlaves,
|
nManagers = 1,
|
||||||
nCachingClients = 0,
|
nCachingClients = 0,
|
||||||
nCachelessClients = 1,
|
nCachelessClients = 1,
|
||||||
maxClientXacts = 4,
|
maxClientXacts = 4,
|
||||||
|
@ -32,7 +32,7 @@ trait HasCoreplexParameters {
|
|||||||
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
||||||
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
||||||
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" })
|
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" })
|
||||||
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap).get
|
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class CoreplexConfig(
|
case class CoreplexConfig(
|
||||||
@ -56,7 +56,7 @@ abstract class Coreplex(implicit val p: Parameters, implicit val c: CoreplexConf
|
|||||||
val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
|
val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
|
||||||
val interrupts = Vec(c.nExtInterrupts, Bool()).asInput
|
val interrupts = Vec(c.nExtInterrupts, Bool()).asInput
|
||||||
val debug = new DebugBusIO()(p).flip
|
val debug = new DebugBusIO()(p).flip
|
||||||
val prci = Vec(c.nTiles, new PRCITileIO).flip
|
val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput
|
||||||
val success = Bool(OUTPUT)
|
val success = Bool(OUTPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +149,8 @@ class DefaultCoreplex(tp: Parameters, tc: CoreplexConfig) extends Coreplex()(tp,
|
|||||||
|
|
||||||
// connect coreplex-internal interrupts to tiles
|
// connect coreplex-internal interrupts to tiles
|
||||||
for (((tile, tileReset), i) <- (tileList zip tileResets) zipWithIndex) {
|
for (((tile, tileReset), i) <- (tileList zip tileResets) zipWithIndex) {
|
||||||
tileReset := io.prci(i).reset
|
tileReset := reset // TODO should tiles be reset separately from coreplex?
|
||||||
tile.io.interrupts := io.prci(i).interrupts
|
tile.io.interrupts := io.clint(i)
|
||||||
tile.io.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
|
tile.io.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
|
||||||
tile.io.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
|
tile.io.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
|
||||||
tile.io.interrupts.debug := debugModule.io.debugInterrupts(i)
|
tile.io.interrupts.debug := debugModule.io.debugInterrupts(i)
|
||||||
|
@ -338,7 +338,7 @@ class ComparatorSink(implicit val p: Parameters) extends Module
|
|||||||
|
|
||||||
assert (g.is_builtin_type, "grant not builtin")
|
assert (g.is_builtin_type, "grant not builtin")
|
||||||
assert (base.g_type === g.g_type, "g_type mismatch")
|
assert (base.g_type === g.g_type, "g_type mismatch")
|
||||||
assert (base.addr_beat === g.addr_beat || !g.hasData(), "addr_beat mismatch")
|
assert (base.addr_beat === g.addr_beat || !g.hasMultibeatData(), "addr_beat mismatch")
|
||||||
assert (base.data === g.data || !g.hasData(), "data mismatch")
|
assert (base.data === g.data || !g.hasData(), "data mismatch")
|
||||||
|
|
||||||
assert_conds.zipWithIndex.foreach { case (cond, i) =>
|
assert_conds.zipWithIndex.foreach { case (cond, i) =>
|
||||||
|
@ -92,7 +92,7 @@ class WithGroundTest extends Config(
|
|||||||
else new MESICoherence(site(L2DirectoryRepresentation))),
|
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
||||||
nCachingClients = site(NCachedTileLinkPorts),
|
nCachingClients = site(NCachedTileLinkPorts),
|
||||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||||
maxClientXacts = ((site(DCacheKey).nMSHRs + 1) +:
|
maxClientXacts = ((site(DCacheKey).nMSHRs + 1) +:
|
||||||
site(GroundTestKey).map(_.maxXacts))
|
site(GroundTestKey).map(_.maxXacts))
|
||||||
.reduce(max(_, _)),
|
.reduce(max(_, _)),
|
||||||
@ -137,11 +137,11 @@ class WithComparator extends Config(
|
|||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new ComparatorCore()(p))
|
(p: Parameters) => Module(new ComparatorCore()(p))
|
||||||
case ComparatorKey => ComparatorParameters(
|
case ComparatorKey => ComparatorParameters(
|
||||||
targets = Seq("mem", "io:ext:testram").map(name =>
|
targets = Seq("mem", "io:ext:TL2:testram").map(name =>
|
||||||
site(GlobalAddrMap).get(name).start.longValue),
|
site(GlobalAddrMap)(name).start.longValue),
|
||||||
width = 8,
|
width = 8,
|
||||||
operations = 1000,
|
operations = 1000,
|
||||||
atomics = site(UseAtomics),
|
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||||
case FPUConfig => None
|
case FPUConfig => None
|
||||||
case UseAtomics => false
|
case UseAtomics => false
|
||||||
@ -168,7 +168,7 @@ class WithMemtest extends Config(
|
|||||||
}
|
}
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new GeneratorTest()(p))
|
(p: Parameters) => Module(new GeneratorTest()(p))
|
||||||
case _ => throw new CDEMatchError
|
case _ => throw new CDEMatchError
|
||||||
@ -228,7 +228,7 @@ class WithNastiConverterTest extends Config(
|
|||||||
}
|
}
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new NastiConverterTest()(p))
|
(p: Parameters) => Module(new NastiConverterTest()(p))
|
||||||
case _ => throw new CDEMatchError
|
case _ => throw new CDEMatchError
|
||||||
@ -248,7 +248,7 @@ class WithTraceGen extends Config(
|
|||||||
val nSets = 32 // L2 NSets
|
val nSets = 32 // L2 NSets
|
||||||
val nWays = 1
|
val nWays = 1
|
||||||
val blockOffset = site(CacheBlockOffsetBits)
|
val blockOffset = site(CacheBlockOffsetBits)
|
||||||
val baseAddr = site(GlobalAddrMap).get("mem").start
|
val baseAddr = site(GlobalAddrMap)("mem").start
|
||||||
val nBeats = site(MIFDataBeats)
|
val nBeats = site(MIFDataBeats)
|
||||||
List.tabulate(4 * nWays) { i =>
|
List.tabulate(4 * nWays) { i =>
|
||||||
Seq.tabulate(nBeats) { j => (j * 8) + ((i * nSets) << blockOffset) }
|
Seq.tabulate(nBeats) { j => (j * 8) + ((i * nSets) << blockOffset) }
|
||||||
@ -260,6 +260,7 @@ class WithTraceGen extends Config(
|
|||||||
knobValues = {
|
knobValues = {
|
||||||
case "L1D_SETS" => 16
|
case "L1D_SETS" => 16
|
||||||
case "L1D_WAYS" => 1
|
case "L1D_WAYS" => 1
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
})
|
})
|
||||||
|
|
||||||
class WithPCIeMockupTest extends Config(
|
class WithPCIeMockupTest extends Config(
|
||||||
@ -270,7 +271,7 @@ class WithPCIeMockupTest extends Config(
|
|||||||
GroundTestTileSettings(1))
|
GroundTestTileSettings(1))
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => p(TileId) match {
|
(p: Parameters) => p(TileId) match {
|
||||||
case 0 => Module(new GeneratorTest()(p))
|
case 0 => Module(new GeneratorTest()(p))
|
||||||
@ -304,7 +305,7 @@ class WithDirectComparator extends Config(
|
|||||||
targets = Seq(0L, 0x100L),
|
targets = Seq(0L, 0x100L),
|
||||||
width = 8,
|
width = 8,
|
||||||
operations = 1000,
|
operations = 1000,
|
||||||
atomics = site(UseAtomics),
|
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||||
case FPUConfig => None
|
case FPUConfig => None
|
||||||
case UseAtomics => false
|
case UseAtomics => false
|
||||||
|
@ -72,7 +72,7 @@ class IOGetAfterPutBlockRegression(implicit p: Parameters) extends Regression()(
|
|||||||
io.mem.grant.ready := Bool(true)
|
io.mem.grant.ready := Bool(true)
|
||||||
|
|
||||||
io.cache.req.valid := !get_sent && started
|
io.cache.req.valid := !get_sent && started
|
||||||
io.cache.req.bits.addr := UInt(addrMap("io:ext:bootrom").start)
|
io.cache.req.bits.addr := UInt(addrMap("io:ext:TL2:bootrom").start)
|
||||||
io.cache.req.bits.typ := UInt(log2Ceil(32 / 8))
|
io.cache.req.bits.typ := UInt(log2Ceil(32 / 8))
|
||||||
io.cache.req.bits.cmd := M_XRD
|
io.cache.req.bits.cmd := M_XRD
|
||||||
io.cache.req.bits.tag := UInt(0)
|
io.cache.req.bits.tag := UInt(0)
|
||||||
|
@ -4,4 +4,4 @@ import Chisel._
|
|||||||
import cde.Parameters
|
import cde.Parameters
|
||||||
|
|
||||||
// !!! TODO: Replace with a groundtest-specific test harness
|
// !!! TODO: Replace with a groundtest-specific test harness
|
||||||
class TestHarness(implicit p: Parameters) extends rocketchip.TestHarness()(p)
|
class TestHarness(implicit p: Parameters) extends rocketchip.TestHarness(p)
|
||||||
|
@ -12,7 +12,7 @@ trait HasAddrMapParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
|
|
||||||
val paddrBits = p(PAddrBits)
|
val paddrBits = p(PAddrBits)
|
||||||
def addrMap = p(rocketchip.GlobalAddrMap).get
|
def addrMap = p(rocketchip.GlobalAddrMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
||||||
|
@ -20,9 +20,6 @@ import cde.{Parameters, Config, Dump, Knob, CDEMatchError}
|
|||||||
|
|
||||||
class BasePlatformConfig extends Config(
|
class BasePlatformConfig extends Config(
|
||||||
topDefinitions = {
|
topDefinitions = {
|
||||||
val configString = new GlobalVariable[String]
|
|
||||||
val globalAddrMap = new GlobalVariable[AddrMap]
|
|
||||||
val nCoreplexExtClients = new GlobalVariable[Int]
|
|
||||||
(pname,site,here) => {
|
(pname,site,here) => {
|
||||||
type PF = PartialFunction[Any,Any]
|
type PF = PartialFunction[Any,Any]
|
||||||
def findBy(sname:Any):Any = here[PF](site[Any](sname))(pname)
|
def findBy(sname:Any):Any = here[PF](site[Any](sname))(pname)
|
||||||
@ -55,7 +52,6 @@ class BasePlatformConfig extends Config(
|
|||||||
case NExtMMIOTLChannels => 0
|
case NExtMMIOTLChannels => 0
|
||||||
case AsyncBusChannels => false
|
case AsyncBusChannels => false
|
||||||
case NExtBusAXIChannels => 0
|
case NExtBusAXIChannels => 0
|
||||||
case NCoreplexExtClients => nCoreplexExtClients
|
|
||||||
case HastiId => "Ext"
|
case HastiId => "Ext"
|
||||||
case HastiKey("TL") =>
|
case HastiKey("TL") =>
|
||||||
HastiParameters(
|
HastiParameters(
|
||||||
@ -69,8 +65,6 @@ class BasePlatformConfig extends Config(
|
|||||||
case NMemoryChannels => Dump("N_MEM_CHANNELS", 1)
|
case NMemoryChannels => Dump("N_MEM_CHANNELS", 1)
|
||||||
case TMemoryChannels => BusType.AXI
|
case TMemoryChannels => BusType.AXI
|
||||||
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
||||||
case ConfigString => configString
|
|
||||||
case GlobalAddrMap => globalAddrMap
|
|
||||||
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
||||||
case BuildExampleTop =>
|
case BuildExampleTop =>
|
||||||
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTop(p))
|
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTop(p))
|
||||||
@ -152,6 +146,7 @@ class RoccExampleConfig extends Config(new WithRoccExample ++ new BaseConfig)
|
|||||||
class WithMIFDataBits(n: Int) extends Config(
|
class WithMIFDataBits(n: Int) extends Config(
|
||||||
(pname, site, here) => pname match {
|
(pname, site, here) => pname match {
|
||||||
case MIFDataBits => Dump("MIF_DATA_BITS", n)
|
case MIFDataBits => Dump("MIF_DATA_BITS", n)
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
})
|
})
|
||||||
|
|
||||||
class MIF128BitConfig extends Config(
|
class MIF128BitConfig extends Config(
|
||||||
@ -182,12 +177,14 @@ class TinyConfig extends Config(
|
|||||||
|
|
||||||
class WithAsyncDebug extends Config (
|
class WithAsyncDebug extends Config (
|
||||||
(pname, site, here) => pname match {
|
(pname, site, here) => pname match {
|
||||||
case AsyncDebugBus => true
|
case AsyncDebugBus => true
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
class WithJtagDTM extends Config (
|
class WithJtagDTM extends Config (
|
||||||
(pname, site, here) => pname match {
|
(pname, site, here) => pname match {
|
||||||
case IncludeJtagDTM => true
|
case IncludeJtagDTM => true
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -56,6 +56,10 @@ trait HasGeneratorUtilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ConfigStringOutput {
|
||||||
|
var contents: Option[String] = None
|
||||||
|
}
|
||||||
|
|
||||||
trait Generator extends App with HasGeneratorUtilities {
|
trait Generator extends App with HasGeneratorUtilities {
|
||||||
lazy val names = {
|
lazy val names = {
|
||||||
require(args.size == 5, "Usage: sbt> " +
|
require(args.size == 5, "Usage: sbt> " +
|
||||||
@ -67,20 +71,25 @@ trait Generator extends App with HasGeneratorUtilities {
|
|||||||
configProject = args(3),
|
configProject = args(3),
|
||||||
configs = args(4))
|
configs = args(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy val td = names.targetDir
|
||||||
lazy val config = getConfig(names)
|
lazy val config = getConfig(names)
|
||||||
lazy val world = config.toInstance
|
lazy val world = config.toInstance
|
||||||
lazy val params = Parameters.root(world)
|
lazy val params = Parameters.root(world)
|
||||||
lazy val circuit = elaborate(names, params)
|
lazy val circuit = elaborate(names, params)
|
||||||
|
lazy val longName = names.topModuleClass + "." + names.configs
|
||||||
|
|
||||||
|
def writeOutputFiles() {
|
||||||
|
TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames)))
|
||||||
|
writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
||||||
|
writeOutputFile(td, s"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump()
|
||||||
|
writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE
|
||||||
|
writeOutputFile(td, s"${names.configs}.cst", world.getConstraints) // Constraints for DSE
|
||||||
|
ConfigStringOutput.contents.foreach(c => writeOutputFile(td, s"${names.configs}.cfg", c)) // String for software
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object RocketChipGenerator extends Generator {
|
object RocketChipGenerator extends Generator {
|
||||||
val longName = names.topModuleClass + "." + names.configs
|
|
||||||
val td = names.targetDir
|
|
||||||
Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
|
Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
|
||||||
TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames)))
|
writeOutputFiles()
|
||||||
writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
|
||||||
writeOutputFile(td, s"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump()
|
|
||||||
writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE
|
|
||||||
writeOutputFile(td, s"${names.configs}.cst", world.getConstraints) // Constraints for DSE
|
|
||||||
writeOutputFile(td, s"${names.configs}.cfg", params(ConfigString).get) // String for software
|
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,13 @@ import cde.{Parameters, Field}
|
|||||||
import junctions._
|
import junctions._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
import uncore.tilelink2._
|
||||||
import uncore.converters._
|
import uncore.converters._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
import rocket.Util._
|
import rocket.Util._
|
||||||
|
import rocket.XLen
|
||||||
|
import scala.math.max
|
||||||
import coreplex._
|
import coreplex._
|
||||||
|
|
||||||
/** Options for memory bus interface */
|
/** Options for memory bus interface */
|
||||||
@ -202,10 +204,10 @@ trait PeripheryMasterMMIOModule extends HasPeripheryParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryMasterMMIO
|
val outer: PeripheryMasterMMIO
|
||||||
val io: PeripheryMasterMMIOBundle
|
val io: PeripheryMasterMMIOBundle
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
val mmioNetwork: TileLinkRecursiveInterconnect
|
||||||
|
|
||||||
val mmio_ports = p(ExtMMIOPorts) map { port =>
|
val mmio_ports = p(ExtMMIOPorts) map { port =>
|
||||||
TileLinkWidthAdapter(mmioNetwork.get.port(port.name), "MMIO_Outermost")
|
TileLinkWidthAdapter(mmioNetwork.port(port.name), "MMIO_Outermost")
|
||||||
}
|
}
|
||||||
|
|
||||||
val mmio_axi_start = 0
|
val mmio_axi_start = 0
|
||||||
@ -277,37 +279,47 @@ trait PeripherySlaveModule extends HasPeripheryParameters {
|
|||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
/** Always-ON block */
|
trait PeripheryCoreplexLocalInterrupter extends LazyModule with HasPeripheryParameters {
|
||||||
trait PeripheryAON extends LazyModule {
|
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
|
val peripheryBus: TLXbar
|
||||||
|
|
||||||
|
// CoreplexLocalInterrupter must be at least 64b if XLen >= 64
|
||||||
|
val beatBytes = (innerMMIOParams(XLen) min 64) / 8
|
||||||
|
val clintConfig = CoreplexLocalInterrupterConfig(beatBytes)
|
||||||
|
val clint = LazyModule(new CoreplexLocalInterrupter(clintConfig)(innerMMIOParams))
|
||||||
|
// The periphery bus is 32-bit, so we may need to adapt its width to XLen
|
||||||
|
clint.node := TLFragmenter(TLWidthWidget(peripheryBus.node, 4), beatBytes, 256)
|
||||||
|
|
||||||
|
// TL1 legacy
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
val pDevices: ResourceManager[AddrMapEntry]
|
||||||
|
pDevices.add(AddrMapEntry("clint", MemRange(clintConfig.address, clintConfig.size, MemAttr(AddrMapProt.RW))))
|
||||||
pDevices.add(AddrMapEntry("prci", MemSize(0x4000000, MemAttr(AddrMapProt.RW))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryAONBundle {
|
trait PeripheryCoreplexLocalInterrupterBundle {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryAONModule extends HasPeripheryParameters {
|
trait PeripheryCoreplexLocalInterrupterModule extends HasPeripheryParameters {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryAON
|
val outer: PeripheryCoreplexLocalInterrupter
|
||||||
val io: PeripheryAONBundle
|
val io: PeripheryCoreplexLocalInterrupterBundle
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
||||||
val coreplex: Coreplex
|
val coreplex: Coreplex
|
||||||
|
|
||||||
val prci = Module(new PRCI()(innerMMIOParams))
|
outer.clint.module.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
||||||
prci.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
coreplex.io.clint <> outer.clint.module.io.tiles
|
||||||
prci.io.tl <> mmioNetwork.get.port("prci")
|
|
||||||
coreplex.io.prci <> prci.io.tiles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
trait PeripheryBootROM extends LazyModule {
|
trait PeripheryBootROM extends LazyModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
val peripheryBus: TLXbar
|
||||||
|
|
||||||
|
val rom = LazyModule(new TLROM(0x1000, 0x1000, GenerateBootROM(p)))
|
||||||
|
rom.node := TLFragmenter(peripheryBus.node, 4, 256)
|
||||||
|
|
||||||
|
// TL1 legacy address map
|
||||||
|
val pDevices: ResourceManager[AddrMapEntry]
|
||||||
pDevices.add(AddrMapEntry("bootrom", MemRange(0x1000, 4096, MemAttr(AddrMapProt.RX))))
|
pDevices.add(AddrMapEntry("bootrom", MemRange(0x1000, 4096, MemAttr(AddrMapProt.RX))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,20 +331,23 @@ trait PeripheryBootROMModule extends HasPeripheryParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryBootROM
|
val outer: PeripheryBootROM
|
||||||
val io: PeripheryBootROMBundle
|
val io: PeripheryBootROMBundle
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
||||||
|
|
||||||
val bootROM = Module(new ROMSlave(GenerateBootROM(p))(innerMMIOParams))
|
|
||||||
bootROM.io <> mmioNetwork.get.port("bootrom")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
trait PeripheryTestRAM extends LazyModule {
|
trait PeripheryTestRAM extends LazyModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
val peripheryBus: TLXbar
|
||||||
|
|
||||||
|
val ramBase = 0x52000000
|
||||||
val ramSize = 0x1000
|
val ramSize = 0x1000
|
||||||
pDevices.add(AddrMapEntry("testram", MemSize(ramSize, MemAttr(AddrMapProt.RW))))
|
|
||||||
|
val sram = LazyModule(new TLRAM(AddressSet(ramBase, ramSize-1)))
|
||||||
|
sram.node := TLFragmenter(peripheryBus.node, 4, 256)
|
||||||
|
|
||||||
|
// TL1 legacy address map
|
||||||
|
val pDevices: ResourceManager[AddrMapEntry]
|
||||||
|
pDevices.add(AddrMapEntry("testram", MemRange(ramBase, ramSize, MemAttr(AddrMapProt.RW))))
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryTestRAMBundle {
|
trait PeripheryTestRAMBundle {
|
||||||
@ -342,22 +357,16 @@ trait PeripheryTestRAMBundle {
|
|||||||
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryTestRAM
|
val outer: PeripheryTestRAM
|
||||||
val io: PeripheryTestRAMBundle
|
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
||||||
|
|
||||||
val testram = Module(new TileLinkTestRAM(outer.ramSize)(innerMMIOParams))
|
|
||||||
testram.io <> mmioNetwork.get.port("testram")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
trait PeripheryTestBusMaster extends LazyModule {
|
trait PeripheryTestBusMaster extends LazyModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pBusMasters: RangeManager
|
val peripheryBus: TLXbar
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
|
||||||
|
|
||||||
pBusMasters.add("busmaster", 1)
|
val fuzzer = LazyModule(new TLFuzzer(5000))
|
||||||
pDevices.add(AddrMapEntry("busmaster", MemSize(4096, MemAttr(AddrMapProt.RW))))
|
peripheryBus.node := fuzzer.node
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryTestBusMasterBundle {
|
trait PeripheryTestBusMasterBundle {
|
||||||
@ -367,16 +376,4 @@ trait PeripheryTestBusMasterBundle {
|
|||||||
trait PeripheryTestBusMasterModule {
|
trait PeripheryTestBusMasterModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryTestBusMaster
|
val outer: PeripheryTestBusMaster
|
||||||
val io: PeripheryTestBusMasterBundle
|
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
||||||
val coreplex: Coreplex
|
|
||||||
|
|
||||||
val busmaster = Module(new groundtest.ExampleBusMaster()(p))
|
|
||||||
busmaster.io.mmio <> mmioNetwork.get.port("busmaster")
|
|
||||||
|
|
||||||
{
|
|
||||||
val r = outer.pBusMasters.range("busmaster")
|
|
||||||
require(r._2 - r._1 == 1, "RangeManager should return 1 slot")
|
|
||||||
coreplex.io.slave(r._1) <> busmaster.io.mem
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,12 @@ import junctions.NastiConstants._
|
|||||||
case object BuildExampleTop extends Field[Parameters => ExampleTop]
|
case object BuildExampleTop extends Field[Parameters => ExampleTop]
|
||||||
case object SimMemLatency extends Field[Int]
|
case object SimMemLatency extends Field[Int]
|
||||||
|
|
||||||
class TestHarness(implicit val p: Parameters) extends Module with HasAddrMapParameters {
|
class TestHarness(q: Parameters) extends Module {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val success = Bool(OUTPUT)
|
val success = Bool(OUTPUT)
|
||||||
}
|
}
|
||||||
val dut = p(BuildExampleTop)(p).module
|
val dut = q(BuildExampleTop)(q).module
|
||||||
|
implicit val p = dut.p
|
||||||
|
|
||||||
// This test harness isn't especially flexible yet
|
// This test harness isn't especially flexible yet
|
||||||
require(dut.io.mem_clk.isEmpty)
|
require(dut.io.mem_clk.isEmpty)
|
||||||
@ -34,7 +35,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasAddrMapPara
|
|||||||
int := false
|
int := false
|
||||||
|
|
||||||
if (dut.io.mem_axi.nonEmpty) {
|
if (dut.io.mem_axi.nonEmpty) {
|
||||||
val memSize = addrMap("mem").size
|
val memSize = p(GlobalAddrMap)("mem").size
|
||||||
require(memSize % dut.io.mem_axi.size == 0)
|
require(memSize % dut.io.mem_axi.size == 0)
|
||||||
for (axi <- dut.io.mem_axi) {
|
for (axi <- dut.io.mem_axi) {
|
||||||
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
|
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
|
||||||
|
@ -6,7 +6,7 @@ import Chisel._
|
|||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
import junctions._
|
import junctions._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
import uncore.tilelink2._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import util.ParameterizedBundle
|
import util.ParameterizedBundle
|
||||||
import rocket._
|
import rocket._
|
||||||
@ -14,18 +14,41 @@ import rocket.Util._
|
|||||||
import coreplex._
|
import coreplex._
|
||||||
|
|
||||||
// the following parameters will be refactored properly with TL2
|
// the following parameters will be refactored properly with TL2
|
||||||
case object GlobalAddrMap extends Field[GlobalVariable[AddrMap]]
|
case object GlobalAddrMap extends Field[AddrMap]
|
||||||
case object ConfigString extends Field[GlobalVariable[String]]
|
case object ConfigString extends Field[String]
|
||||||
case object NCoreplexExtClients extends Field[GlobalVariable[Int]]
|
case object NCoreplexExtClients extends Field[Int]
|
||||||
/** Function for building Coreplex */
|
/** Function for building Coreplex */
|
||||||
case object BuildCoreplex extends Field[(Parameters, CoreplexConfig) => Coreplex]
|
case object BuildCoreplex extends Field[(Parameters, CoreplexConfig) => Coreplex]
|
||||||
|
|
||||||
/** Base Top with no Periphery */
|
/** Base Top with no Periphery */
|
||||||
abstract class BaseTop(val p: Parameters) extends LazyModule {
|
abstract class BaseTop(q: Parameters) extends LazyModule {
|
||||||
// the following variables will be refactored properly with TL2
|
// the following variables will be refactored properly with TL2
|
||||||
val pInterrupts = new RangeManager
|
val pInterrupts = new RangeManager
|
||||||
val pBusMasters = new RangeManager
|
val pBusMasters = new RangeManager
|
||||||
val pDevices = new ResourceManager[AddrMapEntry]
|
val pDevices = new ResourceManager[AddrMapEntry]
|
||||||
|
|
||||||
|
lazy val c = CoreplexConfig(
|
||||||
|
nTiles = q(NTiles),
|
||||||
|
nExtInterrupts = pInterrupts.sum,
|
||||||
|
nSlaves = pBusMasters.sum,
|
||||||
|
nMemChannels = q(NMemoryChannels),
|
||||||
|
hasSupervisor = q(UseVM),
|
||||||
|
hasExtMMIOPort = true
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val genGlobalAddrMap = GenerateGlobalAddrMap(q, pDevices.get)
|
||||||
|
private val qWithMap = q.alterPartial({case GlobalAddrMap => genGlobalAddrMap})
|
||||||
|
|
||||||
|
lazy val genConfigString = GenerateConfigString(qWithMap, c, pDevices.get)
|
||||||
|
implicit val p = qWithMap.alterPartial({
|
||||||
|
case ConfigString => genConfigString
|
||||||
|
case NCoreplexExtClients => pBusMasters.sum})
|
||||||
|
|
||||||
|
// Add a peripheral bus
|
||||||
|
val peripheryBus = LazyModule(new TLXbar)
|
||||||
|
val legacy = LazyModule(new TLLegacy()(p.alterPartial({ case TLId => "L2toMMIO" })))
|
||||||
|
|
||||||
|
peripheryBus.node := TLBuffer(TLWidthWidget(TLHintHandler(legacy.node), legacy.tlDataBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBundle()(p) {
|
class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBundle()(p) {
|
||||||
@ -35,24 +58,19 @@ class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBun
|
|||||||
class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L, b: Coreplex => B) extends LazyModuleImp(l) {
|
class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L, b: Coreplex => B) extends LazyModuleImp(l) {
|
||||||
val outer: L = l
|
val outer: L = l
|
||||||
|
|
||||||
val c = CoreplexConfig(
|
val coreplex = p(BuildCoreplex)(p, outer.c)
|
||||||
nTiles = p(NTiles),
|
val io: B = b(coreplex)
|
||||||
nExtInterrupts = outer.pInterrupts.sum,
|
|
||||||
nSlaves = outer.pBusMasters.sum,
|
|
||||||
nMemChannels = p(NMemoryChannels),
|
|
||||||
hasSupervisor = p(UseVM),
|
|
||||||
hasExtMMIOPort = !(outer.pDevices.get.isEmpty && p(ExtMMIOPorts).isEmpty)
|
|
||||||
)
|
|
||||||
|
|
||||||
def genGlobalAddrMap = GenerateGlobalAddrMap(p, outer.pDevices.get)
|
io.success := coreplex.io.success
|
||||||
def genConfigString = GenerateConfigString(p, c, outer.pDevices.get)
|
|
||||||
|
|
||||||
p(NCoreplexExtClients).assign(outer.pBusMasters.sum)
|
val mmioNetwork =
|
||||||
p(GlobalAddrMap).assign(genGlobalAddrMap)
|
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).subMap("io:ext"))(
|
||||||
p(ConfigString).assign(genConfigString)
|
p.alterPartial({ case TLId => "L2toMMIO" })))
|
||||||
|
mmioNetwork.io.in.head <> coreplex.io.master.mmio.get
|
||||||
|
outer.legacy.module.io.legacy <> mmioNetwork.port("TL2")
|
||||||
|
|
||||||
println("Generated Address Map")
|
println("Generated Address Map")
|
||||||
for (entry <- p(GlobalAddrMap).get.flatten) {
|
for (entry <- p(GlobalAddrMap).flatten) {
|
||||||
val name = entry.name
|
val name = entry.name
|
||||||
val start = entry.region.start
|
val start = entry.region.start
|
||||||
val end = entry.region.start + entry.region.size - 1
|
val end = entry.region.start + entry.region.size - 1
|
||||||
@ -60,36 +78,27 @@ class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L,
|
|||||||
}
|
}
|
||||||
|
|
||||||
println("Generated Configuration String")
|
println("Generated Configuration String")
|
||||||
println(p(ConfigString).get)
|
println(p(ConfigString))
|
||||||
|
ConfigStringOutput.contents = Some(p(ConfigString))
|
||||||
val coreplex = p(BuildCoreplex)(p, c)
|
|
||||||
val io: B = b(coreplex)
|
|
||||||
|
|
||||||
io.success := coreplex.io.success
|
|
||||||
|
|
||||||
val mmioNetwork = c.hasExtMMIOPort.option(
|
|
||||||
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).get.subMap("io:ext"))(
|
|
||||||
p.alterPartial({ case TLId => "L2toMMIO" }))))
|
|
||||||
mmioNetwork.foreach { _.io.in.head <> coreplex.io.master.mmio.get }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Example Top with Periphery */
|
/** Example Top with Periphery */
|
||||||
class ExampleTop(p: Parameters) extends BaseTop(p)
|
class ExampleTop(q: Parameters) extends BaseTop(q)
|
||||||
with PeripheryBootROM with PeripheryDebug with PeripheryExtInterrupts with PeripheryAON
|
with PeripheryBootROM with PeripheryDebug with PeripheryExtInterrupts with PeripheryCoreplexLocalInterrupter
|
||||||
with PeripheryMasterMem with PeripheryMasterMMIO with PeripherySlave {
|
with PeripheryMasterMem with PeripheryMasterMMIO with PeripherySlave {
|
||||||
override lazy val module = Module(new ExampleTopModule(p, this, new ExampleTopBundle(p, _)))
|
override lazy val module = Module(new ExampleTopModule(p, this, new ExampleTopBundle(p, _)))
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExampleTopBundle(p: Parameters, c: Coreplex) extends BaseTopBundle(p, c)
|
class ExampleTopBundle(p: Parameters, c: Coreplex) extends BaseTopBundle(p, c)
|
||||||
with PeripheryBootROMBundle with PeripheryDebugBundle with PeripheryExtInterruptsBundle with PeripheryAONBundle
|
with PeripheryBootROMBundle with PeripheryDebugBundle with PeripheryExtInterruptsBundle with PeripheryCoreplexLocalInterrupterBundle
|
||||||
with PeripheryMasterMemBundle with PeripheryMasterMMIOBundle with PeripherySlaveBundle
|
with PeripheryMasterMemBundle with PeripheryMasterMMIOBundle with PeripherySlaveBundle
|
||||||
|
|
||||||
class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters, l: L, b: Coreplex => B) extends BaseTopModule(p, l, b)
|
class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters, l: L, b: Coreplex => B) extends BaseTopModule(p, l, b)
|
||||||
with PeripheryBootROMModule with PeripheryDebugModule with PeripheryExtInterruptsModule with PeripheryAONModule
|
with PeripheryBootROMModule with PeripheryDebugModule with PeripheryExtInterruptsModule with PeripheryCoreplexLocalInterrupterModule
|
||||||
with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule
|
with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule
|
||||||
|
|
||||||
/** Example Top with TestRAM */
|
/** Example Top with TestRAM */
|
||||||
class ExampleTopWithTestRAM(p: Parameters) extends ExampleTop(p)
|
class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q)
|
||||||
with PeripheryTestRAM {
|
with PeripheryTestRAM {
|
||||||
override lazy val module = Module(new ExampleTopWithTestRAMModule(p, this, new ExampleTopWithTestRAMBundle(p, _)))
|
override lazy val module = Module(new ExampleTopWithTestRAMModule(p, this, new ExampleTopWithTestRAMBundle(p, _)))
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,8 @@ object GenerateGlobalAddrMap {
|
|||||||
new AddrMap(entries)
|
new AddrMap(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val extIOAddrMap = new AddrMap(
|
lazy val tl2AddrMap = new AddrMap(pDevicesEntries, collapse = true)
|
||||||
pDevicesEntries ++ p(ExtMMIOPorts),
|
lazy val extIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: p(ExtMMIOPorts), collapse = true)
|
||||||
start = BigInt("50000000", 16),
|
|
||||||
collapse = true)
|
|
||||||
|
|
||||||
val memBase = 0x80000000L
|
val memBase = 0x80000000L
|
||||||
val memSize = p(ExtMemSize)
|
val memSize = p(ExtMemSize)
|
||||||
@ -83,9 +81,9 @@ object GenerateGlobalAddrMap {
|
|||||||
|
|
||||||
object GenerateConfigString {
|
object GenerateConfigString {
|
||||||
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry]) = {
|
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry]) = {
|
||||||
val addrMap = p(GlobalAddrMap).get
|
val addrMap = p(GlobalAddrMap)
|
||||||
val plicAddr = addrMap("io:int:plic").start
|
val plicAddr = addrMap("io:int:plic").start
|
||||||
val prciAddr = addrMap("io:ext:prci").start
|
val clint = CoreplexLocalInterrupterConfig(0, addrMap("io:ext:TL2:clint").start)
|
||||||
val xLen = p(XLen)
|
val xLen = p(XLen)
|
||||||
val res = new StringBuilder
|
val res = new StringBuilder
|
||||||
res append "plic {\n"
|
res append "plic {\n"
|
||||||
@ -94,7 +92,7 @@ object GenerateConfigString {
|
|||||||
res append s" ndevs ${c.plicKey.nDevices};\n"
|
res append s" ndevs ${c.plicKey.nDevices};\n"
|
||||||
res append "};\n"
|
res append "};\n"
|
||||||
res append "rtc {\n"
|
res append "rtc {\n"
|
||||||
res append s" addr 0x${(prciAddr + PRCI.time).toString(16)};\n"
|
res append s" addr 0x${clint.timeAddress.toString(16)};\n"
|
||||||
res append "};\n"
|
res append "};\n"
|
||||||
if (addrMap contains "mem") {
|
if (addrMap contains "mem") {
|
||||||
res append "ram {\n"
|
res append "ram {\n"
|
||||||
@ -117,8 +115,8 @@ object GenerateConfigString {
|
|||||||
res append s" $i {\n"
|
res append s" $i {\n"
|
||||||
res append " 0 {\n"
|
res append " 0 {\n"
|
||||||
res append s" isa $isa;\n"
|
res append s" isa $isa;\n"
|
||||||
res append s" timecmp 0x${(prciAddr + PRCI.timecmp(i)).toString(16)};\n"
|
res append s" timecmp 0x${clint.timecmpAddress(i).toString(16)};\n"
|
||||||
res append s" ipi 0x${(prciAddr + PRCI.msip(i)).toString(16)};\n"
|
res append s" ipi 0x${clint.msipAddress(i).toString(16)};\n"
|
||||||
res append s" plic {\n"
|
res append s" plic {\n"
|
||||||
res append s" m {\n"
|
res append s" m {\n"
|
||||||
res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\n"
|
res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\n"
|
||||||
@ -138,7 +136,7 @@ object GenerateConfigString {
|
|||||||
}
|
}
|
||||||
res append "};\n"
|
res append "};\n"
|
||||||
pDevicesEntries foreach { entry =>
|
pDevicesEntries foreach { entry =>
|
||||||
val region = addrMap("io:ext:" + entry.name)
|
val region = addrMap("io:ext:TL2:" + entry.name)
|
||||||
res append s"${entry.name} {\n"
|
res append s"${entry.name} {\n"
|
||||||
res append s" addr 0x${region.start.toString(16)};\n"
|
res append s" addr 0x${region.start.toString(16)};\n"
|
||||||
res append s" size 0x${region.size.toString(16)}; \n"
|
res append s" size 0x${region.size.toString(16)}; \n"
|
||||||
@ -158,8 +156,8 @@ object GenerateBootROM {
|
|||||||
|
|
||||||
// for now, have the reset vector jump straight to memory
|
// for now, have the reset vector jump straight to memory
|
||||||
val memBase = (
|
val memBase = (
|
||||||
if (p(GlobalAddrMap).get contains "mem") p(GlobalAddrMap).get("mem")
|
if (p(GlobalAddrMap) contains "mem") p(GlobalAddrMap)("mem")
|
||||||
else p(GlobalAddrMap).get("io:int:dmem0")
|
else p(GlobalAddrMap)("io:int:dmem0")
|
||||||
).start
|
).start
|
||||||
val resetToMemDist = memBase - p(ResetVector)
|
val resetToMemDist = memBase - p(ResetVector)
|
||||||
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
|
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
|
||||||
@ -168,6 +166,6 @@ object GenerateBootROM {
|
|||||||
require(rom.getInt(12) == 0,
|
require(rom.getInt(12) == 0,
|
||||||
"Config string address position should not be occupied by code")
|
"Config string address position should not be occupied by code")
|
||||||
rom.putInt(12, configStringAddr)
|
rom.putInt(12, configStringAddr)
|
||||||
rom.array() ++ (p(ConfigString).get.getBytes.toSeq)
|
rom.array() ++ (p(ConfigString).getBytes.toSeq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package uncore
|
package uncore
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import cde.{Config, Parameters, ParameterDump, Knob, Dump}
|
import cde.{Config, Parameters, ParameterDump, Knob, Dump, CDEMatchError}
|
||||||
import junctions.PAddrBits
|
import junctions.PAddrBits
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.agents._
|
import uncore.agents._
|
||||||
@ -85,6 +85,7 @@ class DefaultL2Config extends Config (
|
|||||||
case ECCCode => None
|
case ECCCode => None
|
||||||
case AmoAluOperandBits => 64
|
case AmoAluOperandBits => 64
|
||||||
case SplitMetadata => false
|
case SplitMetadata => false
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
// case XLen => 128
|
// case XLen => 128
|
||||||
}},
|
}},
|
||||||
knobValues = {
|
knobValues = {
|
||||||
@ -93,22 +94,24 @@ class DefaultL2Config extends Config (
|
|||||||
case "NTILES" => 2
|
case "NTILES" => 2
|
||||||
case "N_CACHED_TILES" => 2
|
case "N_CACHED_TILES" => 2
|
||||||
case "L2_CAPACITY_IN_KB" => 256
|
case "L2_CAPACITY_IN_KB" => 256
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
class WithPLRU extends Config(
|
class WithPLRU extends Config(
|
||||||
(pname, site, here) => pname match {
|
(pname, site, here) => pname match {
|
||||||
case L2Replacer => () => new SeqPLRU(site(NSets), site(NWays))
|
case L2Replacer => () => new SeqPLRU(site(NSets), site(NWays))
|
||||||
|
case _ => throw new CDEMatchError
|
||||||
})
|
})
|
||||||
|
|
||||||
class PLRUL2Config extends Config(new WithPLRU ++ new DefaultL2Config)
|
class PLRUL2Config extends Config(new WithPLRU ++ new DefaultL2Config)
|
||||||
|
|
||||||
class With1L2Ways extends Config(knobValues = { case "L2_WAYS" => 1 })
|
class With1L2Ways extends Config(knobValues = { case "L2_WAYS" => 1; case _ => throw new CDEMatchError })
|
||||||
class With2L2Ways extends Config(knobValues = { case "L2_WAYS" => 2 })
|
class With2L2Ways extends Config(knobValues = { case "L2_WAYS" => 2; case _ => throw new CDEMatchError })
|
||||||
class With4L2Ways extends Config(knobValues = { case "L2_WAYS" => 4 })
|
class With4L2Ways extends Config(knobValues = { case "L2_WAYS" => 4; case _ => throw new CDEMatchError })
|
||||||
|
|
||||||
class With1Cached extends Config(knobValues = { case "N_CACHED_TILES" => 1 })
|
class With1Cached extends Config(knobValues = { case "N_CACHED_TILES" => 1; case _ => throw new CDEMatchError })
|
||||||
class With2Cached extends Config(knobValues = { case "N_CACHED_TILES" => 2 })
|
class With2Cached extends Config(knobValues = { case "N_CACHED_TILES" => 2; case _ => throw new CDEMatchError })
|
||||||
|
|
||||||
|
|
||||||
class W1Cached1WaysConfig extends Config(new With1L2Ways ++ new With1Cached ++ new DefaultL2Config)
|
class W1Cached1WaysConfig extends Config(new With1L2Ways ++ new With1Cached ++ new DefaultL2Config)
|
||||||
|
@ -6,114 +6,84 @@ import Chisel._
|
|||||||
import rocket.Util._
|
import rocket.Util._
|
||||||
import junctions._
|
import junctions._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
|
import scala.math.{min,max}
|
||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
|
|
||||||
/** Number of tiles */
|
/** Number of tiles */
|
||||||
case object NTiles extends Field[Int]
|
case object NTiles extends Field[Int]
|
||||||
|
|
||||||
class PRCITileIO(implicit p: Parameters) extends Bundle {
|
class CoreplexLocalInterrupts extends Bundle {
|
||||||
val reset = Bool(OUTPUT)
|
val mtip = Bool()
|
||||||
val interrupts = new Bundle {
|
val msip = Bool()
|
||||||
val mtip = Bool()
|
|
||||||
val msip = Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
override def cloneType: this.type = new PRCITileIO().asInstanceOf[this.type]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object PRCI {
|
case class CoreplexLocalInterrupterConfig(beatBytes: Int, address: BigInt = 0x44000000) {
|
||||||
def msip(hart: Int) = hart * msipBytes
|
def msipOffset(hart: Int) = hart * msipBytes
|
||||||
def timecmp(hart: Int) = 0x4000 + hart * timecmpBytes
|
def msipAddress(hart: Int) = address + msipOffset(hart)
|
||||||
def time = 0xbff8
|
def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
|
||||||
|
def timecmpAddress(hart: Int) = address + timecmpOffset(hart)
|
||||||
|
def timeOffset = 0xbff8
|
||||||
|
def timeAddress = address + timeOffset
|
||||||
def msipBytes = 4
|
def msipBytes = 4
|
||||||
def timecmpBytes = 8
|
def timecmpBytes = 8
|
||||||
def size = 0xc000
|
def size = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MixCoreplexLocalInterrupterParameters {
|
||||||
|
val params: (CoreplexLocalInterrupterConfig, Parameters)
|
||||||
|
val c = params._1
|
||||||
|
implicit val p = params._2
|
||||||
|
}
|
||||||
|
|
||||||
|
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
|
||||||
|
val tiles = Vec(p(NTiles), new CoreplexLocalInterrupts).asOutput
|
||||||
|
val rtcTick = Bool(INPUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters {
|
||||||
|
val io: CoreplexLocalInterrupterBundle
|
||||||
|
|
||||||
|
val timeWidth = 64
|
||||||
|
val time = Reg(init=UInt(0, width = timeWidth))
|
||||||
|
when (io.rtcTick) { time := time + UInt(1) }
|
||||||
|
|
||||||
|
val timecmp = Seq.fill(p(NTiles)) { Reg(UInt(width = timeWidth)) }
|
||||||
|
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
||||||
|
|
||||||
|
for ((tile, i) <- io.tiles zipWithIndex) {
|
||||||
|
tile.msip := ipi(i)(0)
|
||||||
|
tile.mtip := time >= timecmp(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
def pad = RegField(8) // each use is a new field
|
||||||
|
val ipi_fields = ipi.map(r => Seq(RegField(1, r), RegField(7), pad, pad, pad)).flatten
|
||||||
|
val timecmp_fields = timecmp.map(RegField.bytes(_)).flatten
|
||||||
|
val time_fields = Seq.fill(c.timeOffset % c.beatBytes)(pad) ++ RegField.bytes(time)
|
||||||
|
|
||||||
|
/* 0000 msip hart 0
|
||||||
|
* 0004 msip hart 1
|
||||||
|
* 4000 mtimecmp hart 0 lo
|
||||||
|
* 4004 mtimecmp hart 0 hi
|
||||||
|
* 4008 mtimecmp hart 1 lo
|
||||||
|
* 400c mtimecmp hart 1 hi
|
||||||
|
* bff8 mtime lo
|
||||||
|
* bffc mtime hi
|
||||||
|
*/
|
||||||
|
val ipi_base = 0
|
||||||
|
val timecmp_base = c.timecmpOffset(0) / c.beatBytes
|
||||||
|
val time_base = c.timeOffset / c.beatBytes
|
||||||
|
|
||||||
|
regmap((
|
||||||
|
RegField.split(ipi_fields, ipi_base, c.beatBytes) ++
|
||||||
|
RegField.split(timecmp_fields, timecmp_base, c.beatBytes) ++
|
||||||
|
RegField.split(time_fields, time_base, c.beatBytes)):_*)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Power, Reset, Clock, Interrupt */
|
/** Power, Reset, Clock, Interrupt */
|
||||||
class PRCI(implicit val p: Parameters) extends Module
|
// Magic TL2 Incantation to create a TL2 Slave
|
||||||
with HasTileLinkParameters
|
class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p: Parameters)
|
||||||
with HasAddrMapParameters {
|
extends TLRegisterRouter(c.address, 0, c.size, None, c.beatBytes, false)(
|
||||||
val io = new Bundle {
|
new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)(
|
||||||
val tl = new ClientUncachedTileLinkIO().flip
|
new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule)
|
||||||
val tiles = Vec(p(NTiles), new PRCITileIO)
|
|
||||||
val rtcTick = Bool(INPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val timeWidth = 64
|
|
||||||
val timecmp = Reg(Vec(p(NTiles), UInt(width = timeWidth)))
|
|
||||||
val time = Reg(init=UInt(0, timeWidth))
|
|
||||||
when (io.rtcTick) { time := time + UInt(1) }
|
|
||||||
|
|
||||||
val ipi = Reg(init=Vec.fill(p(NTiles))(UInt(0, 32)))
|
|
||||||
|
|
||||||
val acq = Queue(io.tl.acquire, 1)
|
|
||||||
val addr = acq.bits.full_addr()(log2Ceil(PRCI.size)-1,0)
|
|
||||||
val read = acq.bits.isBuiltInType(Acquire.getType)
|
|
||||||
val rdata = Wire(init=UInt(0))
|
|
||||||
io.tl.grant.valid := acq.valid
|
|
||||||
acq.ready := io.tl.grant.ready
|
|
||||||
io.tl.grant.bits := Grant(
|
|
||||||
is_builtin_type = Bool(true),
|
|
||||||
g_type = acq.bits.getBuiltInGrantType(),
|
|
||||||
client_xact_id = acq.bits.client_xact_id,
|
|
||||||
manager_xact_id = UInt(0),
|
|
||||||
addr_beat = UInt(0),
|
|
||||||
data = rdata)
|
|
||||||
|
|
||||||
when (addr(log2Floor(PRCI.time))) {
|
|
||||||
require(log2Floor(PRCI.timecmp(p(NTiles)-1)) < log2Floor(PRCI.time))
|
|
||||||
rdata := store(Seq(time), acq.bits, io.tl.grant.fire())
|
|
||||||
}.elsewhen (addr >= PRCI.timecmp(0)) {
|
|
||||||
rdata := store(timecmp, acq.bits, io.tl.grant.fire())
|
|
||||||
}.otherwise {
|
|
||||||
rdata := store(ipi, acq.bits, io.tl.grant.fire()) & Fill(tlDataBits/32, UInt(1, 32))
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((tile, i) <- io.tiles zipWithIndex) {
|
|
||||||
tile.interrupts.msip := ipi(i)(0)
|
|
||||||
tile.interrupts.mtip := time >= timecmp(i)
|
|
||||||
tile.reset := reset
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO generalize these to help other TL slaves
|
|
||||||
def load(v: Seq[UInt], acq: Acquire): UInt = {
|
|
||||||
val w = v.head.getWidth
|
|
||||||
val a = acq.full_addr()
|
|
||||||
require(isPow2(w) && w >= 8)
|
|
||||||
if (w > tlDataBits) {
|
|
||||||
(v(a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))) >> a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes)))(tlDataBits-1,0)
|
|
||||||
} else {
|
|
||||||
val row: Seq[UInt] = for (i <- 0 until v.size by tlDataBits/w)
|
|
||||||
yield Cat(v.slice(i, i + tlDataBits/w).reverse)
|
|
||||||
if (row.size == 1) row.head
|
|
||||||
else row(a(log2Ceil(w/8*v.size)-1,log2Ceil(tlDataBytes)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def store(v: Seq[UInt], acq: Acquire, en: Bool): UInt = {
|
|
||||||
val w = v.head.getWidth
|
|
||||||
require(isPow2(w) && w >= 8)
|
|
||||||
val a = acq.full_addr()
|
|
||||||
val rdata = load(v, acq)
|
|
||||||
val wdata = (acq.data & acq.full_wmask()) | (rdata & ~acq.full_wmask())
|
|
||||||
when (en && acq.isBuiltInType(Acquire.putType)) {
|
|
||||||
if (w <= tlDataBits) {
|
|
||||||
val word =
|
|
||||||
if (tlDataBits/w >= v.size) UInt(0)
|
|
||||||
else a(log2Up(w/8*v.size)-1,log2Up(tlDataBytes))
|
|
||||||
for (i <- 0 until v.size) when (word === i/(tlDataBits/w)) {
|
|
||||||
val base = i % (tlDataBits/w)
|
|
||||||
v(i) := wdata >> (w * (i % (tlDataBits/w)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val i = a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))
|
|
||||||
val mask = FillInterleaved(tlDataBits, UIntToOH(a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes))))
|
|
||||||
v(i) := (wdata & mask) | (v(i) & ~mask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rdata
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,9 +4,46 @@ import Chisel._
|
|||||||
import unittest.UnitTest
|
import unittest.UnitTest
|
||||||
import junctions._
|
import junctions._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
|
|
||||||
|
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], beatBytes: Int = 4) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
|
address = List(AddressSet(base, size-1)),
|
||||||
|
regionType = RegionType.UNCACHED,
|
||||||
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
fifoId = Some(0)))
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
|
||||||
|
val contents = contentsDelayed
|
||||||
|
require (contents.size <= size)
|
||||||
|
|
||||||
|
val in = io.in(0)
|
||||||
|
val edge = node.edgesIn(0)
|
||||||
|
|
||||||
|
val words = (contents ++ Seq.fill(size-contents.size)(0.toByte)).grouped(beatBytes).toSeq
|
||||||
|
val bigs = words.map(_.foldRight(BigInt(0)){ case (x,y) => (x.toInt & 0xff) | y << 8})
|
||||||
|
val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))
|
||||||
|
|
||||||
|
in.d.valid := in.a.valid
|
||||||
|
in.a.ready := in.d.ready
|
||||||
|
|
||||||
|
val index = in.a.bits.addr_hi(log2Ceil(size/beatBytes)-1,0)
|
||||||
|
in.d.bits := edge.AccessAck(in.a.bits, UInt(0), rom(index))
|
||||||
|
|
||||||
|
// Tie off unused channels
|
||||||
|
in.b.valid := Bool(false)
|
||||||
|
in.c.ready := Bool(true)
|
||||||
|
in.e.ready := Bool(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module
|
class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module
|
||||||
with HasTileLinkParameters
|
with HasTileLinkParameters
|
||||||
with HasAddrMapParameters {
|
with HasAddrMapParameters {
|
||||||
|
118
src/main/scala/uncore/tilelink2/AddressDecoder.scala
Normal file
118
src/main/scala/uncore/tilelink2/AddressDecoder.scala
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import scala.math.{max,min}
|
||||||
|
|
||||||
|
object AddressDecoder
|
||||||
|
{
|
||||||
|
type Port = Seq[AddressSet]
|
||||||
|
type Ports = Seq[Port]
|
||||||
|
type Partition = Ports
|
||||||
|
type Partitions = Seq[Partition]
|
||||||
|
|
||||||
|
val addressOrder = Ordering.ordered[AddressSet]
|
||||||
|
val portOrder = Ordering.Iterable(addressOrder)
|
||||||
|
val partitionOrder = Ordering.Iterable(portOrder)
|
||||||
|
|
||||||
|
// Find the minimum subset of bits needed to disambiguate port addresses.
|
||||||
|
// ie: inspecting only the bits in the output, you can look at an address
|
||||||
|
// and decide to which port (outer Seq) the address belongs.
|
||||||
|
def apply(ports: Ports): BigInt = if (ports.size <= 1) 0 else {
|
||||||
|
// Every port must have at least one address!
|
||||||
|
ports.foreach { p => require (!p.isEmpty) }
|
||||||
|
// Verify the user did not give us an impossible problem
|
||||||
|
ports.combinations(2).foreach { case Seq(x, y) =>
|
||||||
|
x.foreach { a => y.foreach { b =>
|
||||||
|
require (!a.overlaps(b)) // it must be possible to disambiguate addresses!
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
val maxBits = log2Ceil(ports.map(_.map(_.max).max).max + 1)
|
||||||
|
val bits = (0 until maxBits).map(BigInt(1) << _).toSeq
|
||||||
|
val selected = recurse(Seq(ports.map(_.sorted).sorted(portOrder)), bits)
|
||||||
|
selected.reduceLeft(_ | _)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A simpler version that works for a Seq[Int]
|
||||||
|
def apply(keys: Seq[Int]): Int = {
|
||||||
|
val ports = keys.map(b => Seq(AddressSet(b, 0)))
|
||||||
|
apply(ports).toInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// The algorithm has a set of partitions, discriminated by the selected bits.
|
||||||
|
// Each partion has a set of ports, listing all addresses that lead to that port.
|
||||||
|
// Seq[Seq[Seq[AddressSet]]]
|
||||||
|
// ^^^^^^^^^^^^^^^ set of addresses that are routed out this port
|
||||||
|
// ^^^ the list of ports
|
||||||
|
// ^^^ cases already distinguished by the selected bits thus far
|
||||||
|
//
|
||||||
|
// Solving this problem is NP-hard, so we use a simple greedy heuristic:
|
||||||
|
// pick the bit which minimizes the number of ports in each partition
|
||||||
|
// as a secondary goal, reduce the number of AddressSets within a partition
|
||||||
|
|
||||||
|
val bigValue = 100000
|
||||||
|
def bitScore(partitions: Partitions): Int = {
|
||||||
|
val maxPortsPerPartition = partitions.map(_.size).max
|
||||||
|
val maxSetsPerPartition = partitions.map(_.map(_.size).sum).max
|
||||||
|
maxPortsPerPartition * bigValue + maxSetsPerPartition
|
||||||
|
}
|
||||||
|
|
||||||
|
def partitionPort(port: Port, bit: BigInt): (Port, Port) = {
|
||||||
|
val addr_a = AddressSet(0, ~bit)
|
||||||
|
val addr_b = AddressSet(bit, ~bit)
|
||||||
|
// The addresses were sorted, so the filtered addresses are still sorted
|
||||||
|
val subset_a = port.filter(_.overlaps(addr_a))
|
||||||
|
val subset_b = port.filter(_.overlaps(addr_b))
|
||||||
|
(subset_a, subset_b)
|
||||||
|
}
|
||||||
|
|
||||||
|
def partitionPorts(ports: Ports, bit: BigInt): (Ports, Ports) = {
|
||||||
|
val partitioned_ports = ports.map(p => partitionPort(p, bit))
|
||||||
|
// because partitionPort dropped AddresSets, the ports might no longer be sorted
|
||||||
|
val case_a_ports = partitioned_ports.map(_._1).filter(!_.isEmpty).sorted(portOrder)
|
||||||
|
val case_b_ports = partitioned_ports.map(_._2).filter(!_.isEmpty).sorted(portOrder)
|
||||||
|
(case_a_ports, case_b_ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
def partitionPartitions(partitions: Partitions, bit: BigInt): Partitions = {
|
||||||
|
val partitioned_partitions = partitions.map(p => partitionPorts(p, bit))
|
||||||
|
val case_a_partitions = partitioned_partitions.map(_._1)
|
||||||
|
val case_b_partitions = partitioned_partitions.map(_._2)
|
||||||
|
val new_partitions = (case_a_partitions ++ case_b_partitions).sorted(partitionOrder)
|
||||||
|
// Prevent combinational memory explosion; if two partitions are equal, keep only one
|
||||||
|
// Note: AddressSets in a port are sorted, and ports in a partition are sorted.
|
||||||
|
// This makes it easy to structurally compare two partitions for equality
|
||||||
|
val keep = (new_partitions.init zip new_partitions.tail) filter { case (a,b) => partitionOrder.compare(a,b) != 0 } map { _._2 }
|
||||||
|
new_partitions.head +: keep
|
||||||
|
}
|
||||||
|
|
||||||
|
// requirement: ports have sorted addresses and are sorted lexicographically
|
||||||
|
val debug = false
|
||||||
|
def recurse(partitions: Partitions, bits: Seq[BigInt]): Seq[BigInt] = {
|
||||||
|
if (debug) {
|
||||||
|
println("Partitioning:")
|
||||||
|
partitions.foreach { partition =>
|
||||||
|
println(" Partition:")
|
||||||
|
partition.foreach { port =>
|
||||||
|
print(" ")
|
||||||
|
port.foreach { a => print(s" ${a}") }
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val candidates = bits.map { bit =>
|
||||||
|
val result = partitionPartitions(partitions, bit)
|
||||||
|
val score = bitScore(result)
|
||||||
|
(score, bit, result)
|
||||||
|
}
|
||||||
|
val (bestScore, bestBit, bestPartitions) = candidates.min(Ordering.by[(Int, BigInt, Partitions), Int](_._1))
|
||||||
|
if (debug) println("=> Selected bit 0x%x".format(bestBit))
|
||||||
|
if (bestScore < 2*bigValue) {
|
||||||
|
if (debug) println("---")
|
||||||
|
Seq(bestBit)
|
||||||
|
} else {
|
||||||
|
bestBit +: recurse(bestPartitions, bits.filter(_ != bestBit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -146,7 +146,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
|
|||||||
val dFragnum = out.d.bits.source(fragmentBits-1, 0)
|
val dFragnum = out.d.bits.source(fragmentBits-1, 0)
|
||||||
val dFirst = acknum === UInt(0)
|
val dFirst = acknum === UInt(0)
|
||||||
val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1)
|
val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1)
|
||||||
val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Ceil(maxDownSize))
|
val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Up(maxDownSize))
|
||||||
val dHasData = edgeOut.hasData(out.d.bits)
|
val dHasData = edgeOut.hasData(out.d.bits)
|
||||||
|
|
||||||
// calculate new acknum
|
// calculate new acknum
|
||||||
@ -209,7 +209,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
|
|||||||
val aOrig = in.a.bits.size
|
val aOrig = in.a.bits.size
|
||||||
val aFrag = Mux(aOrig > limit, limit, aOrig)
|
val aFrag = Mux(aOrig > limit, limit, aOrig)
|
||||||
val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize))
|
val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize))
|
||||||
val aFragOH1 = UIntToOH1(aFrag, log2Ceil(maxDownSize))
|
val aFragOH1 = UIntToOH1(aFrag, log2Up(maxDownSize))
|
||||||
val aHasData = node.edgesIn(0).hasData(in.a.bits)
|
val aHasData = node.edgesIn(0).hasData(in.a.bits)
|
||||||
val aMask = Mux(aHasData, UInt(0), aFragOH1)
|
val aMask = Mux(aHasData, UInt(0), aFragOH1)
|
||||||
|
|
||||||
|
@ -32,22 +32,36 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
|
|||||||
val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
|
val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
|
||||||
|
|
||||||
if (supportManagers && !smartManagers) {
|
if (supportManagers && !smartManagers) {
|
||||||
|
// State of the Hint bypass
|
||||||
|
val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
|
||||||
|
val hintHoldsD = RegInit(Bool(false))
|
||||||
|
val outerHoldsD = counter =/= UInt(0)
|
||||||
|
// Only one of them can hold it
|
||||||
|
assert (!hintHoldsD || !outerHoldsD)
|
||||||
|
|
||||||
|
// Count outer D beats
|
||||||
|
val beats1 = edgeOut.numBeats1(out.d.bits)
|
||||||
|
when (out.d.fire()) { counter := Mux(outerHoldsD, counter - UInt(1), beats1) }
|
||||||
|
|
||||||
|
// Who wants what?
|
||||||
val address = edgeIn.address(in.a.bits)
|
val address = edgeIn.address(in.a.bits)
|
||||||
val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true)
|
val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true)
|
||||||
val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint
|
val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint
|
||||||
|
val hintWantsD = in.a.valid && hintBitsAtA
|
||||||
|
val outerWantsD = out.d.valid
|
||||||
|
|
||||||
// Prioritize existing D traffic over HintAck (and finish multibeat xfers)
|
// Prioritize existing D traffic over HintAck (and finish multibeat xfers)
|
||||||
val beats1 = edgeOut.numBeats1(out.d.bits)
|
val hintWinsD = hintHoldsD || (!outerHoldsD && !outerWantsD)
|
||||||
val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
|
hintHoldsD := hintWantsD && hintWinsD && !in.d.ready
|
||||||
val first = counter === UInt(0)
|
// Hint can only hold D b/c it still wants it from last cycle
|
||||||
when (out.d.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
assert (!hintHoldsD || hintWantsD)
|
||||||
|
|
||||||
in.d.valid := out.d.valid || (bypassD && in.a.valid && first)
|
in.d.valid := Mux(hintWinsD, hintWantsD, outerWantsD)
|
||||||
out.d.ready := in.d.ready
|
in.d.bits := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)), out.d.bits)
|
||||||
in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)))
|
out.d.ready := in.d.ready && !hintHoldsD
|
||||||
|
|
||||||
in.a.ready := Mux(bypassD, in.d.ready && first && !out.d.valid, out.a.ready)
|
in.a.ready := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready)
|
||||||
out.a.valid := in.a.valid && !bypassD
|
out.a.valid := in.a.valid && !hintBitsAtA
|
||||||
out.a.bits := in.a.bits
|
out.a.bits := in.a.bits
|
||||||
} else {
|
} else {
|
||||||
out.a.valid := in.a.valid
|
out.a.valid := in.a.valid
|
||||||
@ -60,21 +74,35 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (supportClients && !smartClients) {
|
if (supportClients && !smartClients) {
|
||||||
|
// State of the Hint bypass
|
||||||
|
val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
|
||||||
|
val hintHoldsC = RegInit(Bool(false))
|
||||||
|
val innerHoldsC = counter =/= UInt(0)
|
||||||
|
// Only one of them can hold it
|
||||||
|
assert (!hintHoldsC || !innerHoldsC)
|
||||||
|
|
||||||
|
// Count inner C beats
|
||||||
|
val beats1 = edgeIn.numBeats1(in.c.bits)
|
||||||
|
when (in.c.fire()) { counter := Mux(innerHoldsC, counter - UInt(1), beats1) }
|
||||||
|
|
||||||
|
// Who wants what?
|
||||||
val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true)
|
val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true)
|
||||||
val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint
|
val hintBitsAtB = handleB && out.b.bits.opcode === TLMessages.Hint
|
||||||
|
val hintWantsC = out.b.valid && hintBitsAtB
|
||||||
|
val innerWantsC = in.c.valid
|
||||||
|
|
||||||
// Prioritize existing C traffic over HintAck (and finish multibeat xfers)
|
// Prioritize existing C traffic over HintAck (and finish multibeat xfers)
|
||||||
val beats1 = edgeIn.numBeats1(in.c.bits)
|
val hintWinsC = hintHoldsC || (!innerHoldsC && !innerWantsC)
|
||||||
val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
|
hintHoldsC := hintWantsC && hintWinsC && !out.c.ready
|
||||||
val first = counter === UInt(0)
|
// Hint can only hold C b/c it still wants it from last cycle
|
||||||
when (in.c.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
assert (!hintHoldsC || hintWantsC)
|
||||||
|
|
||||||
out.c.valid := in.c.valid || (bypassC && in.b.valid && first)
|
out.c.valid := Mux(hintWinsC, hintWantsC, innerWantsC)
|
||||||
in.c.ready := out.c.ready
|
out.c.bits := Mux(hintWinsC, edgeOut.HintAck(out.b.bits), in.c.bits)
|
||||||
out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits))
|
in.c.ready := out.c.ready && !hintHoldsC
|
||||||
|
|
||||||
out.b.ready := Mux(bypassC, out.c.ready && first && !in.c.valid, in.b.ready)
|
out.b.ready := Mux(hintBitsAtB, hintWinsC && out.c.ready, in.b.ready)
|
||||||
in.b.valid := out.b.valid && !bypassC
|
in.b.valid := out.b.valid && !hintBitsAtB
|
||||||
in.b.bits := out.b.bits
|
in.b.bits := out.b.bits
|
||||||
} else if (bce) {
|
} else if (bce) {
|
||||||
in.b.valid := out.b.valid
|
in.b.valid := out.b.valid
|
||||||
|
@ -49,7 +49,7 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa
|
|||||||
// During conversion from TL Legacy, we won't support Acquire
|
// During conversion from TL Legacy, we won't support Acquire
|
||||||
|
|
||||||
// Must be able to fit TL2 sink_id into TL legacy
|
// Must be able to fit TL2 sink_id into TL legacy
|
||||||
require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId)
|
require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId || !edge.manager.anySupportAcquire)
|
||||||
|
|
||||||
val out = io.out(0)
|
val out = io.out(0)
|
||||||
out.a.valid := io.legacy.acquire.valid
|
out.a.valid := io.legacy.acquire.valid
|
||||||
@ -78,6 +78,8 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa
|
|||||||
MemoryOpConstants.M_XA_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2,
|
MemoryOpConstants.M_XA_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2,
|
||||||
MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2))
|
MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2))
|
||||||
} else {
|
} else {
|
||||||
|
// If no managers support atomics, assert fail if TL1 asks for them
|
||||||
|
assert (!io.legacy.acquire.valid || io.legacy.acquire.bits.a_type =/= Acquire.putAtomicType)
|
||||||
Wire(new TLBundleA(edge.bundle))
|
Wire(new TLBundleA(edge.bundle))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ object TLMonitor
|
|||||||
val last_v = RegNext(irr.valid, Bool(false))
|
val last_v = RegNext(irr.valid, Bool(false))
|
||||||
val last_r = RegNext(irr.ready, Bool(false))
|
val last_r = RegNext(irr.ready, Bool(false))
|
||||||
val last_b = RegNext(irr.bits)
|
val last_b = RegNext(irr.bits)
|
||||||
val bits_changed = irr.bits.toBits === last_b.toBits
|
val bits_changed = irr.bits.asUInt === last_b.asUInt
|
||||||
|
|
||||||
when (last_v && !last_r) {
|
when (last_v && !last_r) {
|
||||||
assert(irr.valid, s"${irr.bits.channelName} had contents that were revoked by the supplier (valid lowered)" + extra)
|
assert(irr.valid, s"${irr.bits.channelName} had contents that were revoked by the supplier (valid lowered)" + extra)
|
||||||
|
@ -76,7 +76,7 @@ class BaseNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(
|
|||||||
def connectOut = bundleOut
|
def connectOut = bundleOut
|
||||||
def connectIn = bundleIn
|
def connectIn = bundleIn
|
||||||
|
|
||||||
protected[tilelink2] def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = {
|
def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = {
|
||||||
val x = this // x := y
|
val x = this // x := y
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
||||||
|
@ -63,7 +63,7 @@ case class TransferSizes(min: Int, max: Int)
|
|||||||
def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
||||||
|
|
||||||
def intersect(x: TransferSizes) =
|
def intersect(x: TransferSizes) =
|
||||||
if (x.max < min || min < x.max) TransferSizes.none
|
if (x.max < min || max < x.min) TransferSizes.none
|
||||||
else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max))
|
else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ object TransferSizes {
|
|||||||
// Base is the base address, and mask are the bits consumed by the manager
|
// Base is the base address, and mask are the bits consumed by the manager
|
||||||
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
||||||
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
||||||
case class AddressSet(base: BigInt, mask: BigInt)
|
case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
||||||
{
|
{
|
||||||
// Forbid misaligned base address (and empty sets)
|
// Forbid misaligned base address (and empty sets)
|
||||||
require ((base & mask) == 0)
|
require ((base & mask) == 0)
|
||||||
@ -97,12 +97,24 @@ case class AddressSet(base: BigInt, mask: BigInt)
|
|||||||
|
|
||||||
// A strided slave serves discontiguous ranges
|
// A strided slave serves discontiguous ranges
|
||||||
def strided = alignment1 != mask
|
def strided = alignment1 != mask
|
||||||
|
|
||||||
|
// AddressSets have one natural Ordering (the containment order)
|
||||||
|
def compare(x: AddressSet) = {
|
||||||
|
val primary = (this.base - x.base).signum // smallest address first
|
||||||
|
val secondary = (x.mask - this.mask).signum // largest mask first
|
||||||
|
if (primary != 0) primary else secondary
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always want to see things in hex
|
||||||
|
override def toString() = "AddressSet(0x%x, 0x%x)".format(base, mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLManagerParameters(
|
case class TLManagerParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
sinkId: IdRange = IdRange(0, 1),
|
sinkId: IdRange = IdRange(0, 1),
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
|
nodePath: Seq[TLBaseNode] = Seq(),
|
||||||
// Supports both Acquire+Release+Finish of these sizes
|
// Supports both Acquire+Release+Finish of these sizes
|
||||||
supportsAcquire: TransferSizes = TransferSizes.none,
|
supportsAcquire: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||||
@ -183,6 +195,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
|
|||||||
def findFifoId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0))))
|
def findFifoId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0))))
|
||||||
def hasFifoId(address: UInt) = Mux1H(find(address), managers.map(m => Bool(m.fifoId.isDefined)))
|
def hasFifoId(address: UInt) = Mux1H(find(address), managers.map(m => Bool(m.fifoId.isDefined)))
|
||||||
|
|
||||||
|
lazy val addressMask = AddressDecoder(managers.map(_.address))
|
||||||
// !!! need a cheaper version of find, where we assume a valid address match exists
|
// !!! need a cheaper version of find, where we assume a valid address match exists
|
||||||
|
|
||||||
// Does this Port manage this ID/address?
|
// Does this Port manage this ID/address?
|
||||||
@ -207,7 +220,8 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class TLClientParameters(
|
case class TLClientParameters(
|
||||||
sourceId: IdRange = IdRange(0,1),
|
sourceId: IdRange = IdRange(0,1),
|
||||||
|
nodePath: Seq[TLBaseNode] = Seq(),
|
||||||
// Supports both Probe+Grant of these sizes
|
// Supports both Probe+Grant of these sizes
|
||||||
supportsProbe: TransferSizes = TransferSizes.none,
|
supportsProbe: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||||
|
@ -105,6 +105,28 @@ object RegField
|
|||||||
bb.d := data
|
bb.d := data
|
||||||
Bool(true)
|
Bool(true)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// Split a large register into a sequence of byte fields
|
||||||
|
// The bytes can be individually written, as they are one byte per field
|
||||||
|
def bytes(x: UInt): Seq[RegField] = {
|
||||||
|
require (x.getWidth % 8 == 0)
|
||||||
|
val bytes = Seq.tabulate(x.getWidth/8) { i => x(8*(i+1)-1, 8*i) }
|
||||||
|
val wires = bytes.map { b => Wire(init = b) }
|
||||||
|
x := Cat(wires.reverse)
|
||||||
|
Seq.tabulate(x.getWidth/8) { i =>
|
||||||
|
RegField(8, bytes(i), RegWriteFn { (valid, data) =>
|
||||||
|
when (valid) { wires(i) := data }
|
||||||
|
Bool(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide a long sequence of RegFields into a maximum sized registers
|
||||||
|
// Your input RegFields may not cross a beatBytes boundary!
|
||||||
|
def split(fields: Seq[RegField], base: Int, beatBytes: Int = 4): Seq[RegField.Map] = {
|
||||||
|
val offsets = fields.map(_.width).scanLeft(0)(_ + _).init
|
||||||
|
(offsets zip fields).groupBy(_._1 / (beatBytes*8)).toList.map(r => (r._1 + base, r._2.map(_._2)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait HasRegMap
|
trait HasRegMap
|
||||||
|
@ -28,8 +28,8 @@ class RegMapperOutput(params: RegMapperParams) extends GenericParameterizedBundl
|
|||||||
object RegMapper
|
object RegMapper
|
||||||
{
|
{
|
||||||
// Create a generic register-based device
|
// Create a generic register-based device
|
||||||
def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
def apply(bytes: Int, concurrency: Option[Int], undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
||||||
val regmap = mapping.toList
|
val regmap = mapping.toList.filter(!_._2.isEmpty)
|
||||||
require (!regmap.isEmpty)
|
require (!regmap.isEmpty)
|
||||||
|
|
||||||
// Ensure no register appears twice
|
// Ensure no register appears twice
|
||||||
@ -37,15 +37,31 @@ object RegMapper
|
|||||||
require (reg1 != reg2)
|
require (reg1 != reg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
|
// Convert to and from Bits
|
||||||
val flat = regmap.map { case (reg, fields) =>
|
def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] =
|
||||||
val offsets = fields.scanLeft(0)(_ + _.width).init
|
if (x == 0) tail.reverse else toBits(x >> 1, ((x & 1) == 1) :: tail)
|
||||||
(offsets zip fields) map { case (o, f) => (reg, o, f) }
|
def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 }
|
||||||
}.flatten
|
|
||||||
require (!flat.isEmpty)
|
|
||||||
|
|
||||||
|
// Find the minimal mask that can decide the register map
|
||||||
|
val mask = AddressDecoder(regmap.map(_._1))
|
||||||
|
val maskFilter = toBits(mask)
|
||||||
|
val maskBits = maskFilter.filter(x => x).size
|
||||||
|
|
||||||
|
// Calculate size and indexes into the register map
|
||||||
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
||||||
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
||||||
|
val regSize = 1 << maskBits
|
||||||
|
def regIndexI(x: Int) = ofBits((maskFilter zip toBits(x)).filter(_._1).map(_._2))
|
||||||
|
def regIndexU(x: UInt) = if (maskBits == 0) UInt(0) else
|
||||||
|
Cat((maskFilter zip x.toBools).filter(_._1).map(_._2).reverse)
|
||||||
|
|
||||||
|
// Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField)
|
||||||
|
val flat = regmap.map { case (reg, fields) =>
|
||||||
|
val offsets = fields.scanLeft(0)(_ + _.width).init
|
||||||
|
val index = regIndexI(reg)
|
||||||
|
// println("mapping 0x%x -> 0x%x for 0x%x/%d".format(reg, index, mask, maskBits))
|
||||||
|
(offsets zip fields) map { case (o, f) => (index, o, f) }
|
||||||
|
}.flatten
|
||||||
|
|
||||||
val out = Wire(Irrevocable(new RegMapperOutput(params)))
|
val out = Wire(Irrevocable(new RegMapperOutput(params)))
|
||||||
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
||||||
@ -69,13 +85,13 @@ object RegMapper
|
|||||||
val woready = Wire(Vec(flat.size, Bool()))
|
val woready = Wire(Vec(flat.size, Bool()))
|
||||||
|
|
||||||
// Per-register list of all control signals needed for data to flow
|
// Per-register list of all control signals needed for data to flow
|
||||||
val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
|
|
||||||
// The output values for each register
|
// The output values for each register
|
||||||
val dataOut = Array.tabulate(endIndex) { _ => UInt(0) }
|
val dataOut = Array.tabulate(regSize) { _ => UInt(0) }
|
||||||
|
|
||||||
// Which bits are touched?
|
// Which bits are touched?
|
||||||
val frontMask = FillInterleaved(8, front.bits.mask)
|
val frontMask = FillInterleaved(8, front.bits.mask)
|
||||||
@ -110,8 +126,10 @@ object RegMapper
|
|||||||
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
||||||
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
||||||
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
||||||
val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index))
|
val iindex = regIndexU(front.bits.index)
|
||||||
val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index))
|
val oindex = regIndexU(back .bits.index)
|
||||||
|
val iready = Mux(front.bits.read, rifireMux(iindex), wifireMux(iindex))
|
||||||
|
val oready = Mux(back .bits.read, rofireMux(oindex), wofireMux(oindex))
|
||||||
|
|
||||||
// Connect the pipeline
|
// Connect the pipeline
|
||||||
in.ready := front.ready && iready
|
in.ready := front.ready && iready
|
||||||
@ -120,11 +138,11 @@ object RegMapper
|
|||||||
out.valid := back.valid && oready
|
out.valid := back.valid && oready
|
||||||
|
|
||||||
// Which register is touched?
|
// Which register is touched?
|
||||||
val frontSel = UIntToOH(front.bits.index)
|
val frontSel = UIntToOH(iindex)
|
||||||
val backSel = UIntToOH(back.bits.index)
|
val backSel = UIntToOH(oindex)
|
||||||
|
|
||||||
// Include the per-register one-hot selected criteria
|
// Include the per-register one-hot selected criteria
|
||||||
for (reg <- 0 until endIndex) {
|
for (reg <- 0 until regSize) {
|
||||||
rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg)
|
rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg)
|
||||||
wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg)
|
wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg)
|
||||||
rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg)
|
rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg)
|
||||||
@ -141,7 +159,7 @@ object RegMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.bits.read := back.bits.read
|
out.bits.read := back.bits.read
|
||||||
out.bits.data := Vec(dataOut)(back.bits.index)
|
out.bits.data := Vec(dataOut)(oindex)
|
||||||
out.bits.extra := back.bits.extra
|
out.bits.extra := back.bits.extra
|
||||||
|
|
||||||
(endIndex, out)
|
(endIndex, out)
|
||||||
|
@ -4,7 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4)
|
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true)
|
||||||
extends TLManagerNode(beatBytes, TLManagerParameters(
|
extends TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = Seq(address),
|
address = Seq(address),
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
@ -25,7 +25,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
val baseEnd = 0
|
val baseEnd = 0
|
||||||
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
||||||
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
|
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
|
||||||
val (addrLoEnd, addrLoOff) = (log2Ceil(beatBytes) + sourceEnd, sourceEnd)
|
val (addrLoEnd, addrLoOff) = (log2Up(beatBytes) + sourceEnd, sourceEnd)
|
||||||
|
|
||||||
val params = RegMapperParams(log2Up(address.mask+1), beatBytes, addrLoEnd)
|
val params = RegMapperParams(log2Up(address.mask+1), beatBytes, addrLoEnd)
|
||||||
val in = Wire(Decoupled(new RegMapperInput(params)))
|
val in = Wire(Decoupled(new RegMapperInput(params)))
|
||||||
@ -36,7 +36,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
||||||
|
|
||||||
// Invoke the register map builder
|
// Invoke the register map builder
|
||||||
val (endIndex, out) = RegMapper(beatBytes, concurrency, in, mapping:_*)
|
val (endIndex, out) = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*)
|
||||||
|
|
||||||
// All registers must fit inside the device address space
|
// All registers must fit inside the device address space
|
||||||
require (address.mask >= (endIndex-1)*beatBytes)
|
require (address.mask >= (endIndex-1)*beatBytes)
|
||||||
@ -67,17 +67,17 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
|
|
||||||
object TLRegisterNode
|
object TLRegisterNode
|
||||||
{
|
{
|
||||||
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) =
|
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true) =
|
||||||
new TLRegisterNode(address, concurrency, beatBytes)
|
new TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These convenience methods below combine to make it possible to create a TL2
|
// These convenience methods below combine to make it possible to create a TL2
|
||||||
// register mapped device from a totally abstract register mapped device.
|
// register mapped device from a totally abstract register mapped device.
|
||||||
// See GPIO.scala in this directory for an example
|
// See GPIO.scala in this directory for an example
|
||||||
|
|
||||||
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int) extends LazyModule
|
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLRegisterNode(address, concurrency, beatBytes)
|
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||||
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts)
|
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
||||||
(base: BigInt, interrupts: Int = 0, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4)
|
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Option[Int] = None, val beatBytes: Int = 4, undefZero: Boolean = true)
|
||||||
(bundleBuilder: TLRegBundleArg => B)
|
(bundleBuilder: TLRegBundleArg => B)
|
||||||
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
||||||
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes)
|
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero)
|
||||||
{
|
{
|
||||||
require (isPow2(size))
|
require (isPow2(size))
|
||||||
// require (size >= 4096) ... not absolutely required, but highly recommended
|
// require (size >= 4096) ... not absolutely required, but highly recommended
|
||||||
|
@ -9,6 +9,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule
|
|||||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = List(address),
|
address = List(address),
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
|
executable = true,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
supportsPutFull = TransferSizes(1, beatBytes),
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
|
@ -5,13 +5,17 @@ import Chisel._
|
|||||||
import cde.{Parameters}
|
import cde.{Parameters}
|
||||||
|
|
||||||
/** This black-boxes an Async Reset
|
/** This black-boxes an Async Reset
|
||||||
* Reg.
|
* (or Set)
|
||||||
|
* Register.
|
||||||
*
|
*
|
||||||
* Because Chisel doesn't support
|
* Because Chisel doesn't support
|
||||||
* parameterized black boxes,
|
* parameterized black boxes,
|
||||||
* we unfortunately have to
|
* we unfortunately have to
|
||||||
* instantiate a number of these.
|
* instantiate a number of these.
|
||||||
*
|
*
|
||||||
|
* We also have to hard-code the set/
|
||||||
|
* reset behavior.
|
||||||
|
*
|
||||||
* Do not confuse an asynchronous
|
* Do not confuse an asynchronous
|
||||||
* reset signal with an asynchronously
|
* reset signal with an asynchronously
|
||||||
* reset reg. You should still
|
* reset reg. You should still
|
||||||
@ -22,29 +26,25 @@ import cde.{Parameters}
|
|||||||
* @param q Data Output
|
* @param q Data Output
|
||||||
* @param clk Clock Input
|
* @param clk Clock Input
|
||||||
* @param rst Reset Input
|
* @param rst Reset Input
|
||||||
*
|
* @param en Write Enable Input
|
||||||
* @param init Value to write at Reset.
|
|
||||||
* This is a constant,
|
|
||||||
* but this construction
|
|
||||||
* will likely make backend flows
|
|
||||||
* and lint tools unhappy.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AsyncResetReg extends BlackBox {
|
abstract class AbstractBBReg extends BlackBox {
|
||||||
|
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val d = Bool(INPUT)
|
val d = Bool(INPUT)
|
||||||
val q = Bool(OUTPUT)
|
val q = Bool(OUTPUT)
|
||||||
|
val en = Bool(INPUT)
|
||||||
|
|
||||||
val clk = Clock(INPUT)
|
val clk = Clock(INPUT)
|
||||||
val rst = Bool(INPUT)
|
val rst = Bool(INPUT)
|
||||||
|
|
||||||
val init = Bool(INPUT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AsyncResetReg extends AbstractBBReg
|
||||||
|
class AsyncSetReg extends AbstractBBReg
|
||||||
|
|
||||||
class SimpleRegIO(val w: Int) extends Bundle{
|
class SimpleRegIO(val w: Int) extends Bundle{
|
||||||
|
|
||||||
@ -55,29 +55,56 @@ class SimpleRegIO(val w: Int) extends Bundle{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncResetRegVec(val w: Int, val init: Int) extends Module {
|
class AsyncResetRegVec(val w: Int, val init: BigInt) extends Module {
|
||||||
|
|
||||||
val io = new SimpleRegIO(w)
|
val io = new SimpleRegIO(w)
|
||||||
|
|
||||||
val bb_q = Wire(UInt(width = w))
|
val bb_d = Mux(io.en, io.d, io.q)
|
||||||
val bb_d = Wire(UInt(width = w))
|
|
||||||
|
|
||||||
val init_val = Wire(UInt(width = w))
|
val async_regs: List[AbstractBBReg] = List.tabulate(w)(
|
||||||
init_val := UInt(init, width = w)
|
i => Module (
|
||||||
|
if (((init >> i) % 2) > 0)
|
||||||
val async_regs = List.fill(w)(Module (new AsyncResetReg))
|
new AsyncSetReg
|
||||||
|
else
|
||||||
bb_q := (async_regs.map(_.io.q)).asUInt()
|
new AsyncResetReg)
|
||||||
bb_d := Mux(io.en , io.d , bb_q)
|
)
|
||||||
|
|
||||||
io.q := bb_q
|
|
||||||
|
|
||||||
|
io.q := async_regs.map(_.io.q).asUInt
|
||||||
|
|
||||||
for ((reg, idx) <- async_regs.zipWithIndex) {
|
for ((reg, idx) <- async_regs.zipWithIndex) {
|
||||||
reg.io.clk := clock
|
reg.io.clk := clock
|
||||||
reg.io.rst := reset
|
reg.io.rst := reset
|
||||||
reg.io.init := init_val(idx)
|
reg.io.d := bb_d(idx)
|
||||||
reg.io.d := bb_d(idx)
|
reg.io.en := io.en
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object AsyncResetReg {
|
||||||
|
def apply(d: Bool, clk: Clock, rst: Bool, init: Boolean): Bool = {
|
||||||
|
val reg: AbstractBBReg =
|
||||||
|
if (init) Module (new AsyncSetReg)
|
||||||
|
else Module(new AsyncResetReg)
|
||||||
|
reg.io.d := d
|
||||||
|
reg.io.clk := clk
|
||||||
|
reg.io.rst := rst
|
||||||
|
reg.io.en := Bool(true)
|
||||||
|
reg.io.q
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(d: Bool, clk: Clock, rst: Bool): Bool = apply(d, clk, rst, false)
|
||||||
|
|
||||||
|
def apply(updateData: UInt, resetData: BigInt, enable: Bool): UInt = {
|
||||||
|
val w = updateData.getWidth max resetData.bitLength
|
||||||
|
val reg = Module(new AsyncResetRegVec(w, resetData))
|
||||||
|
reg.io.d := updateData
|
||||||
|
reg.io.en := enable
|
||||||
|
reg.io.q
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(updateData: UInt, resetData: BigInt): UInt = apply(updateData, resetData, enable=Bool(true))
|
||||||
|
|
||||||
|
def apply(updateData: UInt, enable: Bool): UInt = apply(updateData, resetData=BigInt(0), enable)
|
||||||
|
|
||||||
|
def apply(updateData: UInt): UInt = apply(updateData, resetData=BigInt(0), enable=Bool(true))
|
||||||
|
}
|
||||||
|
@ -11,10 +11,10 @@ class TestHarness(implicit val p: Parameters) extends Module {
|
|||||||
val success = Bool(OUTPUT)
|
val success = Bool(OUTPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
p(NCoreplexExtClients).assign(0)
|
val l1params = p.alterPartial({
|
||||||
p(ConfigString).assign("")
|
case NCoreplexExtClients => 0
|
||||||
|
case ConfigString => ""
|
||||||
val l1params = p.alterPartial({ case uncore.tilelink.TLId => "L1toL2" })
|
case uncore.tilelink.TLId => "L1toL2" })
|
||||||
val tests = Module(new UnitTestSuite()(l1params))
|
val tests = Module(new UnitTestSuite()(l1params))
|
||||||
|
|
||||||
io.success := tests.io.finished
|
io.success := tests.io.finished
|
||||||
|
@ -8,9 +8,10 @@ bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
|
|||||||
$(base_dir)/vsrc/jtag_vpi.v \
|
$(base_dir)/vsrc/jtag_vpi.v \
|
||||||
$(base_dir)/vsrc/AsyncMailbox.v \
|
$(base_dir)/vsrc/AsyncMailbox.v \
|
||||||
$(base_dir)/vsrc/AsyncResetReg.v \
|
$(base_dir)/vsrc/AsyncResetReg.v \
|
||||||
|
$(base_dir)/vsrc/AsyncSetReg.v \
|
||||||
$(base_dir)/vsrc/ClockDivider.v \
|
$(base_dir)/vsrc/ClockDivider.v \
|
||||||
$(base_dir)/vsrc/ClockToSignal.v \
|
$(base_dir)/vsrc/ClockToSignal.v \
|
||||||
$(base_dir)/vsrc/SignalToClock.v \
|
$(base_dir)/vsrc/SignalToClock.v \
|
||||||
|
|
||||||
|
|
||||||
sim_vsrcs = \
|
sim_vsrcs = \
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
* we unfortunately have to
|
* we unfortunately have to
|
||||||
* instantiate a number of these.
|
* instantiate a number of these.
|
||||||
*
|
*
|
||||||
|
* We also have to hard-code the set/reset.
|
||||||
|
*
|
||||||
* Do not confuse an asynchronous
|
* Do not confuse an asynchronous
|
||||||
* reset signal with an asynchronously
|
* reset signal with an asynchronously
|
||||||
* reset reg. You should still
|
* reset reg. You should still
|
||||||
@ -18,32 +20,25 @@
|
|||||||
* @param q Data Output
|
* @param q Data Output
|
||||||
* @param clk Clock Input
|
* @param clk Clock Input
|
||||||
* @param rst Reset Input
|
* @param rst Reset Input
|
||||||
*
|
* @param en Write Enable Input
|
||||||
* @param init Value to write at Reset.
|
|
||||||
* This is a constant,
|
|
||||||
* but this construction
|
|
||||||
* will likely make backend flows
|
|
||||||
* and lint tools unhappy.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module AsyncResetReg (
|
module AsyncResetReg (
|
||||||
input d,
|
input d,
|
||||||
output reg q,
|
output reg q,
|
||||||
|
input en,
|
||||||
|
|
||||||
input clk,
|
input clk,
|
||||||
input rst,
|
input rst);
|
||||||
|
|
||||||
input init);
|
|
||||||
|
|
||||||
always @(posedge clk or posedge rst) begin
|
always @(posedge clk or posedge rst) begin
|
||||||
|
|
||||||
if (rst) begin
|
if (rst) begin
|
||||||
q <= init;
|
q <= 1'b0;
|
||||||
end else begin
|
end else if (en) begin
|
||||||
q <= d;
|
q <= d;
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
47
vsrc/AsyncSetReg.v
Normal file
47
vsrc/AsyncSetReg.v
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/** This black-boxes an Async Set
|
||||||
|
* Reg.
|
||||||
|
*
|
||||||
|
* Because Chisel doesn't support
|
||||||
|
* parameterized black boxes,
|
||||||
|
* we unfortunately have to
|
||||||
|
* instantiate a number of these.
|
||||||
|
*
|
||||||
|
* We also have to hard-code the set/reset.
|
||||||
|
*
|
||||||
|
* Do not confuse an asynchronous
|
||||||
|
* reset signal with an asynchronously
|
||||||
|
* reset reg. You should still
|
||||||
|
* properly synchronize your reset
|
||||||
|
* deassertion.
|
||||||
|
*
|
||||||
|
* @param d Data input
|
||||||
|
* @param q Data Output
|
||||||
|
* @param clk Clock Input
|
||||||
|
* @param rst Reset Input
|
||||||
|
* @param en Write Enable Input
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module AsyncSetReg (
|
||||||
|
input d,
|
||||||
|
output reg q,
|
||||||
|
input en,
|
||||||
|
|
||||||
|
input clk,
|
||||||
|
input rst);
|
||||||
|
|
||||||
|
always @(posedge clk or posedge rst) begin
|
||||||
|
|
||||||
|
if (rst) begin
|
||||||
|
q <= 1'b1;
|
||||||
|
end else if (en) begin
|
||||||
|
q <= d;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
endmodule // AsyncSetReg
|
||||||
|
|
Loading…
Reference in New Issue
Block a user