package sifive.blocks.devices.gpio
import Chisel._
-import config.Parameters
-import regmapper._
-import uncore.tilelink2._
-import util.AsyncResetRegVec
-
-case class GPIOParams(address: BigInt, width: Int)
-
-// YAGNI: Make the PUE, DS, and
-// these also optionally HW controllable.
-// This is the base class of things you "always"
-// want to control from a HW block.
-class GPIOCtrl extends Bundle {
- val oval = Bool()
- val oe = Bool()
- val ie = Bool()
-}
+import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl}
+import freechips.rocketchip.config.Parameters
+import freechips.rocketchip.util.SynchronizerShiftReg
+import freechips.rocketchip.regmapper._
+import freechips.rocketchip.tilelink._
+import freechips.rocketchip.util.{AsyncResetRegVec, GenericParameterizedBundle}
+
+case class GPIOParams(address: BigInt, width: Int, includeIOF: Boolean = false)
-// This is the actual IOF interface.
+// This is the actual IOF interface.pa
// Add a valid bit to indicate whether
// there is something actually connected
// to this.
-class GPIOPinIOFCtrl extends GPIOCtrl {
+class IOFCtrl extends PinCtrl {
val valid = Bool()
}
// By default,
-object GPIOPinIOFCtrl {
- def apply(): GPIOPinIOFCtrl = {
- val iof = Wire(new GPIOPinIOFCtrl())
+object IOFCtrl {
+ def apply(): IOFCtrl = {
+ val iof = Wire(new IOFCtrl())
iof.valid := Bool(false)
iof.oval := Bool(false)
iof.oe := Bool(false)
}
}
-// This is the control for a physical
-// Pad.
-
-class GPIOPinCtrl extends GPIOCtrl {
- val pue = Bool() // Pull-up Enable
- val ds = Bool() // Drive Strength
-}
-
-object GPIOPinCtrl {
- def apply(): GPIOPinCtrl = {
- val pin = Wire(new GPIOPinCtrl())
- pin.oval := Bool(false)
- pin.oe := Bool(false)
- pin.pue := Bool(false)
- pin.ds := Bool(false)
- pin.ie := Bool(false)
- pin
- }
-}
-
// Package up the inputs and outputs
// for the IOF
-class GPIOPinIOF extends Bundle {
- val i = new Bundle {
- val ival = Bool(INPUT)
+class IOFPin extends Pin {
+ val o = new IOFCtrl().asOutput
+
+ def default(): Unit = {
+ this.o.oval := Bool(false)
+ this.o.oe := Bool(false)
+ this.o.ie := Bool(false)
+ this.o.valid := Bool(false)
+ }
+
+ def inputPin(pue: Bool = Bool(false) /*ignored*/): Bool = {
+ this.o.oval := Bool(false)
+ this.o.oe := Bool(false)
+ this.o.ie := Bool(true)
+ this.i.ival
+ }
+ def outputPin(signal: Bool,
+ pue: Bool = Bool(false), /*ignored*/
+ ds: Bool = Bool(false), /*ignored*/
+ ie: Bool = Bool(false)
+ ): Unit = {
+ this.o.oval := signal
+ this.o.oe := Bool(true)
+ this.o.ie := ie
}
- val o = new GPIOPinIOFCtrl().asOutput
}
// Connect both the i and o side of the pin,
// and drive the valid signal for the IOF.
-object GPIOPinToIOF {
-
- def apply (pin: GPIOPin, iof: GPIOPinIOF): Unit = {
+object BasePinToIOF {
+ def apply(pin: BasePin, iof: IOFPin): Unit = {
iof <> pin
iof.o.valid := Bool(true)
}
-
-}
-
-// Package up the inputs and outputs
-// for the Pin
-class GPIOPin extends Bundle {
- val i = new Bundle {
- val ival = Bool(INPUT)
- }
- val o = new GPIOPinCtrl().asOutput
}
// This is sort of weird because
// level, and we have to do the pinmux
// outside of RocketChipTop.
-class GPIOPortIO(c: GPIOParams) extends Bundle {
- val pins = Vec(c.width, new GPIOPin)
- val iof_0 = Vec(c.width, new GPIOPinIOF).flip
- val iof_1 = Vec(c.width, new GPIOPinIOF).flip
+class GPIOPortIO(c: GPIOParams) extends GenericParameterizedBundle(c) {
+ val pins = Vec(c.width, new EnhancedPin())
+ val iof_0 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
+ val iof_1 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
}
// It would be better if the IOF were here and
// we could do the pinmux inside.
trait HasGPIOBundleContents extends Bundle {
- val params: GPIOParams
+ def params: GPIOParams
val port = new GPIOPortIO(params)
}
// Synchronize Input to get valueReg
val inVal = Wire(UInt(0, width=c.width))
inVal := Vec(io.port.pins.map(_.i.ival)).asUInt
- val inSyncReg = ShiftRegister(inVal, 3)
+ val inSyncReg = SynchronizerShiftReg(inVal, 3, Some("inSyncReg"))
val valueReg = Reg(init = UInt(0, c.width), next = inSyncReg)
// Interrupt Configuration
// HW IO Function
val iofEnReg = Module(new AsyncResetRegVec(c.width, 0))
val iofSelReg = Reg(init = UInt(0, c.width))
-
+
// Invert Output
val xorReg = Reg(init = UInt(0, c.width))
val rise = ~valueReg & inSyncReg;
val fall = valueReg & ~inSyncReg;
+ val iofEnFields = if (c.includeIOF) (Seq(RegField.rwReg(c.width, iofEnReg.io))) else (Seq(RegField(c.width)))
+ val iofSelFields = if (c.includeIOF) (Seq(RegField(c.width, iofSelReg))) else (Seq(RegField(c.width)))
+
+
// Note that these are out of order.
regmap(
GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg)),
GPIOCtrlRegs.low_ip -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
GPIOCtrlRegs.port -> Seq(RegField(c.width, portReg)),
GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
- GPIOCtrlRegs.iof_en -> Seq(RegField.rwReg(c.width, iofEnReg.io)),
- GPIOCtrlRegs.iof_sel -> Seq(RegField(c.width, iofSelReg)),
+ GPIOCtrlRegs.iof_en -> iofEnFields,
+ GPIOCtrlRegs.iof_sel -> iofSelFields,
GPIOCtrlRegs.drive -> Seq(RegField(c.width, dsReg)),
GPIOCtrlRegs.input_en -> Seq(RegField.rwReg(c.width, ieReg.io)),
GPIOCtrlRegs.out_xor -> Seq(RegField(c.width, xorReg))
// Actual Pinmux
// -------------------------------------------------
- val swPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+ val swPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
// This strips off the valid.
- val iof0Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
- val iof1Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
-
- val iofCtrl = Wire(Vec(c.width, new GPIOCtrl()))
- val iofPlusSwPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+ val iof0Ctrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
+ val iof1Ctrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
+ val iofCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
+ val iofPlusSwPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
for (pin <- 0 until c.width) {
swPinCtrl(pin).ds := dsReg(pin)
swPinCtrl(pin).ie := ieReg.io.q(pin)
- // Allow SW Override for invalid inputs.
- iof0Ctrl(pin) <> swPinCtrl(pin)
- when (io.port.iof_0(pin).o.valid) {
- iof0Ctrl(pin) <> io.port.iof_0(pin).o
+ val pre_xor = Wire(new EnhancedPinCtrl())
+
+ if (c.includeIOF) {
+ // Allow SW Override for invalid inputs.
+ iof0Ctrl(pin) <> swPinCtrl(pin)
+ when (io.port.iof_0.get(pin).o.valid) {
+ iof0Ctrl(pin) <> io.port.iof_0.get(pin).o
+ }
+
+ iof1Ctrl(pin) <> swPinCtrl(pin)
+ when (io.port.iof_1.get(pin).o.valid) {
+ iof1Ctrl(pin) <> io.port.iof_1.get(pin).o
+ }
+
+ // Select IOF 0 vs. IOF 1.
+ iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
+
+ // Allow SW Override for things IOF doesn't control.
+ iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
+ iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
+
+ // Final XOR & Pin Control
+ pre_xor := Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
+ } else {
+ pre_xor := swPinCtrl(pin)
}
- iof1Ctrl(pin) <> swPinCtrl(pin)
- when (io.port.iof_1(pin).o.valid) {
- iof1Ctrl(pin) <> io.port.iof_1(pin).o
- }
-
- // Select IOF 0 vs. IOF 1.
- iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
-
- // Allow SW Override for things IOF doesn't control.
- iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
- iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
-
- // Final XOR & Pin Control
- val pre_xor: GPIOPinCtrl = Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
io.port.pins(pin).o := pre_xor
io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
(highIpReg(pin) & highIeReg(pin)) |
(lowIpReg(pin) & lowIeReg(pin))
- // Send Value to all consumers
- io.port.iof_0(pin).i.ival := inSyncReg(pin)
- io.port.iof_1(pin).i.ival := inSyncReg(pin)
- }
-}
-
-object GPIOOutputPinCtrl {
-
- def apply( pin: GPIOPin, signal: Bool,
- pue: Bool = Bool(false),
- ds: Bool = Bool(false),
- ie: Bool = Bool(false)
- ): Unit = {
- pin.o.oval := signal
- pin.o.oe := Bool(true)
- pin.o.pue := pue
- pin.o.ds := ds
- pin.o.ie := ie
- }
-
- def apply(pins: Vec[GPIOPin], signals: Bits,
- pue: Bool, ds: Bool, ie: Bool
- ): Unit = {
- for ((signal, pin) <- (signals.toBools zip pins)) {
- apply(pin, signal, pue, ds, ie)
+ if (c.includeIOF) {
+ // Send Value to all consumers
+ io.port.iof_0.get(pin).i.ival := inSyncReg(pin)
+ io.port.iof_1.get(pin).i.ival := inSyncReg(pin)
}
}
-
- def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
- Bool(false), Bool(false), Bool(false))
-
-}
-
-object GPIOInputPinCtrl {
-
- def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
- pin.o.oval := Bool(false)
- pin.o.oe := Bool(false)
- pin.o.pue := pue
- pin.o.ds := Bool(false)
- pin.o.ie := Bool(true)
-
- pin.i.ival
- }
-
- def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
- val signals = Wire(Vec.fill(pins.size)(Bool(false)))
- for ((signal, pin) <- (signals zip pins)) {
- signal := GPIOInputPinCtrl(pin, pue)
- }
- signals
- }
-
- def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
-
}
// Magic TL2 Incantation to create a TL2 Slave