commit
6ea35125d4
@ -47,6 +47,11 @@ $(output_dir)/%.vpd: $(output_dir)/% $(emu_debug)
|
|||||||
vcd2vpd $@.vcd $@ > /dev/null &
|
vcd2vpd $@.vcd $@ > /dev/null &
|
||||||
./$(emu_debug) +max-cycles=$(timeout_cycles) +verbose -v$@.vcd $< $(disasm) $(patsubst %.vpd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
|
./$(emu_debug) +max-cycles=$(timeout_cycles) +verbose -v$@.vcd $< $(disasm) $(patsubst %.vpd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
|
||||||
|
|
||||||
|
$(output_dir)/%.fst: $(output_dir)/% $(emu_debug)
|
||||||
|
rm -rf $@.vcd && mkfifo $@.vcd
|
||||||
|
vcd2fst -Z $@.vcd $@ &
|
||||||
|
./$(emu_debug) +max-cycles=$(timeout_cycles) +verbose -v$@.vcd $< $(disasm) $(patsubst %.fst,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
|
||||||
|
|
||||||
run: run-asm-tests run-bmark-tests
|
run: run-asm-tests run-bmark-tests
|
||||||
run-debug: run-asm-tests-debug run-bmark-tests-debug
|
run-debug: run-asm-tests-debug run-bmark-tests-debug
|
||||||
run-fast: run-asm-tests-fast run-bmark-tests-fast
|
run-fast: run-asm-tests-fast run-bmark-tests-fast
|
||||||
|
@ -73,7 +73,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
}
|
}
|
||||||
case Rational => {
|
case Rational => {
|
||||||
val wrapper = LazyModule(new RationalRocketTile(c)(pWithExtra))
|
val wrapper = LazyModule(new RationalRocketTile(c)(pWithExtra))
|
||||||
val sink = LazyModule(new TLRationalCrossingSink)
|
val sink = LazyModule(new TLRationalCrossingSink(util.FastToSlow))
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
val source = LazyModule(new TLRationalCrossingSource)
|
||||||
sink.node :=* wrapper.masterNode
|
sink.node :=* wrapper.masterNode
|
||||||
l1tol2.node :=* sink.node
|
l1tol2.node :=* sink.node
|
||||||
|
@ -103,7 +103,7 @@ class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends
|
|||||||
masterNode :=* source.node
|
masterNode :=* source.node
|
||||||
|
|
||||||
val slaveNode = TLRationalInputNode()
|
val slaveNode = TLRationalInputNode()
|
||||||
val sink = LazyModule(new TLRationalCrossingSink)
|
val sink = LazyModule(new TLRationalCrossingSink(util.SlowToFast))
|
||||||
rocket.slaveNode :*= sink.node
|
rocket.slaveNode :*= sink.node
|
||||||
sink.node :*= slaveNode
|
sink.node :*= slaveNode
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ run-$makeTargetName: $$(addprefix $$(output_dir)/, $$(addsuffix .out, $$($makeTa
|
|||||||
|
|
||||||
run-$makeTargetName-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $$($makeTargetName)))
|
run-$makeTargetName-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $$($makeTargetName)))
|
||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
|
|
||||||
|
run-$makeTargetName-fst: $$(addprefix $$(output_dir)/, $$(addsuffix .fst, $$($makeTargetName)))
|
||||||
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.fst,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +81,8 @@ run-$kind-$env-tests: $$(addprefix $$(output_dir)/, $$(addsuffix .out, $suites))
|
|||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
run-$kind-$env-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $suites))
|
run-$kind-$env-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $suites))
|
||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
|
run-$kind-$env-tests-fst: $$(addprefix $$(output_dir)/, $$(addsuffix .fst, $suites))
|
||||||
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.fst,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
run-$kind-$env-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $suites))
|
run-$kind-$env-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $suites))
|
||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
"""} } ).mkString("\n") + s"""
|
"""} } ).mkString("\n") + s"""
|
||||||
@ -85,6 +90,8 @@ run-$kind-tests: $$(addprefix $$(output_dir)/, $$(addsuffix .out, $targets))
|
|||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
run-$kind-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $targets))
|
run-$kind-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $targets))
|
||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.vpd,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
|
run-$kind-tests-fst: $$(addprefix $$(output_dir)/, $$(addsuffix .fst, $targets))
|
||||||
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$(patsubst %.fst,%.out,$$^) /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
run-$kind-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $targets))
|
run-$kind-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $targets))
|
||||||
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED)/i )' $$^ /dev/null | perl -ne 'if(/(.*)/){print "$$$$1\\n\\n"; exit(1) if eof()}'
|
||||||
"""
|
"""
|
||||||
|
@ -7,6 +7,7 @@ import chisel3.internal.sourceinfo.SourceInfo
|
|||||||
import config._
|
import config._
|
||||||
import diplomacy._
|
import diplomacy._
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
|
import util.RationalDirection
|
||||||
|
|
||||||
case object TLMonitorBuilder extends Field[TLMonitorArgs => Option[TLMonitorBase]]
|
case object TLMonitorBuilder extends Field[TLMonitorArgs => Option[TLMonitorBase]]
|
||||||
case object TLFuzzReadyValid extends Field[Boolean]
|
case object TLFuzzReadyValid extends Field[Boolean]
|
||||||
@ -182,20 +183,20 @@ case class TLAsyncSinkNode(depth: Int, sync: Int)
|
|||||||
dFn = { p => p.base.copy(minLatency = sync+1) },
|
dFn = { p => p.base.copy(minLatency = sync+1) },
|
||||||
uFn = { p => TLAsyncManagerPortParameters(depth, p) })
|
uFn = { p => TLAsyncManagerPortParameters(depth, p) })
|
||||||
|
|
||||||
object TLRationalImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeParameters, TLEdgeParameters, TLRationalBundle]
|
object TLRationalImp extends NodeImp[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalEdgeParameters, TLRationalEdgeParameters, TLRationalBundle]
|
||||||
{
|
{
|
||||||
def edgeO(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeParameters = TLEdgeParameters(pd, pu)
|
def edgeO(pd: TLRationalClientPortParameters, pu: TLRationalManagerPortParameters): TLRationalEdgeParameters = TLRationalEdgeParameters(pd, pu)
|
||||||
def edgeI(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeParameters = TLEdgeParameters(pd, pu)
|
def edgeI(pd: TLRationalClientPortParameters, pu: TLRationalManagerPortParameters): TLRationalEdgeParameters = TLRationalEdgeParameters(pd, pu)
|
||||||
|
|
||||||
def bundleO(eo: Seq[TLEdgeParameters]): Vec[TLRationalBundle] = Vec(eo.size, new TLRationalBundle(TLBundleParameters.union(eo.map(_.bundle))))
|
def bundleO(eo: Seq[TLRationalEdgeParameters]): Vec[TLRationalBundle] = Vec(eo.size, new TLRationalBundle(TLBundleParameters.union(eo.map(_.bundle))))
|
||||||
def bundleI(ei: Seq[TLEdgeParameters]): Vec[TLRationalBundle] = Vec(ei.size, new TLRationalBundle(TLBundleParameters.union(ei.map(_.bundle))))
|
def bundleI(ei: Seq[TLRationalEdgeParameters]): Vec[TLRationalBundle] = Vec(ei.size, new TLRationalBundle(TLBundleParameters.union(ei.map(_.bundle))))
|
||||||
|
|
||||||
def colour = "#00ff00" // green
|
def colour = "#00ff00" // green
|
||||||
|
|
||||||
override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLRationalBundle]): TLClientPortParameters =
|
override def mixO(pd: TLRationalClientPortParameters, node: OutwardNode[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]): TLRationalClientPortParameters =
|
||||||
pd.copy(clients = pd.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
|
pd.copy(base = pd.base.copy(clients = pd.base.clients.map { c => c.copy (nodePath = node +: c.nodePath) }))
|
||||||
override def mixI(pu: TLManagerPortParameters, node: InwardNode[TLClientPortParameters, TLManagerPortParameters, TLRationalBundle]): TLManagerPortParameters =
|
override def mixI(pu: TLRationalManagerPortParameters, node: InwardNode[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]): TLRationalManagerPortParameters =
|
||||||
pu.copy(managers = pu.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
|
pu.copy(base = pu.base.copy(managers = pu.base.managers.map { m => m.copy (nodePath = node +: m.nodePath) }))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLRationalIdentityNode() extends IdentityNode(TLRationalImp)
|
case class TLRationalIdentityNode() extends IdentityNode(TLRationalImp)
|
||||||
@ -204,10 +205,10 @@ case class TLRationalInputNode() extends InputNode(TLRationalImp)
|
|||||||
|
|
||||||
case class TLRationalSourceNode()
|
case class TLRationalSourceNode()
|
||||||
extends MixedAdapterNode(TLImp, TLRationalImp)(
|
extends MixedAdapterNode(TLImp, TLRationalImp)(
|
||||||
dFn = { p => p },
|
dFn = { p => TLRationalClientPortParameters(p) },
|
||||||
uFn = { p => p.copy(minLatency = 1) }) // discard cycles from other clock domain
|
uFn = { p => p.base.copy(minLatency = 1) }) // discard cycles from other clock domain
|
||||||
|
|
||||||
case class TLRationalSinkNode()
|
case class TLRationalSinkNode(direction: RationalDirection)
|
||||||
extends MixedAdapterNode(TLRationalImp, TLImp)(
|
extends MixedAdapterNode(TLRationalImp, TLImp)(
|
||||||
dFn = { p => p.copy(minLatency = 1) },
|
dFn = { p => p.base.copy(minLatency = 1) },
|
||||||
uFn = { p => p })
|
uFn = { p => TLRationalManagerPortParameters(direction, p) })
|
||||||
|
@ -5,6 +5,7 @@ package uncore.tilelink2
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import diplomacy._
|
import diplomacy._
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
import util.RationalDirection
|
||||||
|
|
||||||
case class TLManagerParameters(
|
case class TLManagerParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
@ -326,6 +327,14 @@ case class TLAsyncEdgeParameters(client: TLAsyncClientPortParameters, manager: T
|
|||||||
val bundle = TLAsyncBundleParameters(manager.depth, TLBundleParameters(client.base, manager.base))
|
val bundle = TLAsyncBundleParameters(manager.depth, TLBundleParameters(client.base, manager.base))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class TLRationalManagerPortParameters(direction: RationalDirection, base: TLManagerPortParameters)
|
||||||
|
case class TLRationalClientPortParameters(base: TLClientPortParameters)
|
||||||
|
|
||||||
|
case class TLRationalEdgeParameters(client: TLRationalClientPortParameters, manager: TLRationalManagerPortParameters)
|
||||||
|
{
|
||||||
|
val bundle = TLBundleParameters(client.base, manager.base)
|
||||||
|
}
|
||||||
|
|
||||||
object ManagerUnification
|
object ManagerUnification
|
||||||
{
|
{
|
||||||
def apply(managers: Seq[TLManagerParameters]) = {
|
def apply(managers: Seq[TLManagerParameters]) = {
|
||||||
|
@ -27,14 +27,15 @@ class TLRationalCrossingSource(implicit p: Parameters) extends LazyModule
|
|||||||
|
|
||||||
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
val bce = edgeIn.manager.anySupportAcquireB && edgeIn.client.anySupportProbe
|
val bce = edgeIn.manager.anySupportAcquireB && edgeIn.client.anySupportProbe
|
||||||
|
val direction = edgeOut.manager.direction
|
||||||
|
|
||||||
out.a <> ToRational(in.a)
|
out.a <> ToRational(in.a, direction)
|
||||||
in.d <> FromRational(out.d)
|
in.d <> FromRational(out.d, direction.flip)
|
||||||
|
|
||||||
if (bce) {
|
if (bce) {
|
||||||
in.b <> FromRational(out.b)
|
in.b <> FromRational(out.b, direction.flip)
|
||||||
out.c <> ToRational(in.c)
|
out.c <> ToRational(in.c, direction)
|
||||||
out.e <> ToRational(in.e)
|
out.e <> ToRational(in.e, direction)
|
||||||
} else {
|
} else {
|
||||||
in.b.valid := Bool(false)
|
in.b.valid := Bool(false)
|
||||||
in.c.ready := Bool(true)
|
in.c.ready := Bool(true)
|
||||||
@ -50,9 +51,9 @@ class TLRationalCrossingSource(implicit p: Parameters) extends LazyModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TLRationalCrossingSink(implicit p: Parameters) extends LazyModule
|
class TLRationalCrossingSink(direction: RationalDirection = Symmetric)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLRationalSinkNode()
|
val node = TLRationalSinkNode(direction)
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
@ -62,14 +63,15 @@ class TLRationalCrossingSink(implicit p: Parameters) extends LazyModule
|
|||||||
|
|
||||||
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
val bce = edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe
|
val bce = edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe
|
||||||
|
val direction = edgeIn.manager.direction
|
||||||
|
|
||||||
out.a <> FromRational(in.a)
|
out.a <> FromRational(in.a, direction)
|
||||||
in.d <> ToRational(out.d)
|
in.d <> ToRational(out.d, direction.flip)
|
||||||
|
|
||||||
if (bce) {
|
if (bce) {
|
||||||
in.b <> ToRational(out.b)
|
in.b <> ToRational(out.b, direction.flip)
|
||||||
out.c <> FromRational(in.c)
|
out.c <> FromRational(in.c, direction)
|
||||||
out.e <> FromRational(in.e)
|
out.e <> FromRational(in.e, direction)
|
||||||
} else {
|
} else {
|
||||||
out.b.ready := Bool(true)
|
out.b.ready := Bool(true)
|
||||||
out.c.valid := Bool(false)
|
out.c.valid := Bool(false)
|
||||||
@ -98,21 +100,21 @@ object TLRationalCrossingSource
|
|||||||
object TLRationalCrossingSink
|
object TLRationalCrossingSink
|
||||||
{
|
{
|
||||||
// applied to the TL source node; y.node := TLRationalCrossingSink()(x.node)
|
// applied to the TL source node; y.node := TLRationalCrossingSink()(x.node)
|
||||||
def apply()(x: TLRationalOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
def apply(direction: RationalDirection = Symmetric)(x: TLRationalOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
val sink = LazyModule(new TLRationalCrossingSink)
|
val sink = LazyModule(new TLRationalCrossingSink(direction))
|
||||||
sink.node := x
|
sink.node := x
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TLRationalCrossing(implicit p: Parameters) extends LazyModule
|
class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val nodeIn = TLInputNode()
|
val nodeIn = TLInputNode()
|
||||||
val nodeOut = TLOutputNode()
|
val nodeOut = TLOutputNode()
|
||||||
val node = NodeHandle(nodeIn, nodeOut)
|
val node = NodeHandle(nodeIn, nodeOut)
|
||||||
|
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
val source = LazyModule(new TLRationalCrossingSource)
|
||||||
val sink = LazyModule(new TLRationalCrossingSink)
|
val sink = LazyModule(new TLRationalCrossingSink(direction))
|
||||||
|
|
||||||
val _ = (sink.node := source.node) // no monitor
|
val _ = (sink.node := source.node) // no monitor
|
||||||
val in = (source.node := nodeIn)
|
val in = (source.node := nodeIn)
|
||||||
@ -147,35 +149,73 @@ class TLRationalCrossing(implicit p: Parameters) extends LazyModule
|
|||||||
/** Synthesizeable unit tests */
|
/** Synthesizeable unit tests */
|
||||||
import unittest._
|
import unittest._
|
||||||
|
|
||||||
class TLRAMRationalCrossing(implicit p: Parameters) extends LazyModule {
|
class TLRAMRationalCrossingSource(implicit p: Parameters) extends LazyModule {
|
||||||
|
val node = TLRationalOutputNode()
|
||||||
val fuzz = LazyModule(new TLFuzzer(5000))
|
val fuzz = LazyModule(new TLFuzzer(5000))
|
||||||
val model = LazyModule(new TLRAMModel)
|
val model = LazyModule(new TLRAMModel)
|
||||||
val cross = LazyModule(new TLRationalCrossing)
|
|
||||||
val delay = LazyModule(new TLDelayer(0.25))
|
|
||||||
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
|
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
cross.node := TLDelayer(0.25)(TLFragmenter(4, 256)(model.node))
|
node := TLRationalCrossingSource()(TLDelayer(0.25)(model.node))
|
||||||
val monitor1 = (delay.node := cross.node)
|
|
||||||
val monitor2 = (ram.node := delay.node)
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val monitors = monitor1.toList ++ monitor2.toList
|
val io = new Bundle {
|
||||||
|
val finished = Bool(OUTPUT)
|
||||||
|
val out = node.bundleOut
|
||||||
|
}
|
||||||
|
io.finished := fuzz.module.io.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLRAMRationalCrossingSink(direction: RationalDirection)(implicit p: Parameters) extends LazyModule {
|
||||||
|
val node = TLRationalInputNode()
|
||||||
|
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
|
||||||
|
|
||||||
|
ram.node := TLFragmenter(4, 256)(TLDelayer(0.25)(TLRationalCrossingSink(direction)(node)))
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLRAMRationalCrossing(implicit p: Parameters) extends LazyModule {
|
||||||
|
val sym_fast_source = LazyModule(new TLRAMRationalCrossingSource)
|
||||||
|
val sym_slow_sink = LazyModule(new TLRAMRationalCrossingSink(Symmetric))
|
||||||
|
sym_slow_sink.node := sym_fast_source.node
|
||||||
|
|
||||||
|
val sym_slow_source = LazyModule(new TLRAMRationalCrossingSource)
|
||||||
|
val sym_fast_sink = LazyModule(new TLRAMRationalCrossingSink(Symmetric))
|
||||||
|
sym_fast_sink.node := sym_slow_source.node
|
||||||
|
|
||||||
|
val fix_fast_source = LazyModule(new TLRAMRationalCrossingSource)
|
||||||
|
val fix_slow_sink = LazyModule(new TLRAMRationalCrossingSink(FastToSlow))
|
||||||
|
fix_slow_sink.node := fix_fast_source.node
|
||||||
|
|
||||||
|
val fix_slow_source = LazyModule(new TLRAMRationalCrossingSource)
|
||||||
|
val fix_fast_sink = LazyModule(new TLRAMRationalCrossingSink(SlowToFast))
|
||||||
|
fix_fast_sink.node := fix_slow_source.node
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
io.finished := fuzz.module.io.finished
|
io.finished :=
|
||||||
|
sym_fast_source.module.io.finished &&
|
||||||
|
sym_slow_source.module.io.finished &&
|
||||||
|
fix_fast_source.module.io.finished &&
|
||||||
|
fix_slow_source.module.io.finished
|
||||||
|
|
||||||
// Shove the RAM into another clock domain
|
// Generate faster clock (still divided so verilator approves)
|
||||||
val clocks = Module(new util.Pow2ClockDivider(2))
|
val fast = Module(new util.Pow2ClockDivider(1))
|
||||||
ram.module.clock := clocks.io.clock_out
|
sym_fast_source.module.clock := fast.io.clock_out
|
||||||
delay.module.clock := clocks.io.clock_out
|
sym_fast_sink .module.clock := fast.io.clock_out
|
||||||
|
fix_fast_source.module.clock := fast.io.clock_out
|
||||||
|
fix_fast_sink .module.clock := fast.io.clock_out
|
||||||
|
|
||||||
// ... and safely cross TL2 into it
|
// Generate slower clock
|
||||||
cross.module.io.in_clock := clock
|
val slow = Module(new util.Pow2ClockDivider(2))
|
||||||
cross.module.io.in_reset := reset
|
sym_slow_source.module.clock := slow.io.clock_out
|
||||||
cross.module.io.out_clock := clocks.io.clock_out
|
sym_slow_sink .module.clock := slow.io.clock_out
|
||||||
cross.module.io.out_reset := reset
|
fix_slow_source.module.clock := slow.io.clock_out
|
||||||
|
fix_slow_sink .module.clock := slow.io.clock_out
|
||||||
// Push the Monitors into the right clock domain
|
|
||||||
monitors.foreach { m => m.module.clock := clocks.io.clock_out }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ package object tilelink2
|
|||||||
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||||
type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||||
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
||||||
type TLRationalOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLRationalBundle]
|
type TLRationalOutwardNode = OutwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
||||||
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||||
|
|
||||||
def OH1ToOH(x: UInt) = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x)
|
def OH1ToOH(x: UInt) = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x)
|
||||||
|
@ -4,16 +4,20 @@ package util
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
/** Divide the clock by 2 */
|
/** This black-boxes a Clock Divider by 2.
|
||||||
class ClockDivider2 extends Module {
|
* The output clock is phase-aligned to the input clock.
|
||||||
|
* If you use this in synthesis, make sure your sdc
|
||||||
|
* declares that you want it to do the same.
|
||||||
|
*
|
||||||
|
* Because Chisel does not support
|
||||||
|
* blocking assignments, it is impossible
|
||||||
|
* to create a deterministic divided clock.
|
||||||
|
*/
|
||||||
|
class ClockDivider2 extends BlackBox {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val clock_out = Clock(OUTPUT)
|
val clk_out = Clock(OUTPUT)
|
||||||
|
val clk_in = Clock(INPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
val clock_reg = Reg(Bool())
|
|
||||||
clock_reg := !clock_reg
|
|
||||||
|
|
||||||
io.clock_out := clock_reg.asClock
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Divide the clock by power of 2 times.
|
/** Divide the clock by power of 2 times.
|
||||||
@ -30,9 +34,10 @@ class Pow2ClockDivider(pow2: Int) extends Module {
|
|||||||
val dividers = Seq.fill(pow2) { Module(new ClockDivider2) }
|
val dividers = Seq.fill(pow2) { Module(new ClockDivider2) }
|
||||||
|
|
||||||
dividers.init.zip(dividers.tail).map { case (last, next) =>
|
dividers.init.zip(dividers.tail).map { case (last, next) =>
|
||||||
next.clock := last.io.clock_out
|
next.io.clk_in := last.io.clk_out
|
||||||
}
|
}
|
||||||
|
|
||||||
io.clock_out := dividers.last.io.clock_out
|
dividers.head.io.clk_in := clock
|
||||||
|
io.clock_out := dividers.last.io.clk_out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,32 @@
|
|||||||
package util
|
package util
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
|
// A rational crossing must put registers on the slow side.
|
||||||
|
// This trait covers the options of how/where to put the registers.
|
||||||
|
// BEWARE: the source+sink must agree on the direction!
|
||||||
|
sealed trait RationalDirection {
|
||||||
|
def flip: RationalDirection
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's unclear which side will be slow (or it is variable),
|
||||||
|
// place registers on both sides of the crossing, by splitting
|
||||||
|
// a Queue into flow and pipe parts on either side. This is safe
|
||||||
|
// for all possible clock ratios, but has the downside that the
|
||||||
|
// path from the slow domain must close timing in the fast domain.
|
||||||
|
case object Symmetric extends RationalDirection {
|
||||||
|
def flip = Symmetric
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the source is fast, place the registers at the sink.
|
||||||
|
case object FastToSlow extends RationalDirection {
|
||||||
|
def flip = SlowToFast
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the source is slow, place the registers at the source.
|
||||||
|
case object SlowToFast extends RationalDirection {
|
||||||
|
def flip = FastToSlow
|
||||||
|
}
|
||||||
|
|
||||||
final class RationalIO[T <: Data](gen: T) extends Bundle
|
final class RationalIO[T <: Data](gen: T) extends Bundle
|
||||||
{
|
{
|
||||||
val bits = gen.chiselCloneType
|
val bits = gen.chiselCloneType
|
||||||
@ -23,15 +49,19 @@ object RationalIO
|
|||||||
def apply[T <: Data](gen: T) = new RationalIO(gen)
|
def apply[T <: Data](gen: T) = new RationalIO(gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RationalCrossingSource[T <: Data](gen: T) extends Module
|
class RationalCrossingSource[T <: Data](gen: T, direction: RationalDirection = Symmetric) extends Module
|
||||||
{
|
{
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val enq = DecoupledIO(gen).flip
|
val enq = DecoupledIO(gen).flip
|
||||||
val deq = RationalIO(gen)
|
val deq = RationalIO(gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
val enq = Queue(io.enq, 1, flow=true)
|
|
||||||
val deq = io.deq
|
val deq = io.deq
|
||||||
|
val enq = direction match {
|
||||||
|
case Symmetric => Queue(io.enq, 1, flow=true)
|
||||||
|
case FastToSlow => io.enq
|
||||||
|
case SlowToFast => Queue(io.enq, 2)
|
||||||
|
}
|
||||||
|
|
||||||
val count = RegInit(UInt(0, width = 2))
|
val count = RegInit(UInt(0, width = 2))
|
||||||
val equal = count === deq.sink
|
val equal = count === deq.sink
|
||||||
@ -42,9 +72,16 @@ class RationalCrossingSource[T <: Data](gen: T) extends Module
|
|||||||
enq.ready := Mux(equal, deq.ready, count(1) =/= deq.sink(0))
|
enq.ready := Mux(equal, deq.ready, count(1) =/= deq.sink(0))
|
||||||
|
|
||||||
when (enq.fire()) { count := Cat(count(0), !count(1)) }
|
when (enq.fire()) { count := Cat(count(0), !count(1)) }
|
||||||
|
|
||||||
|
// Ensure the clocking is setup correctly
|
||||||
|
direction match {
|
||||||
|
case Symmetric => () // always safe
|
||||||
|
case FastToSlow => assert (equal || count(1) === deq.sink(0))
|
||||||
|
case SlowToFast => assert (equal || count(1) =/= deq.sink(0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RationalCrossingSink[T <: Data](gen: T) extends Module
|
class RationalCrossingSink[T <: Data](gen: T, direction: RationalDirection = Symmetric) extends Module
|
||||||
{
|
{
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val enq = RationalIO(gen).flip
|
val enq = RationalIO(gen).flip
|
||||||
@ -53,7 +90,11 @@ class RationalCrossingSink[T <: Data](gen: T) extends Module
|
|||||||
|
|
||||||
val enq = io.enq
|
val enq = io.enq
|
||||||
val deq = Wire(io.deq)
|
val deq = Wire(io.deq)
|
||||||
io.deq <> Queue(deq, 1, pipe=true)
|
direction match {
|
||||||
|
case Symmetric => io.deq <> Queue(deq, 1, pipe=true)
|
||||||
|
case FastToSlow => io.deq <> Queue(deq, 2)
|
||||||
|
case SlowToFast => io.deq <> deq
|
||||||
|
}
|
||||||
|
|
||||||
val count = RegInit(UInt(0, width = 2))
|
val count = RegInit(UInt(0, width = 2))
|
||||||
val equal = count === enq.source
|
val equal = count === enq.source
|
||||||
@ -64,14 +105,21 @@ class RationalCrossingSink[T <: Data](gen: T) extends Module
|
|||||||
deq.valid := Mux(equal, enq.valid, count(1) =/= enq.source(0))
|
deq.valid := Mux(equal, enq.valid, count(1) =/= enq.source(0))
|
||||||
|
|
||||||
when (deq.fire()) { count := Cat(count(0), !count(1)) }
|
when (deq.fire()) { count := Cat(count(0), !count(1)) }
|
||||||
|
|
||||||
|
// Ensure the clocking is setup correctly
|
||||||
|
direction match {
|
||||||
|
case Symmetric => () // always safe
|
||||||
|
case FastToSlow => assert (equal || count(1) =/= enq.source(0))
|
||||||
|
case SlowToFast => assert (equal || count(1) === enq.source(0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RationalCrossing[T <: Data](gen: T) extends Module
|
class RationalCrossing[T <: Data](gen: T, direction: RationalDirection = Symmetric) extends Module
|
||||||
{
|
{
|
||||||
val io = new CrossingIO(gen)
|
val io = new CrossingIO(gen)
|
||||||
|
|
||||||
val source = Module(new RationalCrossingSource(gen))
|
val source = Module(new RationalCrossingSource(gen, direction))
|
||||||
val sink = Module(new RationalCrossingSink(gen))
|
val sink = Module(new RationalCrossingSink(gen, direction))
|
||||||
|
|
||||||
source.clock := io.enq_clock
|
source.clock := io.enq_clock
|
||||||
source.reset := io.enq_reset
|
source.reset := io.enq_reset
|
||||||
@ -84,8 +132,8 @@ class RationalCrossing[T <: Data](gen: T) extends Module
|
|||||||
|
|
||||||
object ToRational
|
object ToRational
|
||||||
{
|
{
|
||||||
def apply[T <: Data](x: DecoupledIO[T]): RationalIO[T] = {
|
def apply[T <: Data](x: DecoupledIO[T], direction: RationalDirection = Symmetric): RationalIO[T] = {
|
||||||
val source = Module(new RationalCrossingSource(x.bits))
|
val source = Module(new RationalCrossingSource(x.bits, direction))
|
||||||
source.io.enq <> x
|
source.io.enq <> x
|
||||||
source.io.deq
|
source.io.deq
|
||||||
}
|
}
|
||||||
@ -93,8 +141,8 @@ object ToRational
|
|||||||
|
|
||||||
object FromRational
|
object FromRational
|
||||||
{
|
{
|
||||||
def apply[T <: Data](x: RationalIO[T]): DecoupledIO[T] = {
|
def apply[T <: Data](x: RationalIO[T], direction: RationalDirection = Symmetric): DecoupledIO[T] = {
|
||||||
val sink = Module(new RationalCrossingSink(x.bits))
|
val sink = Module(new RationalCrossingSink(x.bits, direction))
|
||||||
sink.io.enq <> x
|
sink.io.enq <> x
|
||||||
sink.io.deq
|
sink.io.deq
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
|
bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
|
||||||
$(base_dir)/vsrc/jtag_vpi.v \
|
$(base_dir)/vsrc/jtag_vpi.v \
|
||||||
|
$(base_dir)/vsrc/ClockDivider2.v \
|
||||||
$(base_dir)/vsrc/AsyncResetReg.v \
|
$(base_dir)/vsrc/AsyncResetReg.v \
|
||||||
|
|
||||||
sim_vsrcs = \
|
sim_vsrcs = \
|
||||||
|
24
vsrc/ClockDivider2.v
Normal file
24
vsrc/ClockDivider2.v
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
/** This black-boxes a Clock Divider by 2.
|
||||||
|
* The output clock is phase-aligned to the input clock.
|
||||||
|
* If you use this in synthesis, make sure your sdc
|
||||||
|
* declares that you want it to do the same.
|
||||||
|
*
|
||||||
|
* Because Chisel does not support
|
||||||
|
* blocking assignments, it is impossible
|
||||||
|
* to create a deterministic divided clock.
|
||||||
|
*
|
||||||
|
* @param clk_out Divided Clock
|
||||||
|
* @param clk_in Clock Input
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module ClockDivider2 (output reg clk_out, input clk_in);
|
||||||
|
|
||||||
|
initial clk_out = 1'b0;
|
||||||
|
always @(posedge clk_in) begin
|
||||||
|
clk_out = ~clk_out; // Must use =, NOT <=
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule // ClockDivider2
|
Loading…
Reference in New Issue
Block a user