1
0

Merge pull request #587 from ucb-bar/ahb-fix

ahb: rewrote TLToAHB to avoid retracting requests on stall
This commit is contained in:
Wesley W. Terpstra 2017-03-16 20:55:39 -07:00 committed by GitHub
commit eb953c40f0
10 changed files with 239 additions and 154 deletions

View File

@ -219,3 +219,20 @@ object AddressSet
if (out.size != n) unify(out) else out.toList if (out.size != n) unify(out) else out.toList
} }
} }
case class BufferParams(depth: Int, flow: Boolean, pipe: Boolean)
{
require (depth >= 0)
def isDefined = depth > 0
def latency = if (isDefined && !flow) 1 else 0
}
object BufferParams
{
implicit def apply(depth: Int): BufferParams = BufferParams(depth, false, false)
val default = BufferParams(2)
val none = BufferParams(0)
val flow = BufferParams(1, true, false)
val pipe = BufferParams(1, false, true)
}

View File

@ -16,7 +16,7 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter
new AHBRegBundle((), _) with RRTest1Bundle)( new AHBRegBundle((), _) with RRTest1Bundle)(
new AHBRegModule((), _, _) with RRTest1Module) new AHBRegModule((), _, _) with RRTest1Module)
class AHBFuzzNative()(implicit p: Parameters) extends LazyModule class AHBFuzzNative(aFlow: Boolean)(implicit p: Parameters) extends LazyModule
{ {
val fuzz = LazyModule(new TLFuzzer(5000)) val fuzz = LazyModule(new TLFuzzer(5000))
val model = LazyModule(new TLRAMModel("AHBFuzzNative")) val model = LazyModule(new TLRAMModel("AHBFuzzNative"))
@ -25,7 +25,7 @@ class AHBFuzzNative()(implicit p: Parameters) extends LazyModule
val gpio = LazyModule(new RRTest0(0x100)) val gpio = LazyModule(new RRTest0(0x100))
model.node := fuzz.node model.node := fuzz.node
xbar.node := TLToAHB()(TLDelayer(0.1)(model.node)) xbar.node := TLToAHB(aFlow)(TLDelayer(0.1)(model.node))
ram.node := xbar.node ram.node := xbar.node
gpio.node := xbar.node gpio.node := xbar.node
@ -34,12 +34,12 @@ class AHBFuzzNative()(implicit p: Parameters) extends LazyModule
} }
} }
class AHBNativeTest()(implicit p: Parameters) extends UnitTest(500000) { class AHBNativeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) {
val dut = Module(LazyModule(new AHBFuzzNative).module) val dut = Module(LazyModule(new AHBFuzzNative(aFlow)).module)
io.finished := dut.io.finished io.finished := dut.io.finished
} }
class AHBFuzzMaster()(implicit p: Parameters) extends LazyModule class AHBFuzzMaster(aFlow: Boolean)(implicit p: Parameters) extends LazyModule
{ {
val node = AHBOutputNode() val node = AHBOutputNode()
val fuzz = LazyModule(new TLFuzzer(5000)) val fuzz = LazyModule(new TLFuzzer(5000))
@ -47,9 +47,9 @@ class AHBFuzzMaster()(implicit p: Parameters) extends LazyModule
model.node := fuzz.node model.node := fuzz.node
node := node :=
TLToAHB()( TLToAHB(aFlow)(
TLDelayer(0.2)( TLDelayer(0.2)(
TLBuffer(TLBufferParams.flow)( TLBuffer(BufferParams.flow)(
TLDelayer(0.2)( TLDelayer(0.2)(
model.node)))) model.node))))
@ -71,7 +71,7 @@ class AHBFuzzSlave()(implicit p: Parameters) extends LazyModule
ram.node := ram.node :=
TLFragmenter(4, 16)( TLFragmenter(4, 16)(
TLDelayer(0.2)( TLDelayer(0.2)(
TLBuffer(TLBufferParams.flow)( TLBuffer(BufferParams.flow)(
TLDelayer(0.2)( TLDelayer(0.2)(
AHBToTL()( AHBToTL()(
node))))) node)))))
@ -83,9 +83,9 @@ class AHBFuzzSlave()(implicit p: Parameters) extends LazyModule
} }
} }
class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule class AHBFuzzBridge(aFlow: Boolean)(implicit p: Parameters) extends LazyModule
{ {
val master = LazyModule(new AHBFuzzMaster) val master = LazyModule(new AHBFuzzMaster(aFlow))
val slave = LazyModule(new AHBFuzzSlave) val slave = LazyModule(new AHBFuzzSlave)
slave.node := master.node slave.node := master.node
@ -95,7 +95,7 @@ class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule
} }
} }
class AHBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) { class AHBBridgeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) {
val dut = Module(LazyModule(new AHBFuzzBridge).module) val dut = Module(LazyModule(new AHBFuzzBridge(aFlow)).module)
io.finished := dut.io.finished io.finished := dut.io.finished
} }

View File

@ -56,7 +56,7 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule
val d_addr = Reg(in.haddr) val d_addr = Reg(in.haddr)
val d_size = Reg(in.hsize) val d_size = Reg(in.hsize)
when (out.d.valid) { d_recv := Bool(false); d_error := d_error || out.d.bits.error } when (out.d.valid) { d_recv := Bool(false) }
when (out.a.ready) { d_send := Bool(false) } when (out.a.ready) { d_send := Bool(false) }
val a_count = RegInit(UInt(0, width = 4)) val a_count = RegInit(UInt(0, width = 4))
@ -87,14 +87,12 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule
when (a_accept) { when (a_accept) {
a_count := a_count - UInt(1) a_count := a_count - UInt(1)
d_error := d_error || !a_legal
when ( in.hwrite) { d_send := Bool(true) } when ( in.hwrite) { d_send := Bool(true) }
when (!in.hwrite) { d_recv := Bool(true) } when (!in.hwrite) { d_recv := Bool(true) }
when (a_first) { when (a_first) {
a_count := Mux(a_burst_ok, a_burst_mask >> log2Ceil(beatBytes), UInt(0)) a_count := Mux(a_burst_ok, a_burst_mask >> log2Ceil(beatBytes), UInt(0))
d_send := a_legal d_send := a_legal
d_recv := a_legal d_recv := a_legal
d_error := !a_legal
d_pause := Bool(false) d_pause := Bool(false)
d_write := in.hwrite d_write := in.hwrite
d_addr := in.haddr d_addr := in.haddr
@ -111,7 +109,11 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule
out.a.bits.data := in.hwdata out.a.bits.data := in.hwdata
out.a.bits.mask := maskGen(d_addr, d_size, beatBytes) out.a.bits.mask := maskGen(d_addr, d_size, beatBytes)
// Save the error for the last beat (so the master can't cancel the burst) d_error :=
(d_error && !(a_first && in.hready)) || // clear error when a new beat starts
(a_accept && !a_legal) || // error if the address requested is illegal
(out.d.valid && out.d.bits.error) // error if TL reports an error
// When we report an error, we need to be hreadyout LOW for one cycle // When we report an error, we need to be hreadyout LOW for one cycle
val inject_error = d_last && (d_error || (out.d.valid && out.d.bits.error)) val inject_error = d_last && (d_error || (out.d.valid && out.d.bits.error))
when (inject_error) { d_pause := Bool(true) } when (inject_error) { d_pause := Bool(true) }

View File

@ -16,7 +16,7 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends APBRegisterRouter
new APBRegBundle((), _) with RRTest1Bundle)( new APBRegBundle((), _) with RRTest1Bundle)(
new APBRegModule((), _, _) with RRTest1Module) new APBRegModule((), _, _) with RRTest1Module)
class APBFuzzBridge()(implicit p: Parameters) extends LazyModule class APBFuzzBridge(aFlow: Boolean)(implicit p: Parameters) extends LazyModule
{ {
val fuzz = LazyModule(new TLFuzzer(5000)) val fuzz = LazyModule(new TLFuzzer(5000))
val model = LazyModule(new TLRAMModel("APBFuzzMaster")) val model = LazyModule(new TLRAMModel("APBFuzzMaster"))
@ -28,9 +28,9 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule
ram.node := xbar.node ram.node := xbar.node
gpio.node := xbar.node gpio.node := xbar.node
xbar.node := xbar.node :=
TLToAPB()( TLToAPB(aFlow)(
TLDelayer(0.2)( TLDelayer(0.2)(
TLBuffer(TLBufferParams.flow)( TLBuffer(BufferParams.flow)(
TLDelayer(0.2)( TLDelayer(0.2)(
model.node)))) model.node))))
@ -39,7 +39,7 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule
} }
} }
class APBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) { class APBBridgeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) {
val dut = Module(LazyModule(new APBFuzzBridge).module) val dut = Module(LazyModule(new APBFuzzBridge(aFlow)).module)
io.finished := dut.io.finished io.finished := dut.io.finished
} }

View File

@ -4,22 +4,26 @@ package uncore.axi4
import Chisel._ import Chisel._
import chisel3.internal.sourceinfo.SourceInfo import chisel3.internal.sourceinfo.SourceInfo
import chisel3.util.IrrevocableIO
import config._ import config._
import diplomacy._ import diplomacy._
import scala.math.{min,max} import scala.math.{min,max}
// pipe is only used if a queue has depth = 1 // pipe is only used if a queue has depth = 1
class AXI4Buffer(aw: Int = 2, w: Int = 2, b: Int = 2, ar: Int = 2, r: Int = 2, pipe: Boolean = true)(implicit p: Parameters) extends LazyModule class AXI4Buffer(
aw: BufferParams,
w: BufferParams,
b: BufferParams,
ar: BufferParams,
r: BufferParams)(implicit p: Parameters) extends LazyModule
{ {
require (aw >= 0) def this(aw: BufferParams, br: BufferParams)(implicit p: Parameters) = this(aw, aw, br, aw, br)
require (w >= 0) def this(x: BufferParams)(implicit p: Parameters) = this(x, x)
require (b >= 0) def this()(implicit p: Parameters) = this(BufferParams.default)
require (ar >= 0)
require (r >= 0)
val node = AXI4AdapterNode( val node = AXI4AdapterNode(
masterFn = { p => p }, masterFn = { p => p },
slaveFn = { p => p.copy(minLatency = p.minLatency + min(1,min(aw,ar)) + min(1,min(r,b))) }) slaveFn = { p => p.copy(minLatency = p.minLatency + min(aw.latency,ar.latency) + min(r.latency,b.latency)) })
lazy val module = new LazyModuleImp(this) { lazy val module = new LazyModuleImp(this) {
val io = new Bundle { val io = new Bundle {
@ -27,12 +31,20 @@ class AXI4Buffer(aw: Int = 2, w: Int = 2, b: Int = 2, ar: Int = 2, r: Int = 2, p
val out = node.bundleOut val out = node.bundleOut
} }
def buffer[T <: Data](config: BufferParams, data: IrrevocableIO[T]): IrrevocableIO[T] = {
if (config.isDefined) {
Queue.irrevocable(data, config.depth, pipe=config.pipe, flow=config.flow)
} else {
data
}
}
((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)) =>
if (aw>0) { out.aw <> Queue(in .aw, aw, pipe && aw<2) } else { out.aw <> in .aw } out.aw <> buffer(aw, in .aw)
if (w >0) { out.w <> Queue(in .w, w, pipe && w <2) } else { out.w <> in .w } out.w <> buffer(w, in .w)
if (b >0) { in .b <> Queue(out.b, b, pipe && b <2) } else { in .b <> out.b } in .b <> buffer(b, out.b)
if (ar>0) { out.ar <> Queue(in .ar, ar, pipe && ar<2) } else { out.ar <> in .ar } out.ar <> buffer(ar, in .ar)
if (r >0) { in .r <> Queue(out.r, r, pipe && r <2) } else { in .r <> out.r } in .r <> buffer(r, out.r)
} }
} }
} }
@ -40,13 +52,16 @@ class AXI4Buffer(aw: Int = 2, w: Int = 2, b: Int = 2, ar: Int = 2, r: Int = 2, p
object AXI4Buffer object AXI4Buffer
{ {
// applied to the AXI4 source node; y.node := AXI4Buffer(x.node) // applied to the AXI4 source node; y.node := AXI4Buffer(x.node)
def apply() (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(2)(x) def apply() (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(BufferParams.default)(x)
def apply(entries: Int) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(entries, true)(x) def apply(z: BufferParams) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(z, z)(x)
def apply(entries: Int, pipe: Boolean) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(entries, entries, pipe)(x) def apply(aw: BufferParams, br: BufferParams)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(aw, aw, br, aw, br)(x)
def apply(aw: Int, br: Int) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(aw, br, true)(x) def apply(
def apply(aw: Int, br: Int, pipe: Boolean)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(aw, aw, br, aw, br, pipe)(x) aw: BufferParams,
def apply(aw: Int, w: Int, b: Int, ar: Int, r: Int, pipe: Boolean = true)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = { w: BufferParams,
val buffer = LazyModule(new AXI4Buffer(aw, w, b, ar, r, pipe)) b: BufferParams,
ar: BufferParams,
r: BufferParams)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = {
val buffer = LazyModule(new AXI4Buffer(aw, w, b, ar, r))
buffer.node := x buffer.node := x
buffer.node buffer.node
} }

View File

@ -25,7 +25,7 @@ class AXI4LiteFuzzRAM()(implicit p: Parameters) extends LazyModule
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
model.node := fuzz.node model.node := fuzz.node
xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node))) xbar.node := TLDelayer(0.1)(TLBuffer(BufferParams.flow)(TLDelayer(0.2)(model.node)))
ram.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, true )(xbar.node)) ram.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, true )(xbar.node))
gpio.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, false)(xbar.node)) gpio.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, false)(xbar.node))
@ -48,7 +48,7 @@ class AXI4FullFuzzRAM()(implicit p: Parameters) extends LazyModule
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
model.node := fuzz.node model.node := fuzz.node
xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node))) xbar.node := TLDelayer(0.1)(TLBuffer(BufferParams.flow)(TLDelayer(0.2)(model.node)))
ram.node := AXI4Fragmenter(lite=false, maxInFlight = 2)(TLToAXI4(4,false)(xbar.node)) ram.node := AXI4Fragmenter(lite=false, maxInFlight = 2)(TLToAXI4(4,false)(xbar.node))
gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node)) gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node))
@ -72,7 +72,7 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule
node := node :=
TLToAXI4(4)( TLToAXI4(4)(
TLDelayer(0.1)( TLDelayer(0.1)(
TLBuffer(TLBufferParams.flow)( TLBuffer(BufferParams.flow)(
TLDelayer(0.1)( TLDelayer(0.1)(
model.node)))) model.node))))
@ -94,7 +94,7 @@ class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule
ram.node := ram.node :=
TLFragmenter(4, 16)( TLFragmenter(4, 16)(
TLDelayer(0.1)( TLDelayer(0.1)(
TLBuffer(TLBufferParams.flow)( TLBuffer(BufferParams.flow)(
TLDelayer(0.1)( TLDelayer(0.1)(
AXI4ToTL()( AXI4ToTL()(
AXI4Fragmenter()( AXI4Fragmenter()(

View File

@ -8,33 +8,16 @@ import config._
import diplomacy._ import diplomacy._
import scala.math.{min,max} import scala.math.{min,max}
case class TLBufferParams(depth: Int, flow: Boolean, pipe: Boolean)
{
require (depth >= 0)
def isDefined = depth > 0
def latency = if (isDefined && !flow) 1 else 0
}
object TLBufferParams
{
implicit def apply(depth: Int): TLBufferParams = TLBufferParams(depth, false, false)
val default = TLBufferParams(2)
val none = TLBufferParams(0)
val flow = TLBufferParams(1, true, false)
val pipe = TLBufferParams(1, false, true)
}
class TLBuffer( class TLBuffer(
a: TLBufferParams, a: BufferParams,
b: TLBufferParams, b: BufferParams,
c: TLBufferParams, c: BufferParams,
d: TLBufferParams, d: BufferParams,
e: TLBufferParams)(implicit p: Parameters) extends LazyModule e: BufferParams)(implicit p: Parameters) extends LazyModule
{ {
def this(ace: TLBufferParams, bd: TLBufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace) def this(ace: BufferParams, bd: BufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace)
def this(abcde: TLBufferParams)(implicit p: Parameters) = this(abcde, abcde) def this(abcde: BufferParams)(implicit p: Parameters) = this(abcde, abcde)
def this()(implicit p: Parameters) = this(TLBufferParams.default) def this()(implicit p: Parameters) = this(BufferParams.default)
val node = TLAdapterNode( val node = TLAdapterNode(
clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) }, clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) },
@ -46,7 +29,7 @@ class TLBuffer(
val out = node.bundleOut val out = node.bundleOut
} }
def buffer[T <: Data](config: TLBufferParams, data: DecoupledIO[T]): DecoupledIO[T] = { def buffer[T <: Data](config: BufferParams, data: DecoupledIO[T]): DecoupledIO[T] = {
if (config.isDefined) { if (config.isDefined) {
Queue(data, config.depth, pipe=config.pipe, flow=config.flow) Queue(data, config.depth, pipe=config.pipe, flow=config.flow)
} else { } else {
@ -77,15 +60,15 @@ class TLBuffer(
object TLBuffer object TLBuffer
{ {
// applied to the TL source node; y.node := TLBuffer(x.node) // applied to the TL source node; y.node := TLBuffer(x.node)
def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(TLBufferParams.default)(x) def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(BufferParams.default)(x)
def apply(abcde: TLBufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x) def apply(abcde: BufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x)
def apply(ace: TLBufferParams, bd: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x) def apply(ace: BufferParams, bd: BufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x)
def apply( def apply(
a: TLBufferParams, a: BufferParams,
b: TLBufferParams, b: BufferParams,
c: TLBufferParams, c: BufferParams,
d: TLBufferParams, d: BufferParams,
e: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { e: BufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
val buffer = LazyModule(new TLBuffer(a, b, c, d, e)) val buffer = LazyModule(new TLBuffer(a, b, c, d, e))
buffer.node := x buffer.node := x
buffer.node buffer.node

View File

@ -25,12 +25,29 @@ case class TLToAHBNode() extends MixedAdapterNode(TLImp, AHBImp)(
nodePath = s.nodePath, nodePath = s.nodePath,
supportsGet = s.supportsRead, supportsGet = s.supportsRead,
supportsPutFull = s.supportsWrite, // but not PutPartial supportsPutFull = s.supportsWrite, // but not PutPartial
fifoId = Some(0)) // a common FIFO domain fifoId = Some(0))
} }
TLManagerPortParameters(managers, beatBytes, 1, 1) TLManagerPortParameters(managers, beatBytes, 1, 1)
}) })
class TLToAHB(val combinational: Boolean = true)(implicit p: Parameters) extends LazyModule class AHBControlBundle(params: TLEdge) extends util.GenericParameterizedBundle(params)
{
val full = Bool()
val send = Bool() // => full+data
val first = Bool()
val last = Bool()
val write = Bool()
val size = UInt(width = params.bundle.sizeBits)
val source = UInt(width = params.bundle.sourceBits)
val hsize = UInt(width = AHBParameters.sizeBits)
val hburst = UInt(width = AHBParameters.burstBits)
val addr = UInt(width = params.bundle.addressBits)
val data = UInt(width = params.bundle.dataBits)
}
// The input side has either a flow queue (aFlow=true) or a pipe queue (aFlow=false)
// The output side always has a flow queue
class TLToAHB(val aFlow: Boolean = false)(implicit p: Parameters) extends LazyModule
{ {
val node = TLToAHBNode() val node = TLToAHBNode()
@ -40,88 +57,135 @@ class TLToAHB(val combinational: Boolean = true)(implicit p: Parameters) extends
val out = node.bundleOut val out = node.bundleOut
} }
((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 beatBytes = edgeOut.slave.beatBytes val beatBytes = edgeOut.slave.beatBytes
val maxTransfer = edgeOut.slave.maxTransfer val maxTransfer = edgeOut.slave.maxTransfer
val lgMax = log2Ceil(maxTransfer) val lgMax = log2Ceil(maxTransfer)
val lgBytes = log2Ceil(beatBytes) val lgBytes = log2Ceil(beatBytes)
// AHB has no cache coherence // Initial FSM state
in.b.valid := Bool(false) val resetState = Wire(new AHBControlBundle(edgeIn))
in.c.ready := Bool(true) resetState.full := Bool(false)
in.e.ready := Bool(true) resetState.send := Bool(false)
resetState.first := Bool(true)
// These are needed to appease AHB VIP:
resetState.hsize := UInt(0)
resetState.hburst:= UInt(0)
resetState.addr := UInt(0)
// The stages of the combinational pipeline
val reg = RegInit(resetState)
val send = Wire(init = reg)
val step = Wire(init = send)
val next = Wire(init = step)
reg := next
// Advance the FSM based on the result of this AHB beat
when (send.send && !out.hreadyout) /* retry AHB */ {
step.full := Bool(true)
step.send := Bool(true)
} .elsewhen (send.full && !send.send) /* retry beat */ {
step.full := Bool(true)
step.send := Bool(false)
} .elsewhen (send.full && !send.last) /* continue burst */ {
step.full := Bool(true)
step.send := Bool(false) // => looks like a retry to injector
step.first := Bool(false)
step.last := (if (lgBytes + 1 >= lgMax) Bool(true) else
!((UIntToOH1(send.size, lgMax) & ~send.addr) >> (lgBytes + 1)).orR())
step.addr := Cat(send.addr(edgeIn.bundle.addressBits-1, lgMax), send.addr(lgMax-1, 0) + UInt(beatBytes))
} .otherwise /* new burst */ {
step.full := Bool(false)
step.send := Bool(false)
step.first := Bool(true)
}
val d_block = Wire(Bool())
val pre = if (aFlow) reg else step
val post = if (aFlow) send else next
// Transform TL size into AHB hsize+hburst
val a_sizeDelta = Cat(UInt(0, width = 1), in.a.bits.size) - UInt(lgBytes+1)
val a_singleBeat = Bool(lgBytes >= lgMax) || a_sizeDelta(edgeIn.bundle.sizeBits)
val a_logBeats1 = a_sizeDelta(edgeIn.bundle.sizeBits-1, 0)
// Pulse this every time we commit to sending an AHB request
val a_commit = Wire(Bool())
// Inject A channel into FSM
when (pre.send) /* busy */ {
a_commit := Bool(false)
in.a.ready := Bool(false)
} .elsewhen (pre.full) /* retry beat (or continue burst) */ {
post.send := !d_block && (!pre.write || in.a.valid)
post.data := in.a.bits.data
a_commit := !d_block && !pre.write // only read beats commit to a D beat answer
in.a.ready := !d_block && pre.write
} .otherwise /* new burst */ {
a_commit := in.a.fire() // every first beat commits to a D beat answer
in.a.ready := !d_block
when (in.a.fire()) {
post.full := Bool(true)
post.send := Bool(true)
post.last := a_singleBeat
post.write := edgeIn.hasData(in.a.bits)
post.size := in.a.bits.size
post.source:= in.a.bits.source
post.hsize := Mux(a_singleBeat, in.a.bits.size, UInt(lgBytes))
post.hburst:= Mux(a_singleBeat, BURST_SINGLE, (a_logBeats1<<1) | UInt(1))
post.addr := in.a.bits.address
post.data := in.a.bits.data
}
}
out.hmastlock := Bool(false) // for now
out.htrans := Mux(send.send, Mux(send.first, TRANS_NONSEQ, TRANS_SEQ), Mux(send.first, TRANS_IDLE, TRANS_BUSY))
out.hsel := send.send || !send.first
out.hready := out.hreadyout
out.hwrite := send.write
out.haddr := send.addr
out.hsize := send.hsize
out.hburst := send.hburst
out.hprot := PROT_DEFAULT
out.hwdata := RegEnable(send.data, out.hreadyout)
// We need a skidpad to capture D output: // We need a skidpad to capture D output:
// We cannot know if the D response will be accepted until we have // We cannot know if the D response will be accepted until we have
// presented it on D as valid. We also can't back-pressure AHB in the // presented it on D as valid. We also can't back-pressure AHB in the
// data phase. Therefore, we must have enough space to save the data // data phase. Therefore, we must have enough space to save the all
// phase result. Whenever we have a queued response, we can not allow // commited AHB requests (A+D phases = 2). To decouple d_ready from
// AHB to present new responses, so we must quash the address phase. // a_ready and htrans, we add another entry for aFlow=false.
val depth = if (aFlow) 2 else 3
val d = Wire(in.d) val d = Wire(in.d)
in.d <> Queue(d, 1, flow = true) in.d <> Queue(d, depth, flow=true)
val a_quash = in.d.valid && !in.d.ready assert (!d.valid || d.ready)
val d_flight = RegInit(UInt(0, width = 2))
assert (d_flight <= UInt(depth))
d_flight := d_flight + a_commit.asUInt - in.d.fire().asUInt
d_block := d_flight >= UInt(depth)
// Record what is coming out in d_phase
val d_valid = RegInit(Bool(false)) val d_valid = RegInit(Bool(false))
val d_hasData = Reg(Bool())
val d_error = Reg(Bool()) val d_error = Reg(Bool())
val d_addr_lo = Reg(UInt(width = lgBytes)) val d_write = RegEnable(send.write, out.hreadyout)
val d_source = Reg(UInt()) val d_source = RegEnable(send.source, out.hreadyout)
val d_size = Reg(UInt()) val d_addr = RegEnable(send.addr, out.hreadyout)
val d_size = RegEnable(send.size, out.hreadyout)
when (out.hreadyout) { d_error := d_error || out.hresp } when (out.hreadyout) {
when (d.fire()) { d_valid := Bool(false) } d_valid := send.send && (send.last || !send.write)
when (out.hresp) { d_error := d_write }
d.valid := d_valid && out.hreadyout when (send.first) { d_error := Bool(false) }
d.bits := edgeIn.AccessAck(d_addr_lo, UInt(0), d_source, d_size, out.hrdata, out.hresp || d_error)
d.bits.opcode := Mux(d_hasData, TLMessages.AccessAckData, TLMessages.AccessAck)
// We need an irrevocable input for AHB to stall on read bursts
// We also need the values to NOT change when valid goes low => 1 entry only
val a = Queue(in.a, 1, flow = combinational, pipe = !combinational)
val a_valid = a.valid && !a_quash
// This is lot like TLEdge.firstlast, but counts beats also for single-beat TL types
val a_size = edgeIn.size(a.bits)
val a_beats1 = UIntToOH1(a_size, lgMax) >> lgBytes
val a_counter = RegInit(UInt(0, width = log2Up(maxTransfer/beatBytes)))
val a_counter1 = a_counter - UInt(1)
val a_first = a_counter === UInt(0)
val a_last = a_counter === UInt(1) || a_beats1 === UInt(0)
val a_offset = (a_beats1 & ~a_counter1) << lgBytes
val a_hasData = edgeIn.hasData(a.bits)
// Expand no-data A-channel requests into multiple beats
a.ready := (a_hasData || a_last) && out.hreadyout && !a_quash
when (a_valid && out.hreadyout) {
a_counter := Mux(a_first, a_beats1, a_counter1)
d_valid := !a_hasData || a_last
// Record what will be in the data phase
when (a_first) {
d_hasData := !a_hasData
d_error := Bool(false)
d_addr_lo := a.bits.address
d_source := a.bits.source
d_size := a.bits.size
}
} }
// Transform TL size into AHB hsize+hburst d.valid := d_valid && out.hreadyout
val a_size_bits = a_size.getWidth d.bits := edgeIn.AccessAck(d_addr, UInt(0), d_source, d_size, out.hrdata, out.hresp || d_error)
val a_sizeDelta = Cat(UInt(0, width = 1), a_size) - UInt(lgBytes+1) d.bits.opcode := Mux(d_write, TLMessages.AccessAck, TLMessages.AccessAckData)
val a_singleBeat = a_sizeDelta(a_size_bits)
val a_logBeats1 = a_sizeDelta(a_size_bits-1, 0)
out.hmastlock := Bool(false) // for now // AHB has no cache coherence
out.htrans := Mux(a_valid, Mux(a_first, TRANS_NONSEQ, TRANS_SEQ), Mux(a_first, TRANS_IDLE, TRANS_BUSY)) in.b.valid := Bool(false)
out.hsel := a_valid || !a_first in.c.ready := Bool(true)
out.hready := out.hreadyout in.e.ready := Bool(true)
out.hwrite := a_hasData
out.haddr := a.bits.address | a_offset
out.hsize := Mux(a_singleBeat, a.bits.size, UInt(lgBytes))
out.hburst := Mux(a_singleBeat, BURST_SINGLE, (a_logBeats1<<1) | UInt(1))
out.hprot := PROT_DEFAULT
out.hwdata := RegEnable(a.bits.data, a.fire())
} }
} }
} }
@ -129,8 +193,8 @@ class TLToAHB(val combinational: Boolean = true)(implicit p: Parameters) extends
object TLToAHB object TLToAHB
{ {
// applied to the TL source node; y.node := TLToAHB()(x.node) // applied to the TL source node; y.node := TLToAHB()(x.node)
def apply(combinational: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { def apply(aFlow: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = {
val ahb = LazyModule(new TLToAHB(combinational)) val ahb = LazyModule(new TLToAHB(aFlow))
ahb.node := x ahb.node := x
ahb.node ahb.node
} }

View File

@ -31,7 +31,9 @@ case class TLToAPBNode() extends MixedAdapterNode(TLImp, APBImp)(
TLManagerPortParameters(managers, beatBytes, 1, 0) TLManagerPortParameters(managers, beatBytes, 1, 0)
}) })
class TLToAPB(combinational: Boolean = true)(implicit p: Parameters) extends LazyModule // The input side has either a flow queue (aFlow=true) or a pipe queue (aFlow=false)
// The output side always has a flow queue
class TLToAPB(val aFlow: Boolean = true)(implicit p: Parameters) extends LazyModule
{ {
val node = TLToAPBNode() val node = TLToAPBNode()
@ -60,7 +62,7 @@ class TLToAPB(combinational: Boolean = true)(implicit p: Parameters) extends Laz
in.d <> Queue(d, 1, flow = true) in.d <> Queue(d, 1, flow = true)
// We need an irrevocable input for APB to stall // We need an irrevocable input for APB to stall
val a = Queue(in.a, 1, flow = combinational, pipe = !combinational) val a = Queue(in.a, 1, flow = aFlow, pipe = !aFlow)
val a_enable = RegInit(Bool(false)) val a_enable = RegInit(Bool(false))
val a_sel = a.valid && RegNext(!in.d.valid || in.d.ready) val a_sel = a.valid && RegNext(!in.d.valid || in.d.ready)
@ -90,8 +92,8 @@ class TLToAPB(combinational: Boolean = true)(implicit p: Parameters) extends Laz
object TLToAPB object TLToAPB
{ {
// applied to the TL source node; y.node := TLToAPB()(x.node) // applied to the TL source node; y.node := TLToAPB()(x.node)
def apply(combinational: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): APBOutwardNode = { def apply(aFlow: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): APBOutwardNode = {
val apb = LazyModule(new TLToAPB(combinational)) val apb = LazyModule(new TLToAPB(aFlow))
apb.node := x apb.node := x
apb.node apb.node
} }

View File

@ -12,9 +12,11 @@ class WithUncoreUnitTests extends Config((site, here, up) => {
implicit val p = q implicit val p = q
Seq( Seq(
Module(new uncore.tilelink2.TLFuzzRAMTest), Module(new uncore.tilelink2.TLFuzzRAMTest),
Module(new uncore.ahb.AHBBridgeTest), Module(new uncore.ahb.AHBBridgeTest(true)),
Module(new uncore.ahb.AHBNativeTest), Module(new uncore.ahb.AHBNativeTest(true)),
Module(new uncore.apb.APBBridgeTest), Module(new uncore.ahb.AHBNativeTest(false)),
Module(new uncore.apb.APBBridgeTest(true)),
Module(new uncore.apb.APBBridgeTest(false)),
Module(new uncore.axi4.AXI4LiteFuzzRAMTest), Module(new uncore.axi4.AXI4LiteFuzzRAMTest),
Module(new uncore.axi4.AXI4FullFuzzRAMTest), Module(new uncore.axi4.AXI4FullFuzzRAMTest),
Module(new uncore.axi4.AXI4BridgeTest)) } Module(new uncore.axi4.AXI4BridgeTest)) }