From bb4957536805607a7545878ec098be5a0eb8bd4c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 14:36:30 -0700 Subject: [PATCH 1/9] ahb: rewrote TLToAHB to avoid retracting requests on stall --- src/main/scala/uncore/tilelink2/ToAHB.scala | 198 +++++++++++++------- 1 file changed, 129 insertions(+), 69 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/ToAHB.scala b/src/main/scala/uncore/tilelink2/ToAHB.scala index 5be1a5dc..abc47133 100644 --- a/src/main/scala/uncore/tilelink2/ToAHB.scala +++ b/src/main/scala/uncore/tilelink2/ToAHB.scala @@ -25,12 +25,29 @@ case class TLToAHBNode() extends MixedAdapterNode(TLImp, AHBImp)( nodePath = s.nodePath, supportsGet = s.supportsRead, supportsPutFull = s.supportsWrite, // but not PutPartial - fifoId = Some(0)) // a common FIFO domain + fifoId = Some(0)) } 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 (a_pipe=false) or a pipe queue (a_pipe=true) +// The output side always has a flow queue +class TLToAHB(val a_pipe: Boolean = true)(implicit p: Parameters) extends LazyModule { val node = TLToAHBNode() @@ -40,88 +57,131 @@ class TLToAHB(val combinational: Boolean = true)(implicit p: Parameters) extends 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 maxTransfer = edgeOut.slave.maxTransfer val lgMax = log2Ceil(maxTransfer) val lgBytes = log2Ceil(beatBytes) - // AHB has no cache coherence - in.b.valid := Bool(false) - in.c.ready := Bool(true) - in.e.ready := Bool(true) + // Initial FSM state + val resetState = Wire(new AHBControlBundle(edgeIn)) + resetState.full := Bool(false) + resetState.send := Bool(false) + resetState.first := Bool(true) + + // 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 (a_pipe) step else reg + val post = if (a_pipe) next else send + + // 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 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 - // data phase. Therefore, we must have enough space to save the data - // phase result. Whenever we have a queued response, we can not allow - // AHB to present new responses, so we must quash the address phase. + // data phase. Therefore, we must have enough space to save the all + // commited AHB requests (A+D phases = 2). To decouple d_ready from + // a_ready and htrans, we add another entry for a_pipe=true. + val depth = if (a_pipe) 3 else 2 val d = Wire(in.d) - in.d <> Queue(d, 1, flow = true) - val a_quash = in.d.valid && !in.d.ready + in.d <> Queue(d, depth, flow=true) + 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_hasData = Reg(Bool()) val d_error = Reg(Bool()) - val d_addr_lo = Reg(UInt(width = lgBytes)) - val d_source = Reg(UInt()) - val d_size = Reg(UInt()) + val d_write = RegEnable(send.write, out.hreadyout) + val d_source = RegEnable(send.source, out.hreadyout) + 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 (d.fire()) { d_valid := Bool(false) } - - d.valid := d_valid && out.hreadyout - 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 - } + when (out.hreadyout) { + d_valid := send.send && (send.last || !send.write) + when (out.hresp) { d_error := d_write } + when (send.first) { d_error := Bool(false) } } - // Transform TL size into AHB hsize+hburst - val a_size_bits = a_size.getWidth - val a_sizeDelta = Cat(UInt(0, width = 1), a_size) - UInt(lgBytes+1) - val a_singleBeat = a_sizeDelta(a_size_bits) - val a_logBeats1 = a_sizeDelta(a_size_bits-1, 0) + d.valid := d_valid && out.hreadyout + d.bits := edgeIn.AccessAck(d_addr, UInt(0), d_source, d_size, out.hrdata, out.hresp || d_error) + d.bits.opcode := Mux(d_write, TLMessages.AccessAck, TLMessages.AccessAckData) - out.hmastlock := Bool(false) // for now - out.htrans := Mux(a_valid, Mux(a_first, TRANS_NONSEQ, TRANS_SEQ), Mux(a_first, TRANS_IDLE, TRANS_BUSY)) - out.hsel := a_valid || !a_first - out.hready := out.hreadyout - 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()) + // AHB has no cache coherence + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) } } } @@ -129,8 +189,8 @@ class TLToAHB(val combinational: Boolean = true)(implicit p: Parameters) extends object TLToAHB { // applied to the TL source node; y.node := TLToAHB()(x.node) - def apply(combinational: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { - val ahb = LazyModule(new TLToAHB(combinational)) + def apply(a_pipe: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { + val ahb = LazyModule(new TLToAHB(a_pipe)) ahb.node := x ahb.node } From 604a164b97fdbe8f0fd631ab3c153305d67bdf4f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:10:54 -0700 Subject: [PATCH 2/9] TLToAHB: rename parameter to aFlow --- src/main/scala/uncore/tilelink2/ToAHB.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/ToAHB.scala b/src/main/scala/uncore/tilelink2/ToAHB.scala index abc47133..cbf87d3a 100644 --- a/src/main/scala/uncore/tilelink2/ToAHB.scala +++ b/src/main/scala/uncore/tilelink2/ToAHB.scala @@ -45,9 +45,9 @@ class AHBControlBundle(params: TLEdge) extends util.GenericParameterizedBundle(p val data = UInt(width = params.bundle.dataBits) } -// The input side has either a flow queue (a_pipe=false) or a pipe queue (a_pipe=true) +// 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 a_pipe: Boolean = true)(implicit p: Parameters) extends LazyModule +class TLToAHB(val aFlow: Boolean = false)(implicit p: Parameters) extends LazyModule { val node = TLToAHBNode() @@ -97,8 +97,8 @@ class TLToAHB(val a_pipe: Boolean = true)(implicit p: Parameters) extends LazyMo } val d_block = Wire(Bool()) - val pre = if (a_pipe) step else reg - val post = if (a_pipe) next else send + 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) @@ -150,8 +150,8 @@ class TLToAHB(val a_pipe: Boolean = true)(implicit p: Parameters) extends LazyMo // 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 all // commited AHB requests (A+D phases = 2). To decouple d_ready from - // a_ready and htrans, we add another entry for a_pipe=true. - val depth = if (a_pipe) 3 else 2 + // a_ready and htrans, we add another entry for aFlow=false. + val depth = if (aFlow) 2 else 3 val d = Wire(in.d) in.d <> Queue(d, depth, flow=true) assert (!d.valid || d.ready) @@ -189,8 +189,8 @@ class TLToAHB(val a_pipe: Boolean = true)(implicit p: Parameters) extends LazyMo object TLToAHB { // applied to the TL source node; y.node := TLToAHB()(x.node) - def apply(a_pipe: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { - val ahb = LazyModule(new TLToAHB(a_pipe)) + def apply(aFlow: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { + val ahb = LazyModule(new TLToAHB(aFlow)) ahb.node := x ahb.node } From 963d244094bf40d202958162a06f7e027c4a3ae9 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:13:57 -0700 Subject: [PATCH 3/9] unittest: try both aFlow settings of TLToAHB --- src/main/scala/uncore/ahb/Test.scala | 20 ++++++++++---------- src/main/scala/unittest/Configs.scala | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/scala/uncore/ahb/Test.scala b/src/main/scala/uncore/ahb/Test.scala index 6bcf94f7..43fbcb49 100644 --- a/src/main/scala/uncore/ahb/Test.scala +++ b/src/main/scala/uncore/ahb/Test.scala @@ -16,7 +16,7 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter new AHBRegBundle((), _) with RRTest1Bundle)( 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 model = LazyModule(new TLRAMModel("AHBFuzzNative")) @@ -25,7 +25,7 @@ class AHBFuzzNative()(implicit p: Parameters) extends LazyModule val gpio = LazyModule(new RRTest0(0x100)) 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 gpio.node := xbar.node @@ -34,12 +34,12 @@ class AHBFuzzNative()(implicit p: Parameters) extends LazyModule } } -class AHBNativeTest()(implicit p: Parameters) extends UnitTest(500000) { - val dut = Module(LazyModule(new AHBFuzzNative).module) +class AHBNativeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) { + val dut = Module(LazyModule(new AHBFuzzNative(aFlow)).module) 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 fuzz = LazyModule(new TLFuzzer(5000)) @@ -47,7 +47,7 @@ class AHBFuzzMaster()(implicit p: Parameters) extends LazyModule model.node := fuzz.node node := - TLToAHB()( + TLToAHB(aFlow)( TLDelayer(0.2)( TLBuffer(TLBufferParams.flow)( TLDelayer(0.2)( @@ -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) slave.node := master.node @@ -95,7 +95,7 @@ class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule } } -class AHBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) { - val dut = Module(LazyModule(new AHBFuzzBridge).module) +class AHBBridgeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) { + val dut = Module(LazyModule(new AHBFuzzBridge(aFlow)).module) io.finished := dut.io.finished } diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index 5d6803d6..482e72bf 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -12,8 +12,9 @@ class WithUncoreUnitTests extends Config((site, here, up) => { implicit val p = q Seq( Module(new uncore.tilelink2.TLFuzzRAMTest), - Module(new uncore.ahb.AHBBridgeTest), - Module(new uncore.ahb.AHBNativeTest), + Module(new uncore.ahb.AHBBridgeTest(true)), + Module(new uncore.ahb.AHBNativeTest(true)), + Module(new uncore.ahb.AHBNativeTest(false)), Module(new uncore.apb.APBBridgeTest), Module(new uncore.axi4.AXI4LiteFuzzRAMTest), Module(new uncore.axi4.AXI4FullFuzzRAMTest), From 778c8a5c9751f8c7262b710c8e2db286d2d9de7f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:17:05 -0700 Subject: [PATCH 4/9] ToAHB: appease AHB VIP --- src/main/scala/uncore/tilelink2/ToAHB.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/uncore/tilelink2/ToAHB.scala b/src/main/scala/uncore/tilelink2/ToAHB.scala index cbf87d3a..e3ca09fd 100644 --- a/src/main/scala/uncore/tilelink2/ToAHB.scala +++ b/src/main/scala/uncore/tilelink2/ToAHB.scala @@ -68,6 +68,10 @@ class TLToAHB(val aFlow: Boolean = false)(implicit p: Parameters) extends LazyMo resetState.full := Bool(false) 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) From ca2c709d2983b11f00ca00d7c317e5a761d0e255 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:19:36 -0700 Subject: [PATCH 5/9] TLBuffer: move TLBufferParams to diplomacy.BufferParams --- src/main/scala/diplomacy/Parameters.scala | 17 +++++++ src/main/scala/uncore/ahb/Test.scala | 4 +- src/main/scala/uncore/apb/Test.scala | 2 +- src/main/scala/uncore/axi4/Test.scala | 8 +-- src/main/scala/uncore/tilelink2/Buffer.scala | 51 +++++++------------- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/main/scala/diplomacy/Parameters.scala b/src/main/scala/diplomacy/Parameters.scala index ccad3fbb..aa2e5bc3 100644 --- a/src/main/scala/diplomacy/Parameters.scala +++ b/src/main/scala/diplomacy/Parameters.scala @@ -219,3 +219,20 @@ object AddressSet 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) +} diff --git a/src/main/scala/uncore/ahb/Test.scala b/src/main/scala/uncore/ahb/Test.scala index 43fbcb49..05aa5da9 100644 --- a/src/main/scala/uncore/ahb/Test.scala +++ b/src/main/scala/uncore/ahb/Test.scala @@ -49,7 +49,7 @@ class AHBFuzzMaster(aFlow: Boolean)(implicit p: Parameters) extends LazyModule node := TLToAHB(aFlow)( TLDelayer(0.2)( - TLBuffer(TLBufferParams.flow)( + TLBuffer(BufferParams.flow)( TLDelayer(0.2)( model.node)))) @@ -71,7 +71,7 @@ class AHBFuzzSlave()(implicit p: Parameters) extends LazyModule ram.node := TLFragmenter(4, 16)( TLDelayer(0.2)( - TLBuffer(TLBufferParams.flow)( + TLBuffer(BufferParams.flow)( TLDelayer(0.2)( AHBToTL()( node))))) diff --git a/src/main/scala/uncore/apb/Test.scala b/src/main/scala/uncore/apb/Test.scala index c6d6f56e..198d25b1 100644 --- a/src/main/scala/uncore/apb/Test.scala +++ b/src/main/scala/uncore/apb/Test.scala @@ -30,7 +30,7 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule xbar.node := TLToAPB()( TLDelayer(0.2)( - TLBuffer(TLBufferParams.flow)( + TLBuffer(BufferParams.flow)( TLDelayer(0.2)( model.node)))) diff --git a/src/main/scala/uncore/axi4/Test.scala b/src/main/scala/uncore/axi4/Test.scala index 924fdeae..11bf11a8 100644 --- a/src/main/scala/uncore/axi4/Test.scala +++ b/src/main/scala/uncore/axi4/Test.scala @@ -25,7 +25,7 @@ class AXI4LiteFuzzRAM()(implicit p: Parameters) extends LazyModule val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) 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)) 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))) 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)) gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node)) @@ -72,7 +72,7 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule node := TLToAXI4(4)( TLDelayer(0.1)( - TLBuffer(TLBufferParams.flow)( + TLBuffer(BufferParams.flow)( TLDelayer(0.1)( model.node)))) @@ -94,7 +94,7 @@ class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule ram.node := TLFragmenter(4, 16)( TLDelayer(0.1)( - TLBuffer(TLBufferParams.flow)( + TLBuffer(BufferParams.flow)( TLDelayer(0.1)( AXI4ToTL()( AXI4Fragmenter()( diff --git a/src/main/scala/uncore/tilelink2/Buffer.scala b/src/main/scala/uncore/tilelink2/Buffer.scala index b7a51c4d..32b80cb5 100644 --- a/src/main/scala/uncore/tilelink2/Buffer.scala +++ b/src/main/scala/uncore/tilelink2/Buffer.scala @@ -8,33 +8,16 @@ import config._ import diplomacy._ 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( - a: TLBufferParams, - b: TLBufferParams, - c: TLBufferParams, - d: TLBufferParams, - e: TLBufferParams)(implicit p: Parameters) extends LazyModule + a: BufferParams, + b: BufferParams, + c: BufferParams, + d: BufferParams, + e: BufferParams)(implicit p: Parameters) extends LazyModule { - def this(ace: TLBufferParams, bd: TLBufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace) - def this(abcde: TLBufferParams)(implicit p: Parameters) = this(abcde, abcde) - def this()(implicit p: Parameters) = this(TLBufferParams.default) + def this(ace: BufferParams, bd: BufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace) + def this(abcde: BufferParams)(implicit p: Parameters) = this(abcde, abcde) + def this()(implicit p: Parameters) = this(BufferParams.default) val node = TLAdapterNode( clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) }, @@ -46,7 +29,7 @@ class TLBuffer( 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) { Queue(data, config.depth, pipe=config.pipe, flow=config.flow) } else { @@ -77,15 +60,15 @@ class TLBuffer( object TLBuffer { // 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(abcde: TLBufferParams) (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() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(BufferParams.default)(x) + def apply(abcde: BufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x) + def apply(ace: BufferParams, bd: BufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x) def apply( - a: TLBufferParams, - b: TLBufferParams, - c: TLBufferParams, - d: TLBufferParams, - e: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + a: BufferParams, + b: BufferParams, + c: BufferParams, + d: BufferParams, + e: BufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { val buffer = LazyModule(new TLBuffer(a, b, c, d, e)) buffer.node := x buffer.node From e31b84af33cf809b58363f081f7a82f31381bf2e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:32:17 -0700 Subject: [PATCH 6/9] axi4: use common BufferParams --- src/main/scala/uncore/axi4/Buffer.scala | 53 ++++++++++++++++--------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/main/scala/uncore/axi4/Buffer.scala b/src/main/scala/uncore/axi4/Buffer.scala index ee3304dd..1658e8b0 100644 --- a/src/main/scala/uncore/axi4/Buffer.scala +++ b/src/main/scala/uncore/axi4/Buffer.scala @@ -4,22 +4,26 @@ package uncore.axi4 import Chisel._ import chisel3.internal.sourceinfo.SourceInfo +import chisel3.util.IrrevocableIO import config._ import diplomacy._ import scala.math.{min,max} // 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) - require (w >= 0) - require (b >= 0) - require (ar >= 0) - require (r >= 0) + def this(aw: BufferParams, br: BufferParams)(implicit p: Parameters) = this(aw, aw, br, aw, br) + def this(x: BufferParams)(implicit p: Parameters) = this(x, x) + def this()(implicit p: Parameters) = this(BufferParams.default) val node = AXI4AdapterNode( 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) { 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 } + 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)) => - if (aw>0) { out.aw <> Queue(in .aw, aw, pipe && aw<2) } else { out.aw <> in .aw } - if (w >0) { out.w <> Queue(in .w, w, pipe && w <2) } else { out.w <> in .w } - if (b >0) { in .b <> Queue(out.b, b, pipe && b <2) } else { in .b <> out.b } - if (ar>0) { out.ar <> Queue(in .ar, ar, pipe && ar<2) } else { out.ar <> in .ar } - if (r >0) { in .r <> Queue(out.r, r, pipe && r <2) } else { in .r <> out.r } + out.aw <> buffer(aw, in .aw) + out.w <> buffer(w, in .w) + in .b <> buffer(b, out.b) + out.ar <> buffer(ar, in .ar) + 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 { // 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(entries: Int) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(entries, true)(x) - def apply(entries: Int, pipe: Boolean) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(entries, entries, pipe)(x) - def apply(aw: Int, br: Int) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(aw, br, true)(x) - def apply(aw: Int, br: Int, pipe: Boolean)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(aw, aw, br, aw, br, pipe)(x) - def apply(aw: Int, w: Int, b: Int, ar: Int, r: Int, pipe: Boolean = true)(x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = { - val buffer = LazyModule(new AXI4Buffer(aw, w, b, ar, r, pipe)) + def apply() (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(BufferParams.default)(x) + def apply(z: BufferParams) (x: AXI4OutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AXI4OutwardNode = apply(z, z)(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: BufferParams, + w: BufferParams, + 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 } From 882a7ff8ffbc70577cc9ffb7a27330ab50b8400e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:34:28 -0700 Subject: [PATCH 7/9] TLToAPB: use the now standard aFlow parameter name --- src/main/scala/uncore/tilelink2/ToAPB.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/ToAPB.scala b/src/main/scala/uncore/tilelink2/ToAPB.scala index 48ee119e..eb195a48 100644 --- a/src/main/scala/uncore/tilelink2/ToAPB.scala +++ b/src/main/scala/uncore/tilelink2/ToAPB.scala @@ -31,7 +31,9 @@ case class TLToAPBNode() extends MixedAdapterNode(TLImp, APBImp)( 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() @@ -60,7 +62,7 @@ class TLToAPB(combinational: Boolean = true)(implicit p: Parameters) extends Laz in.d <> Queue(d, 1, flow = true) // 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_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 { // applied to the TL source node; y.node := TLToAPB()(x.node) - def apply(combinational: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): APBOutwardNode = { - val apb = LazyModule(new TLToAPB(combinational)) + def apply(aFlow: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): APBOutwardNode = { + val apb = LazyModule(new TLToAPB(aFlow)) apb.node := x apb.node } From 5efd38bf971790e38e6ebc4ac84a34c40fd531a4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 15:35:30 -0700 Subject: [PATCH 8/9] apb: put both aFlow options under regression --- src/main/scala/uncore/apb/Test.scala | 8 ++++---- src/main/scala/unittest/Configs.scala | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/scala/uncore/apb/Test.scala b/src/main/scala/uncore/apb/Test.scala index 198d25b1..80d707a4 100644 --- a/src/main/scala/uncore/apb/Test.scala +++ b/src/main/scala/uncore/apb/Test.scala @@ -16,7 +16,7 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends APBRegisterRouter new APBRegBundle((), _) with RRTest1Bundle)( 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 model = LazyModule(new TLRAMModel("APBFuzzMaster")) @@ -28,7 +28,7 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule ram.node := xbar.node gpio.node := xbar.node xbar.node := - TLToAPB()( + TLToAPB(aFlow)( TLDelayer(0.2)( TLBuffer(BufferParams.flow)( TLDelayer(0.2)( @@ -39,7 +39,7 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule } } -class APBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) { - val dut = Module(LazyModule(new APBFuzzBridge).module) +class APBBridgeTest(aFlow: Boolean)(implicit p: Parameters) extends UnitTest(500000) { + val dut = Module(LazyModule(new APBFuzzBridge(aFlow)).module) io.finished := dut.io.finished } diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index 482e72bf..ac825820 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -15,7 +15,8 @@ class WithUncoreUnitTests extends Config((site, here, up) => { Module(new uncore.ahb.AHBBridgeTest(true)), Module(new uncore.ahb.AHBNativeTest(true)), Module(new uncore.ahb.AHBNativeTest(false)), - Module(new uncore.apb.APBBridgeTest), + Module(new uncore.apb.APBBridgeTest(true)), + Module(new uncore.apb.APBBridgeTest(false)), Module(new uncore.axi4.AXI4LiteFuzzRAMTest), Module(new uncore.axi4.AXI4FullFuzzRAMTest), Module(new uncore.axi4.AXI4BridgeTest)) } From 9b5b3279a66852a466b9f6788110f72ae327e731 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 16 Mar 2017 18:18:29 -0700 Subject: [PATCH 9/9] AHBToTL: don't report error during idle cycles --- src/main/scala/uncore/ahb/ToTL.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/ahb/ToTL.scala b/src/main/scala/uncore/ahb/ToTL.scala index 7d721f84..0a2a7cda 100644 --- a/src/main/scala/uncore/ahb/ToTL.scala +++ b/src/main/scala/uncore/ahb/ToTL.scala @@ -56,7 +56,7 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule val d_addr = Reg(in.haddr) 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) } val a_count = RegInit(UInt(0, width = 4)) @@ -87,14 +87,12 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule when (a_accept) { a_count := a_count - UInt(1) - d_error := d_error || !a_legal when ( in.hwrite) { d_send := Bool(true) } when (!in.hwrite) { d_recv := Bool(true) } when (a_first) { a_count := Mux(a_burst_ok, a_burst_mask >> log2Ceil(beatBytes), UInt(0)) d_send := a_legal d_recv := a_legal - d_error := !a_legal d_pause := Bool(false) d_write := in.hwrite d_addr := in.haddr @@ -111,7 +109,11 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule out.a.bits.data := in.hwdata 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 val inject_error = d_last && (d_error || (out.d.valid && out.d.bits.error)) when (inject_error) { d_pause := Bool(true) }