1
0

Make it possible to adjust the type of pad controls used,

and seperate out some of the "GPIO Peripheral" from "Pin Control"
This commit is contained in:
Megan Wachs 2017-07-18 10:58:04 -07:00
parent fb9dd31374
commit 4d74e8f67f
11 changed files with 198 additions and 236 deletions

View File

@ -2,6 +2,7 @@
package sifive.blocks.devices.gpio
import Chisel._
import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl}
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
@ -9,28 +10,18 @@ import freechips.rocketchip.util.{AsyncResetRegVec, GenericParameterizedBundle}
case class GPIOParams(address: BigInt, width: Int, includeIOF: Boolean = false)
// 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()
}
// 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)
@ -39,53 +30,34 @@ object GPIOPinIOFCtrl {
}
}
// 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 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 = {
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
@ -94,9 +66,9 @@ class GPIOPin extends Bundle {
// outside of RocketChipTop.
class GPIOPortIO(c: GPIOParams) extends GenericParameterizedBundle(c) {
val pins = Vec(c.width, new GPIOPin)
val iof_0 = if (c.includeIOF) Some(Vec(c.width, new GPIOPinIOF).flip) else None
val iof_1 = if (c.includeIOF) Some(Vec(c.width, new GPIOPinIOF).flip) else None
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
@ -183,15 +155,14 @@ trait HasGPIOModuleContents extends Module with HasRegMap {
// 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) {
@ -202,7 +173,7 @@ trait HasGPIOModuleContents extends Module with HasRegMap {
swPinCtrl(pin).ds := dsReg(pin)
swPinCtrl(pin).ie := ieReg.io.q(pin)
val pre_xor = Wire(new GPIOPinCtrl())
val pre_xor = Wire(new EnhancedPinCtrl())
if (c.includeIOF) {
// Allow SW Override for invalid inputs.
@ -246,57 +217,6 @@ trait HasGPIOModuleContents extends Module with HasRegMap {
}
}
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)
}
}
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
class TLGPIO(w: Int, c: GPIOParams)(implicit p: Parameters)
extends TLRegisterRouter(c.address, "gpio", Seq("sifive,gpio0"), interrupts = c.width, beatBytes = w)(

View File

@ -12,30 +12,23 @@ import Chisel._
import freechips.rocketchip.config._
import freechips.rocketchip.jtag.{JTAGIO}
import sifive.blocks.devices.pinctrl.{Pin, PinCtrl}
class JTAGPinsIO(hasTRSTn: Boolean = true) extends Bundle {
class JTAGPins[T <: Pin](pingen: () => T, hasTRSTn: Boolean = true) extends Bundle {
val TCK = new GPIOPin()
val TMS = new GPIOPin()
val TDI = new GPIOPin()
val TDO = new GPIOPin()
val TRSTn = if (hasTRSTn) Option(new GPIOPin()) else None
val TCK = pingen()
val TMS = pingen()
val TDI = pingen()
val TDO = pingen()
val TRSTn = if (hasTRSTn) Option(pingen()) else None
def fromJTAGPort(jtag: JTAGIO): Unit = {
jtag.TCK := TCK.inputPin (pue = Bool(true)).asClock
jtag.TMS := TMS.inputPin (pue = Bool(true))
jtag.TDI := TDI.inputPin(pue = Bool(true))
jtag.TRSTn.foreach{t => t := TRSTn.get.inputPin(pue = Bool(true))}
TDO.outputPin(jtag.TDO.data)
TDO.o.oe := jtag.TDO.driven
}
class JTAGGPIOPort(hasTRSTn: Boolean = true)(implicit p: Parameters) extends Module {
val io = new Bundle {
// TODO: make this not hard-coded true.
val jtag = new JTAGIO(hasTRSTn)
val pins = new JTAGPinsIO(hasTRSTn)
}
io.jtag.TCK := GPIOInputPinCtrl(io.pins.TCK, pue = Bool(true)).asClock
io.jtag.TMS := GPIOInputPinCtrl(io.pins.TMS, pue = Bool(true))
io.jtag.TDI := GPIOInputPinCtrl(io.pins.TDI, pue = Bool(true))
io.jtag.TRSTn.foreach{t => t := GPIOInputPinCtrl(io.pins.TRSTn.get, pue = Bool(true))}
GPIOOutputPinCtrl(io.pins.TDO, io.jtag.TDO.data)
io.pins.TDO.o.oe := io.jtag.TDO.driven
}

View File

@ -46,7 +46,6 @@ import freechips.rocketchip.config._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.{AsyncResetRegVec, Majority}
import sifive.blocks.devices.gpio.{GPIOPinCtrl}
case class I2CParams(address: BigInt)

View File

@ -21,12 +21,6 @@ trait HasPeripheryI2C extends HasSystemNetworks {
trait HasPeripheryI2CBundle {
val i2cs: Vec[I2CPort]
def I2CtoGPIOPins(syncStages: Int = 0): Seq[I2CPinsIO] = i2cs.map { i =>
val pins = Module(new I2CGPIOPort(syncStages))
pins.io.i2c <> i
pins.io.pins
}
}
trait HasPeripheryI2CModuleImp extends LazyMultiIOModuleImp with HasPeripheryI2CBundle {

View File

@ -2,26 +2,22 @@
package sifive.blocks.devices.i2c
import Chisel._
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl}
import sifive.blocks.devices.pinctrl.{Pin, PinCtrl}
import sifive.blocks.util.ShiftRegisterInit
class I2CPinsIO extends Bundle {
val scl = new GPIOPin
val sda = new GPIOPin
}
class I2CPins[T <: Pin](pingen: () => T) extends Bundle {
class I2CGPIOPort(syncStages: Int = 0) extends Module {
val io = new Bundle{
val i2c = new I2CPort().flip()
val pins = new I2CPinsIO
}
val scl: T = pingen()
val sda: T = pingen()
GPIOOutputPinCtrl(io.pins.scl, io.i2c.scl.out, pue=true.B, ie = true.B)
io.pins.scl.o.oe := io.i2c.scl.oe
io.i2c.scl.in := ShiftRegisterInit(io.pins.scl.i.ival, syncStages, Bool(true))
def fromI2CPort(i2c: I2CPort, syncStages: Int = 0) = {
scl.outputPin(i2c.scl.out, pue=true.B, ie = true.B)
scl.o.oe := i2c.scl.oe
i2c.scl.in := ShiftRegisterInit(scl.i.ival, syncStages, Bool(true))
GPIOOutputPinCtrl(io.pins.sda, io.i2c.sda.out, pue=true.B, ie = true.B)
io.pins.sda.o.oe := io.i2c.sda.oe
io.i2c.sda.in := ShiftRegisterInit(io.pins.sda.i.ival, syncStages, Bool(true))
sda.outputPin(i2c.sda.out, pue=true.B, ie = true.B)
sda.o.oe := i2c.sda.oe
i2c.sda.in := ShiftRegisterInit(sda.i.ival, syncStages, Bool(true))
}
}

View File

@ -6,20 +6,20 @@ import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
import sifive.blocks.devices.pinctrl.{EnhancedPin}
import sifive.blocks.util.{DeglitchShiftRegister, ResetCatchAndSync}
/* The wrapper handles the Clock and Reset Generation for The AON block itself,
and instantiates real pad controls (aka pull-ups)*/
class MockAONWrapperPMUIO extends Bundle {
val dwakeup_n = new GPIOPin()
val vddpaden = new GPIOPin()
val dwakeup_n = new EnhancedPin()
val vddpaden = new EnhancedPin()
}
class MockAONWrapperPadsIO extends Bundle {
val erst_n = new GPIOPin()
val lfextclk = new GPIOPin()
val erst_n = new EnhancedPin()
val lfextclk = new EnhancedPin()
val pmu = new MockAONWrapperPMUIO()
}
@ -68,7 +68,7 @@ class MockAONWrapper(w: Int, c: MockAONParams)(implicit p: Parameters) extends L
// -----------------------------------------------
// ERST
val erst = ~ GPIOInputPinCtrl(pads.erst_n, pue = Bool(true))
val erst = ~pads.erst_n.inputPin(pue = Bool(true))
aon_io.resetCauses.erst := erst
aon_io.resetCauses.wdogrst := aon_io.wdog_rst
@ -94,7 +94,7 @@ class MockAONWrapper(w: Int, c: MockAONParams)(implicit p: Parameters) extends L
// Note that the actual mux lives inside AON itself.
// Therefore, the lfclk which comes out of AON is the
// true clock that AON and AONWrapper are running off of.
val lfextclk = GPIOInputPinCtrl(pads.lfextclk, pue=Bool(true))
val lfextclk = pads.lfextclk.inputPin(pue=Bool(true))
aon_io.lfextclk := lfextclk.asClock
// Drive AON's clock and Reset
@ -136,14 +136,14 @@ class MockAONWrapper(w: Int, c: MockAONParams)(implicit p: Parameters) extends L
// PMU <--> pads Interface
//--------------------------------------------------
val dwakeup_n_async = GPIOInputPinCtrl(pads.pmu.dwakeup_n, pue=Bool(true))
val dwakeup_n_async = pads.pmu.dwakeup_n.inputPin(pue=Bool(true))
val dwakeup_deglitch = Module (new DeglitchShiftRegister(3))
dwakeup_deglitch.clock := lfclk
dwakeup_deglitch.io.d := ~dwakeup_n_async
aon.module.io.pmu.dwakeup := dwakeup_deglitch.io.q
GPIOOutputPinCtrl(pads.pmu.vddpaden, aon.module.io.pmu.vddpaden)
pads.pmu.vddpaden.outputPin(aon.module.io.pmu.vddpaden)
//--------------------------------------------------
// Connect signals to MOFF

View File

@ -0,0 +1,96 @@
//See LICENSE for license details
package sifive.blocks.devices.pinctrl
import Chisel._
// This is the base class of things you "always"
// want to control from a HW block.
class PinCtrl extends Bundle {
val oval = Bool()
val oe = Bool()
val ie = Bool()
}
// Package up the inputs and outputs
// for the Pin
abstract class Pin extends Bundle {
val i = new Bundle {
val ival = Bool(INPUT)
}
val o: PinCtrl
// Must be defined by the subclasses
def inputPin(pue: Bool = Bool(false)): Bool
def outputPin(signal: Bool,
pue: Bool = Bool(false),
ds: Bool = Bool(false),
ie: Bool = Bool(false)
): Unit
def inputPin(pins: Vec[this.type], pue: Bool): Vec[Bool] = {
val signals = Wire(Vec(pins.length, new Bool()))
for ((signal, pin) <- (signals zip pins)) {
signal := pin.inputPin(pue)
}
signals
}
}
////////////////////////////////////////////////////////////////////////////////////
class BasePin extends Pin() {
val o = new PinCtrl().asOutput
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
}
}
/////////////////////////////////////////////////////////////////////////
class EnhancedPinCtrl extends PinCtrl {
val pue = Bool()
val ds = Bool()
}
class EnhancedPin extends Pin() {
val o = new EnhancedPinCtrl().asOutput
def inputPin(pue: Bool = Bool(false)): Bool = {
this.o.oval := Bool(false)
this.o.oe := Bool(false)
this.o.pue := pue
this.o.ds := Bool(false)
this.o.ie := Bool(true)
this.i.ival
}
def outputPin(signal: Bool,
pue: Bool = Bool(false),
ds: Bool = Bool(false),
ie: Bool = Bool(false)
): Unit = {
this.o.oval := signal
this.o.oe := Bool(true)
this.o.pue := pue
this.o.ds := ds
this.o.ie := ie
}
}

View File

@ -7,25 +7,22 @@ import freechips.rocketchip.diplomacy.{LazyModule,LazyMultiIOModuleImp}
import freechips.rocketchip.chip.HasSystemNetworks
import freechips.rocketchip.tilelink.TLFragmenter
import freechips.rocketchip.util.HeterogeneousBag
import sifive.blocks.devices.gpio._
import sifive.blocks.devices.pinctrl.{PinCtrl, Pin}
class PWMPortIO(val c: PWMParams) extends Bundle {
val port = Vec(c.ncmp, Bool()).asOutput
override def cloneType: this.type = new PWMPortIO(c).asInstanceOf[this.type]
}
class PWMPinsIO(val c: PWMParams) extends Bundle {
val pwm = Vec(c.ncmp, new GPIOPin)
}
class PWMPins[T <: Pin] (pingen: ()=> T, val c: PWMParams) extends Bundle {
class PWMGPIOPort(val c: PWMParams) extends Module {
val io = new Bundle {
val pwm = new PWMPortIO(c).flip()
val pins = new PWMPinsIO(c)
}
val pwm: Vec[T] = Vec(c.ncmp, pingen())
GPIOOutputPinCtrl(io.pins.pwm, io.pwm.port.asUInt)
def fromPWMPort(port: PWMPortIO) {
(pwm zip port.port) foreach {case (pin, port) =>
pin.outputPin(port)
}
}
}
case object PeripheryPWMKey extends Field[Seq[PWMParams]]
@ -43,11 +40,6 @@ trait HasPeripheryPWM extends HasSystemNetworks {
trait HasPeripheryPWMBundle {
val pwms: HeterogeneousBag[PWMPortIO]
def PWMtoGPIOPins(dummy: Int = 1): Seq[PWMPinsIO] = pwms.map { p =>
val pins = Module(new PWMGPIOPort(p.c))
pins.io.pwm <> p
pins.io.pins
}
}
trait HasPeripheryPWMModuleImp extends LazyMultiIOModuleImp with HasPeripheryPWMBundle {

View File

@ -23,11 +23,6 @@ trait HasPeripherySPI extends HasSystemNetworks {
trait HasPeripherySPIBundle {
val spis: HeterogeneousBag[SPIPortIO]
def SPItoGPIOPins(syncStages: Int = 0): Seq[SPIPinsIO] = spis.map { s =>
val pins = Module(new SPIGPIOPort(s.c, syncStages))
pins.io.spi <> s
pins.io.pins
}
}
trait HasPeripherySPIModuleImp extends LazyMultiIOModuleImp with HasPeripherySPIBundle {
@ -55,14 +50,6 @@ trait HasPeripherySPIFlash extends HasSystemNetworks {
trait HasPeripherySPIFlashBundle {
val qspi: HeterogeneousBag[SPIPortIO]
// It is important for SPIFlash that the syncStages is agreed upon, because
// internally it needs to realign the input data to the output SCK.
// Therefore, we rely on the syncStages parameter.
def SPIFlashtoGPIOPins(syncStages: Int = 0): Seq[SPIPinsIO] = qspi.map { s =>
val pins = Module(new SPIGPIOPort(s.c, syncStages))
pins.io.spi <> s
pins.io.pins
}
}
trait HasPeripherySPIFlashModuleImp extends LazyMultiIOModuleImp with HasPeripherySPIFlashBundle {

View File

@ -2,33 +2,27 @@
package sifive.blocks.devices.spi
import Chisel._
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
import sifive.blocks.devices.pinctrl.{PinCtrl, Pin}
class SPIPinsIO(c: SPIParamsBase) extends SPIBundle(c) {
val sck = new GPIOPin
val dq = Vec(4, new GPIOPin)
val cs = Vec(c.csWidth, new GPIOPin)
}
class SPIPins[T <: Pin] (pingen: ()=> T, c: SPIParamsBase) extends SPIBundle(c) {
class SPIGPIOPort(c: SPIParamsBase, syncStages: Int = 0, driveStrength: Bool = Bool(false)) extends Module {
val io = new SPIBundle(c) {
val spi = new SPIPortIO(c).flip
val pins = new SPIPinsIO(c)
}
val sck: T = pingen()
val dq: Vec[T] = Vec(4, pingen())
val cs: Vec[T] = Vec(c.csWidth, pingen())
GPIOOutputPinCtrl(io.pins.sck, io.spi.sck, ds = driveStrength)
def fromSPIPort(spi: SPIPortIO, syncStages: Int = 0, driveStrength: Bool = Bool(false)) {
GPIOOutputPinCtrl(io.pins.dq, Bits(0, io.spi.dq.size))
(io.pins.dq zip io.spi.dq).foreach {
case (p, s) =>
p.o.oval := s.o
sck.outputPin(spi.sck, ds = driveStrength)
(dq zip spi.dq).foreach {case (p, s) =>
p.outputPin(s.o, pue = Bool(true), ds = driveStrength)
p.o.oe := s.oe
p.o.ie := ~s.oe
p.o.pue := Bool(true)
p.o.ds := driveStrength
s.i := ShiftRegister(p.i.ival, syncStages)
}
GPIOOutputPinCtrl(io.pins.cs, io.spi.cs.asUInt)
io.pins.cs.foreach(_.o.ds := driveStrength)
(cs zip spi.cs) foreach { case (c, s) =>
c.outputPin(s, ds = driveStrength)
}
}
}

View File

@ -6,7 +6,7 @@ import freechips.rocketchip.config.Field
import freechips.rocketchip.diplomacy.{LazyModule, LazyMultiIOModuleImp}
import freechips.rocketchip.chip.HasSystemNetworks
import freechips.rocketchip.tilelink.TLFragmenter
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
import sifive.blocks.devices.pinctrl.{Pin, PinCtrl}
import sifive.blocks.util.ShiftRegisterInit
case object PeripheryUARTKey extends Field[Seq[UARTParams]]
@ -28,11 +28,6 @@ trait HasPeripheryUARTBundle {
uarts.foreach { _.rxd := UInt(1) }
}
def UARTtoGPIOPins(syncStages: Int = 0): Seq[UARTPinsIO] = uarts.map { u =>
val pins = Module(new UARTGPIOPort(syncStages))
pins.io.uart <> u
pins.io.pins
}
}
trait HasPeripheryUARTModuleImp extends LazyMultiIOModuleImp with HasPeripheryUARTBundle {
@ -44,18 +39,14 @@ trait HasPeripheryUARTModuleImp extends LazyMultiIOModuleImp with HasPeripheryUA
}
}
class UARTPinsIO extends Bundle {
val rxd = new GPIOPin
val txd = new GPIOPin
class UARTPins(pingen: () => Pin) extends Bundle {
val rxd = pingen()
val txd = pingen()
def fromUARTPort(uart: UARTPortIO, syncStages: Int = 0) {
txd.outputPin(uart.txd)
val rxd_t = rxd.inputPin()
uart.rxd := ShiftRegisterInit(rxd_t, syncStages, Bool(true))
}
}
class UARTGPIOPort(syncStages: Int = 0) extends Module {
val io = new Bundle{
val uart = new UARTPortIO().flip()
val pins = new UARTPinsIO
}
GPIOOutputPinCtrl(io.pins.txd, io.uart.txd)
val rxd = GPIOInputPinCtrl(io.pins.rxd)
io.uart.rxd := ShiftRegisterInit(rxd, syncStages, Bool(true))
}