From ba681676f338af158023c99b4c802009aa0b601b Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 4 Sep 2020 13:29:31 -0700 Subject: [PATCH] Clean up IOCell types and parameterization --- iocell/src/main/scala/chisel/IOCell.scala | 83 ++++++++++------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/iocell/src/main/scala/chisel/IOCell.scala b/iocell/src/main/scala/chisel/IOCell.scala index 14c29603..452aaded 100644 --- a/iocell/src/main/scala/chisel/IOCell.scala +++ b/iocell/src/main/scala/chisel/IOCell.scala @@ -4,7 +4,7 @@ package barstools.iocell.chisel import chisel3._ import chisel3.util.{Cat, HasBlackBoxResource} -import chisel3.experimental.{Analog, DataMirror, IO} +import chisel3.experimental.{Analog, DataMirror, IO, BaseModule} // The following four IO cell bundle types are bare-minimum functional connections // for modeling 4 different IO cell scenarios. The intention is that the user @@ -63,76 +63,68 @@ class DigitalInIOCellBundle extends Bundle { val ie = Input(Bool()) } -abstract class IOCell extends BlackBox +trait IOCell extends BaseModule -abstract class AnalogIOCell extends IOCell { - val io: AnalogIOCellBundle +trait AnalogIOCell extends IOCell { + val io = IO(new AnalogIOCellBundle) } -abstract class DigitalGPIOCell extends IOCell { - val io: DigitalGPIOCellBundle +trait DigitalGPIOCell extends IOCell { + val io = IO(new DigitalGPIOCellBundle) } -abstract class DigitalInIOCell extends IOCell { - val io: DigitalInIOCellBundle +trait DigitalInIOCell extends IOCell { + val io = IO(new DigitalInIOCellBundle) } -abstract class DigitalOutIOCell extends IOCell { - val io: DigitalOutIOCellBundle +trait DigitalOutIOCell extends IOCell { + val io = IO(new DigitalOutIOCellBundle) } // The following Generic IO cell black boxes have verilog models that mimic a very simple // implementation of an IO cell. For building a real chip, it is important to implement // and use similar classes which wrap the foundry-specific IO cells. -trait IsGenericIOCell extends HasBlackBoxResource { +abstract class GenericIOCell extends BlackBox with HasBlackBoxResource { addResource("/barstools/iocell/vsrc/IOCell.v") } -class GenericAnalogIOCell extends AnalogIOCell with IsGenericIOCell { - val io = IO(new AnalogIOCellBundle) -} +class GenericAnalogIOCell extends GenericIOCell with AnalogIOCell +class GenericDigitalGPIOCell extends GenericIOCell with DigitalGPIOCell +class GenericDigitalInIOCell extends GenericIOCell with DigitalInIOCell +class GenericDigitalOutIOCell extends GenericIOCell with DigitalOutIOCell -class GenericDigitalGPIOCell extends DigitalGPIOCell with IsGenericIOCell { - val io = IO(new DigitalGPIOCellBundle) +trait IOCellTypeParams { + def analog(): AnalogIOCell + def gpio(): DigitalGPIOCell + def input(): DigitalInIOCell + def output(): DigitalOutIOCell } -class GenericDigitalInIOCell extends DigitalInIOCell with IsGenericIOCell { - val io = IO(new DigitalInIOCellBundle) -} - -class GenericDigitalOutIOCell extends DigitalOutIOCell with IsGenericIOCell { - val io = IO(new DigitalOutIOCellBundle) +case class GenericIOCellParams() extends IOCellTypeParams { + def analog() = Module(new GenericAnalogIOCell) + def gpio() = Module(new GenericDigitalGPIOCell) + def input() = Module(new GenericDigitalInIOCell) + def output() = Module(new GenericDigitalOutIOCell) } object IOCell { - - def genericAnalog() = Module(new GenericAnalogIOCell) - def genericGPIO() = Module(new GenericDigitalGPIOCell) - def genericInput() = Module(new GenericDigitalInIOCell) - def genericOutput() = Module(new GenericDigitalOutIOCell) - /** * From within a RawModule or MultiIOModule context, generate new module IOs from a given * signal and return the new IO and a Seq containing all generated IO cells. * @param coreSignal The signal onto which to add IO cells * @param name An optional name or name prefix to use for naming IO cells - * @param inFn A function to generate a DigitalInIOCell to use for input signals - * @param outFn A function to generate a DigitalOutIOCell to use for output signals - * @param anaFn A function to generate an AnalogIOCell to use for analog signals * @param abstractResetAsAsync When set, will coerce abstract resets to * AsyncReset, and otherwise to Bool (sync reset) * @return A tuple of (the generated IO data node, a Seq of all generated IO cell instances) */ def generateIOFromSignal[T <: Data](coreSignal: T, name: Option[String] = None, - inFn: () => DigitalInIOCell = IOCell.genericInput, - outFn: () => DigitalOutIOCell = IOCell.genericOutput, - anaFn: () => AnalogIOCell = IOCell.genericAnalog, + typeParams: IOCellTypeParams = GenericIOCellParams(), abstractResetAsAsync: Boolean = false): (T, Seq[IOCell]) = { val padSignal = IO(DataMirror.internal.chiselTypeClone[T](coreSignal)) val resetFn = if (abstractResetAsAsync) toAsyncReset else toSyncReset - val iocells = IOCell.generateFromSignal(coreSignal, padSignal, name, inFn, outFn, anaFn, resetFn) + val iocells = IOCell.generateFromSignal(coreSignal, padSignal, name, typeParams, resetFn) (padSignal, iocells) } @@ -142,9 +134,6 @@ object IOCell { * @param coreSignal The core-side (internal) signal onto which to connect/add IO cells * @param padSignal The pad-side (external) signal onto which to connect IO cells * @param name An optional name or name prefix to use for naming IO cells - * @param inFn A function to generate a DigitalInIOCell to use for input signals - * @param outFn A function to generate a DigitalOutIOCell to use for output signals - * @param anaFn A function to generate an AnalogIOCell to use for analog signals * @return A Seq of all generated IO cell instances */ val toSyncReset: (Reset) => Bool = _.toBool @@ -153,9 +142,7 @@ object IOCell { coreSignal: T, padSignal: T, name: Option[String] = None, - inFn: () => DigitalInIOCell = IOCell.genericInput, - outFn: () => DigitalOutIOCell = IOCell.genericOutput, - anaFn: () => AnalogIOCell = IOCell.genericAnalog, + typeParams: IOCellTypeParams = GenericIOCellParams(), concretizeResetFn : (Reset) => R = toSyncReset): Seq[IOCell] = { def genCell[T <: Data]( @@ -165,7 +152,7 @@ object IOCell { padSignal: T): Seq[IOCell] = { DataMirror.directionOf(coreSignal) match { case ActualDirection.Input => { - val iocell = inFn() + val iocell = typeParams.input() name.foreach(n => iocell.suggestName(n)) coreSignal := castFromBool(iocell.io.i) iocell.io.ie := true.B @@ -173,7 +160,7 @@ object IOCell { Seq(iocell) } case ActualDirection.Output => { - val iocell = outFn() + val iocell = typeParams.output() name.foreach(n => iocell.suggestName(n)) iocell.io.o := castToBool(coreSignal) iocell.io.oe := true.B @@ -193,7 +180,7 @@ object IOCell { Seq() } else { require(coreSignal.getWidth == 1, "Analogs wider than 1 bit are not supported because we can't bit-select Analogs (https://github.com/freechipsproject/chisel3/issues/536)") - val iocell = anaFn() + val iocell = typeParams.analog() name.foreach(n => iocell.suggestName(n)) iocell.io.core <> coreSignal padSignal <> iocell.io.pad @@ -215,7 +202,7 @@ object IOCell { DataMirror.directionOf(coreSignal) match { case ActualDirection.Input => { val iocells = padSignal.asBools.zipWithIndex.map { case (sig, i) => - val iocell = inFn() + val iocell = typeParams.input() // Note that we are relying on chisel deterministically naming this in the index order (which it does) // This has the side-effect of naming index 0 with no _0 suffix, which is how chisel names other signals // An alternative solution would be to suggestName(n + "_" + i) @@ -230,7 +217,7 @@ object IOCell { } case ActualDirection.Output => { val iocells = coreSignal.asBools.zipWithIndex.map { case (sig, i) => - val iocell = outFn() + val iocell = typeParams.output() // Note that we are relying on chisel deterministically naming this in the index order (which it does) // This has the side-effect of naming index 0 with no _0 suffix, which is how chisel names other signals // An alternative solution would be to suggestName(n + "_" + i) @@ -251,14 +238,14 @@ object IOCell { case (coreSignal: Vec[_], padSignal: Vec[_]) => { require(padSignal.size == coreSignal.size, "size of Vec for padSignal and coreSignal must be the same") coreSignal.zip(padSignal).zipWithIndex.foldLeft(Seq.empty[IOCell]) { case (total, ((core, pad), i)) => - val ios = IOCell.generateFromSignal(core, pad, name.map(_ + "_" + i), inFn, outFn, anaFn) + val ios = IOCell.generateFromSignal(core, pad, name.map(_ + "_" + i), typeParams) total ++ ios } } case (coreSignal: Record, padSignal: Record) => { coreSignal.elements.foldLeft(Seq.empty[IOCell]) { case (total, (eltName, core)) => val pad = padSignal.elements(eltName) - val ios = IOCell.generateFromSignal(core, pad, name.map(_ + "_" + eltName), inFn, outFn, anaFn) + val ios = IOCell.generateFromSignal(core, pad, name.map(_ + "_" + eltName), typeParams) total ++ ios } }