From 51dfb9cb0656a1b0906cae34b4e451d4e834d67b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 7 Dec 2016 20:47:11 -0800 Subject: [PATCH] ahb: TileLink master --- src/main/scala/uncore/tilelink2/ToAHB.scala | 141 ++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/main/scala/uncore/tilelink2/ToAHB.scala diff --git a/src/main/scala/uncore/tilelink2/ToAHB.scala b/src/main/scala/uncore/tilelink2/ToAHB.scala new file mode 100644 index 00000000..bdc8b454 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/ToAHB.scala @@ -0,0 +1,141 @@ +// See LICENSE.SiFive for license details. + +package uncore.tilelink2 + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import config._ +import diplomacy._ +import util.PositionalMultiQueue +import uncore.ahb._ +import scala.math.{min, max} +import AHBParameters._ + +case class TLToAHBNode() extends MixedNode(TLImp, AHBImp)( + dFn = { case (1, Seq(TLClientPortParameters(clients, unsafeAtomics, minLatency))) => + val masters = clients.map { case c => AHBMasterParameters(nodePath = c.nodePath) } + Seq(AHBMasterPortParameters(masters)) + }, + uFn = { case (1, Seq(AHBSlavePortParameters(slaves, beatBytes))) => + val managers = slaves.map { case s => + TLManagerParameters( + address = s.address, + regionType = s.regionType, + executable = s.executable, + nodePath = s.nodePath, + supportsGet = s.supportsRead, + supportsPutFull = s.supportsWrite, // but not PutPartial + fifoId = Some(0)) // a common FIFO domain + } + Seq(TLManagerPortParameters(managers, beatBytes, 1, 1)) + }, + numPO = 1 to 1, + numPI = 1 to 1) + +class TLToAHB(combinational: Boolean = true)(implicit p: Parameters) extends LazyModule +{ + val node = TLToAHBNode() + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val in = io.in(0) + val out = io.out(0) + val edgeIn = node.edgesIn(0) + val edgeOut = node.edgesOut(0) + 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) + + // 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. + val d = Wire(in.d) + in.d <> Queue(d, 1, flow = true) + val a_quash = in.d.valid && !in.d.ready + + // 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()) + + 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 + } + } + + // 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) + + 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 := Bool(true) + 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()) + } +} + +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 axi4 = LazyModule(new TLToAHB(combinational)) + axi4.node := x + axi4.node + } +}