1
0
Fork 0
rocket-chip/src/main/scala/uncore/tilelink2/ToAHB.scala

142 lines
5.2 KiB
Scala
Raw Normal View History

2016-12-08 05:47:11 +01:00
// 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
}
}