tilelink2: connect abstract register-based modules to TileLink
This commit is contained in:
		
							
								
								
									
										29
									
								
								uncore/src/main/scala/tilelink2/GPIO.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								uncore/src/main/scala/tilelink2/GPIO.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore.tilelink2
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
case class GPIOParams(num: Int, address: Option[BigInt] = None)
 | 
			
		||||
 | 
			
		||||
trait GPIOBundle
 | 
			
		||||
{
 | 
			
		||||
  val params: GPIOParams
 | 
			
		||||
  val gpio = UInt(width = params.num)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait GPIOModule extends HasRegMap
 | 
			
		||||
{
 | 
			
		||||
  val params: GPIOParams
 | 
			
		||||
  val io: GPIOBundle
 | 
			
		||||
 | 
			
		||||
  val state = RegInit(UInt(0))
 | 
			
		||||
  io.gpio := state
 | 
			
		||||
 | 
			
		||||
  regmap(0 -> Seq(RegField(params.num, state)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a concrete TL2 version of the abstract GPIO slave
 | 
			
		||||
class TLGPIO(p: GPIOParams) extends TLRegisterRouter(p.address)(
 | 
			
		||||
  new TLRegBundle(p, _)    with GPIOBundle)(
 | 
			
		||||
  new TLRegModule(p, _, _) with GPIOModule)
 | 
			
		||||
@@ -5,6 +5,10 @@ package uncore.tilelink2
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn)
 | 
			
		||||
{
 | 
			
		||||
  require (width > 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object RegField
 | 
			
		||||
{
 | 
			
		||||
  type ReadFn = Bool => (Bool, UInt)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										122
									
								
								uncore/src/main/scala/tilelink2/RegisterRouter.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								uncore/src/main/scala/tilelink2/RegisterRouter.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore.tilelink2
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
class TLRegisterNode(address: AddressSet, beatBytes: Int = 4)
 | 
			
		||||
  extends TLManagerNode(beatBytes, TLManagerParameters(
 | 
			
		||||
    address            = Seq(address),
 | 
			
		||||
    supportsGet        = TransferSizes(1, beatBytes),
 | 
			
		||||
    supportsPutPartial = TransferSizes(1, beatBytes),
 | 
			
		||||
    supportsPutFull    = TransferSizes(1, beatBytes),
 | 
			
		||||
    fifoId             = Some(0))) // requests are handled in order
 | 
			
		||||
{
 | 
			
		||||
  require (!address.strided)
 | 
			
		||||
 | 
			
		||||
  // Calling this method causes the matching TL2 bundle to be
 | 
			
		||||
  // configured to route all requests to the listed RegFields.
 | 
			
		||||
  def regmap(mapping: RegField.Map*) = {
 | 
			
		||||
    val regmap = mapping.toList
 | 
			
		||||
    require (!regmap.isEmpty)
 | 
			
		||||
 | 
			
		||||
    // Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
 | 
			
		||||
    val flat = regmap.map { case (reg, fields) => 
 | 
			
		||||
      val offsets = fields.scanLeft(0)(_ + _.width).init
 | 
			
		||||
      (offsets zip fields) map { case (o, f) => (reg, o, f) }
 | 
			
		||||
    }.flatten
 | 
			
		||||
 | 
			
		||||
    // Confirm that no register is too big
 | 
			
		||||
    require (flat.map(_._2).max <= beatBytes*8)
 | 
			
		||||
 | 
			
		||||
    // All registers must fit inside the device address space
 | 
			
		||||
    val maxIndex = regmap.map(_._1).max
 | 
			
		||||
    require (address.mask >= maxIndex*beatBytes)
 | 
			
		||||
 | 
			
		||||
    // Which register is touched?
 | 
			
		||||
    val alignBits = log2Ceil(beatBytes)
 | 
			
		||||
    val addressBits = log2Up(maxIndex+1)
 | 
			
		||||
    val a = bundleIn(0).a // Must apply Queue !!! (so no change once started)
 | 
			
		||||
    val d = bundleIn(0).d
 | 
			
		||||
    val regIdx = a.bits.address(addressBits+alignBits-1, alignBits)
 | 
			
		||||
    val regSel = UIntToOH(regIdx)
 | 
			
		||||
 | 
			
		||||
    // What is the access?
 | 
			
		||||
    val opcode = a.bits.opcode
 | 
			
		||||
    val read  = a.valid && opcode === TLMessages.Get
 | 
			
		||||
    val write = a.valid && (opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData)
 | 
			
		||||
    val wmaskWide = Vec.tabulate(beatBytes*8) { i => a.bits.wmask(i/8) } .toBits.asUInt
 | 
			
		||||
    val dataIn = a.bits.data & wmaskWide // zero undefined bits
 | 
			
		||||
 | 
			
		||||
    // The output values for each register
 | 
			
		||||
    val dataOutAcc = Array.tabulate(maxIndex+1) { _ => UInt(0) }
 | 
			
		||||
    // The ready state for read and write
 | 
			
		||||
    val rReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) }
 | 
			
		||||
    val wReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) }
 | 
			
		||||
 | 
			
		||||
    // Apply all the field methods
 | 
			
		||||
    flat.foreach { case (reg, low, field) =>
 | 
			
		||||
      val high = low + field.width - 1
 | 
			
		||||
      val rfire = wmaskWide(high, low).orR()
 | 
			
		||||
      val wfire = wmaskWide(high, low).andR()
 | 
			
		||||
      val sel = regSel(reg)
 | 
			
		||||
      val ren = read  && sel && rfire
 | 
			
		||||
      val wen = write && sel && wfire
 | 
			
		||||
      val (rReady, rResult) = field.read(ren)
 | 
			
		||||
      val wReady = field.write(wen, dataIn(high, low))
 | 
			
		||||
      dataOutAcc(reg) = dataOutAcc(reg) | (rResult << low)
 | 
			
		||||
      rReadyAcc(reg) = rReadyAcc(reg) && (!rfire || rReady)
 | 
			
		||||
      wReadyAcc(reg) = wReadyAcc(reg) && (!wfire || wReady)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create the output data signal
 | 
			
		||||
    val dataOut = Vec(dataOutAcc)(regIdx)
 | 
			
		||||
    val rReady = Vec(rReadyAcc)(regIdx)
 | 
			
		||||
    val wReady = Vec(wReadyAcc)(regIdx)
 | 
			
		||||
 | 
			
		||||
    val ready = (read && rReady) || (write && wReady)
 | 
			
		||||
    a.ready := ready && d.ready
 | 
			
		||||
    d.valid := a.valid && ready
 | 
			
		||||
 | 
			
		||||
    val edge = edgesIn(0)
 | 
			
		||||
    d.bits := edge.AccessAck(a.bits.source, a.bits.size)
 | 
			
		||||
    // avoid a Mux on the data bus by manually overriding two fields
 | 
			
		||||
    d.bits.data := dataOut
 | 
			
		||||
    d.bits.opcode := Mux(opcode === TLMessages.Get, TLMessages.AccessAck, TLMessages.AccessAckData)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object TLRegisterNode
 | 
			
		||||
{
 | 
			
		||||
  def apply(address: AddressSet, beatBytes: Int = 4) = new TLRegisterNode(address, beatBytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// These convenience methods below combine to make it possible to create a TL2 
 | 
			
		||||
// register mapped device from a totally abstract register mapped device.
 | 
			
		||||
// See GPIO.scala in this directory for an example
 | 
			
		||||
 | 
			
		||||
abstract class TLRegFactory(address: AddressSet, beatBytes: Int) extends TLFactory
 | 
			
		||||
{
 | 
			
		||||
  val node = TLRegisterNode(address, beatBytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle
 | 
			
		||||
 | 
			
		||||
class TLRegModule[P, B <: Bundle](val params: P, val io: B, factory: TLRegFactory)
 | 
			
		||||
  extends TLModule(factory) with HasRegMap
 | 
			
		||||
{
 | 
			
		||||
  def regmap(mapping: RegField.Map*) = factory.node.regmap(mapping:_*)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class TLRegisterRouter[B <: Bundle, M <: TLModule]
 | 
			
		||||
   (address: Option[BigInt] = None, size: BigInt = 4096, beatBytes: Int = 4)
 | 
			
		||||
   (bundleBuilder: Vec[TLBundle] => B)
 | 
			
		||||
   (moduleBuilder: (B, TLRegFactory) => M)
 | 
			
		||||
  extends TLRegFactory(AddressSet(size-1, address), beatBytes)
 | 
			
		||||
{
 | 
			
		||||
  require (size % 4096 == 0) // devices should be 4K aligned
 | 
			
		||||
  require (isPow2(size))
 | 
			
		||||
  require (size >= 4096)
 | 
			
		||||
 | 
			
		||||
  lazy val module = Module(moduleBuilder(bundleBuilder(node.bundleIn), this))
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user