Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #86 from ucb-bar/iocell-params
Browse files Browse the repository at this point in the history
Clean up IOCell types and parameterization
  • Loading branch information
jerryz123 authored Sep 14, 2020
2 parents f791073 + ba68167 commit e6e1ed8
Showing 1 changed file with 35 additions and 48 deletions.
83 changes: 35 additions & 48 deletions iocell/src/main/scala/chisel/IOCell.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand All @@ -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
Expand All @@ -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](
Expand All @@ -165,15 +152,15 @@ 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
iocell.io.pad := castToBool(padSignal)
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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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
}
}
Expand Down

0 comments on commit e6e1ed8

Please sign in to comment.