Initial commit.
This commit is contained in:
295
src/main/scala/devices/gpio/GPIO.scala
Normal file
295
src/main/scala/devices/gpio/GPIO.scala
Normal file
@ -0,0 +1,295 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.gpio
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
import util.AsyncResetRegVec
|
||||
|
||||
case class GPIOConfig(address: BigInt, width: Int)
|
||||
|
||||
trait HasGPIOParameters {
|
||||
val params: Tuple2[Parameters, GPIOConfig]
|
||||
implicit val p = params._1
|
||||
val c = params._2
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Add a valid bit to indicate whether
|
||||
// there is something actually connected
|
||||
// to this.
|
||||
class GPIOPinIOFCtrl extends GPIOCtrl {
|
||||
val valid = Bool()
|
||||
}
|
||||
|
||||
// By default,
|
||||
object GPIOPinIOFCtrl {
|
||||
def apply(): GPIOPinIOFCtrl = {
|
||||
val iof = Wire(new GPIOPinIOFCtrl())
|
||||
iof.valid := Bool(false)
|
||||
iof.oval := Bool(false)
|
||||
iof.oe := Bool(false)
|
||||
iof.ie := Bool(false)
|
||||
iof
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
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 = {
|
||||
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
|
||||
// the IOF end up at the RocketChipTop
|
||||
// level, and we have to do the pinmux
|
||||
// outside of RocketChipTop.
|
||||
|
||||
class GPIOPortIO(c: GPIOConfig) 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
|
||||
}
|
||||
|
||||
// It would be better if the IOF were here and
|
||||
// we could do the pinmux inside.
|
||||
trait GPIOBundle extends Bundle with HasGPIOParameters {
|
||||
val port = new GPIOPortIO(c)
|
||||
}
|
||||
|
||||
trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
|
||||
val io: GPIOBundle
|
||||
|
||||
//--------------------------------------------------
|
||||
// CSR Declarations
|
||||
// -------------------------------------------------
|
||||
|
||||
// SW Control only.
|
||||
val portReg = Reg(init = UInt(0, c.width))
|
||||
|
||||
val oeReg = Module(new AsyncResetRegVec(c.width, 0))
|
||||
val pueReg = Module(new AsyncResetRegVec(c.width, 0))
|
||||
val dsReg = Reg(init = UInt(0, c.width))
|
||||
val ieReg = Module(new AsyncResetRegVec(c.width, 0))
|
||||
|
||||
// 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 valueReg = Reg(init = UInt(0, c.width), next = inSyncReg)
|
||||
|
||||
// Interrupt Configuration
|
||||
val highIeReg = Reg(init = UInt(0, c.width))
|
||||
val lowIeReg = Reg(init = UInt(0, c.width))
|
||||
val riseIeReg = Reg(init = UInt(0, c.width))
|
||||
val fallIeReg = Reg(init = UInt(0, c.width))
|
||||
val highIpReg = Reg(init = UInt(0, c.width))
|
||||
val lowIpReg = Reg(init = UInt(0, c.width))
|
||||
val riseIpReg = Reg(init = UInt(0, c.width))
|
||||
val fallIpReg = Reg(init = UInt(0, c.width))
|
||||
|
||||
// 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))
|
||||
|
||||
//--------------------------------------------------
|
||||
// CSR Access Logic (most of this section is boilerplate)
|
||||
// -------------------------------------------------
|
||||
|
||||
val rise = ~valueReg & inSyncReg;
|
||||
val fall = valueReg & ~inSyncReg;
|
||||
|
||||
// Note that these are out of order.
|
||||
regmap(
|
||||
GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg)),
|
||||
GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io)),
|
||||
GPIOCtrlRegs.rise_ie -> Seq(RegField(c.width, riseIeReg)),
|
||||
GPIOCtrlRegs.rise_ip -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise)),
|
||||
GPIOCtrlRegs.fall_ie -> Seq(RegField(c.width, fallIeReg)),
|
||||
GPIOCtrlRegs.fall_ip -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall)),
|
||||
GPIOCtrlRegs.high_ie -> Seq(RegField(c.width, highIeReg)),
|
||||
GPIOCtrlRegs.high_ip -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg)),
|
||||
GPIOCtrlRegs.low_ie -> Seq(RegField(c.width, lowIeReg)),
|
||||
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.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()))
|
||||
|
||||
// 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()))
|
||||
|
||||
|
||||
for (pin <- 0 until c.width) {
|
||||
|
||||
// Software Pin Control
|
||||
swPinCtrl(pin).pue := pueReg.io.q(pin)
|
||||
swPinCtrl(pin).oval := portReg(pin)
|
||||
swPinCtrl(pin).oe := oeReg.io.q(pin)
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// Generate Interrupts
|
||||
interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) |
|
||||
(fallIpReg(pin) & fallIeReg(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)
|
||||
}
|
||||
}
|
||||
|
||||
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(p: Parameters, c: GPIOConfig)
|
||||
extends TLRegisterRouter(c.address, interrupts = c.width, beatBytes = p(PeripheryBusConfig).beatBytes)(
|
||||
new TLRegBundle(Tuple2(p, c), _) with GPIOBundle)(
|
||||
new TLRegModule(Tuple2(p, c), _, _) with GPIOModule)
|
22
src/main/scala/devices/gpio/GPIOCtrlRegs.scala
Normal file
22
src/main/scala/devices/gpio/GPIOCtrlRegs.scala
Normal file
@ -0,0 +1,22 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.gpio
|
||||
|
||||
object GPIOCtrlRegs {
|
||||
val value = 0x00
|
||||
val input_en = 0x04
|
||||
val output_en = 0x08
|
||||
val port = 0x0c
|
||||
val pullup_en = 0x10
|
||||
val drive = 0x14
|
||||
val rise_ie = 0x18
|
||||
val rise_ip = 0x1c
|
||||
val fall_ie = 0x20
|
||||
val fall_ip = 0x24
|
||||
val high_ie = 0x28
|
||||
val high_ip = 0x2c
|
||||
val low_ie = 0x30
|
||||
val low_ip = 0x34
|
||||
val iof_en = 0x38
|
||||
val iof_sel = 0x3c
|
||||
val out_xor = 0x40
|
||||
}
|
28
src/main/scala/devices/gpio/GPIOPeriphery.scala
Normal file
28
src/main/scala/devices/gpio/GPIOPeriphery.scala
Normal file
@ -0,0 +1,28 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.gpio
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
import uncore.tilelink2.TLFragmenter
|
||||
|
||||
trait PeripheryGPIO {
|
||||
this: TopNetwork { val gpioConfig: GPIOConfig } =>
|
||||
val gpio = LazyModule(new TLGPIO(p, gpioConfig))
|
||||
gpio.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
intBus.intnode := gpio.intnode
|
||||
}
|
||||
|
||||
trait PeripheryGPIOBundle {
|
||||
this: { val gpioConfig: GPIOConfig } =>
|
||||
val gpio = new GPIOPortIO(gpioConfig)
|
||||
}
|
||||
|
||||
trait PeripheryGPIOModule {
|
||||
this: TopNetworkModule {
|
||||
val gpioConfig: GPIOConfig
|
||||
val outer: PeripheryGPIO
|
||||
val io: PeripheryGPIOBundle
|
||||
} =>
|
||||
io.gpio <> outer.gpio.module.io.port
|
||||
}
|
43
src/main/scala/devices/gpio/JTAG.scala
Normal file
43
src/main/scala/devices/gpio/JTAG.scala
Normal file
@ -0,0 +1,43 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.gpio
|
||||
|
||||
import Chisel._
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// SPI, UART, etc are with their
|
||||
// respective packages,
|
||||
// This file is for those that don't seem to have a good place
|
||||
// to put them otherwise.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
import config._
|
||||
import junctions.{JTAGIO}
|
||||
|
||||
class JTAGPinsIO extends Bundle {
|
||||
|
||||
val TCK = new GPIOPin()
|
||||
val TMS = new GPIOPin()
|
||||
val TDI = new GPIOPin()
|
||||
val TDO = new GPIOPin()
|
||||
val TRST_n = new GPIOPin()
|
||||
|
||||
}
|
||||
|
||||
class JTAGGPIOPort(drvTdo: Boolean = false)(implicit p: Parameters) extends Module {
|
||||
|
||||
val io = new Bundle {
|
||||
val jtag = new JTAGIO(drvTdo)
|
||||
val pins = new JTAGPinsIO()
|
||||
}
|
||||
|
||||
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.TRST := ~GPIOInputPinCtrl(io.pins.TRST_n, pue = Bool(true))
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.TDO, io.jtag.TDO)
|
||||
if (drvTdo) {
|
||||
io.pins.TDO.o.oe := io.jtag.DRV_TDO.get
|
||||
}
|
||||
|
||||
}
|
105
src/main/scala/devices/mockaon/MockAON.scala
Normal file
105
src/main/scala/devices/mockaon/MockAON.scala
Normal file
@ -0,0 +1,105 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
|
||||
import sifive.blocks.util.GenericTimer
|
||||
|
||||
case class MockAONConfig(
|
||||
address: BigInt = BigInt(0x10000000),
|
||||
nBackupRegs: Int = 16) {
|
||||
def size: Int = 0x1000
|
||||
def regBytes: Int = 4
|
||||
def wdogOffset: Int = 0
|
||||
def rtcOffset: Int = 0x40
|
||||
def backupRegOffset: Int = 0x80
|
||||
def pmuOffset: Int = 0x100
|
||||
}
|
||||
|
||||
trait HasMockAONParameters {
|
||||
val params: (MockAONConfig, Parameters)
|
||||
val c = params._1
|
||||
implicit val p = params._2
|
||||
}
|
||||
|
||||
class MockAONPMUIO extends Bundle {
|
||||
val vddpaden = Bool(OUTPUT)
|
||||
val dwakeup = Bool(INPUT)
|
||||
}
|
||||
|
||||
class MockAONMOffRstIO extends Bundle {
|
||||
val hfclkrst = Bool(OUTPUT)
|
||||
val corerst = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
trait MockAONBundle extends Bundle with HasMockAONParameters {
|
||||
|
||||
// Output of the Power Management Sequencer
|
||||
val moff = new MockAONMOffRstIO ()
|
||||
|
||||
// This goes out to wrapper
|
||||
// to be combined to create aon_rst.
|
||||
val wdog_rst = Bool(OUTPUT)
|
||||
|
||||
// This goes out to wrapper
|
||||
// and comes back as our clk
|
||||
val lfclk = Clock(OUTPUT)
|
||||
|
||||
val pmu = new MockAONPMUIO
|
||||
|
||||
val lfextclk = Clock(INPUT)
|
||||
|
||||
val resetCauses = new ResetCauses().asInput
|
||||
}
|
||||
|
||||
trait MockAONModule extends Module with HasRegMap with HasMockAONParameters {
|
||||
val io: MockAONBundle
|
||||
|
||||
// the expectation here is that Chisel's implicit reset is aonrst,
|
||||
// which is asynchronous, so don't use synchronous-reset registers.
|
||||
|
||||
val rtc = Module(new RTC)
|
||||
|
||||
val pmu = Module(new PMU(new DevKitPMUConfig))
|
||||
io.moff <> pmu.io.control
|
||||
io.pmu.vddpaden := pmu.io.control.vddpaden
|
||||
pmu.io.wakeup.dwakeup := io.pmu.dwakeup
|
||||
pmu.io.wakeup.awakeup := Bool(false)
|
||||
pmu.io.wakeup.rtc := rtc.io.ip(0)
|
||||
pmu.io.resetCauses := io.resetCauses
|
||||
val pmuRegMap = {
|
||||
val regs = pmu.io.regs.wakeupProgram ++ pmu.io.regs.sleepProgram ++
|
||||
Seq(pmu.io.regs.ie, pmu.io.regs.cause, pmu.io.regs.sleep, pmu.io.regs.key)
|
||||
for ((r, i) <- regs.zipWithIndex)
|
||||
yield (c.pmuOffset + c.regBytes*i) -> Seq(r.toRegField())
|
||||
}
|
||||
interrupts(1) := rtc.io.ip(0)
|
||||
|
||||
val wdog = Module(new WatchdogTimer)
|
||||
io.wdog_rst := wdog.io.rst
|
||||
wdog.io.corerst := pmu.io.control.corerst
|
||||
interrupts(0) := wdog.io.ip(0)
|
||||
|
||||
// If there are multiple lfclks to choose from, we can mux them here.
|
||||
io.lfclk := io.lfextclk
|
||||
|
||||
val backupRegs = Seq.fill(c.nBackupRegs)(Reg(UInt(width = c.regBytes * 8)))
|
||||
val backupRegMap =
|
||||
for ((reg, i) <- backupRegs.zipWithIndex)
|
||||
yield (c.backupRegOffset + c.regBytes*i) -> Seq(RegField(reg.getWidth, RegReadFn(reg), RegWriteFn(reg)))
|
||||
|
||||
regmap((backupRegMap ++
|
||||
GenericTimer.timerRegMap(wdog, c.wdogOffset, c.regBytes) ++
|
||||
GenericTimer.timerRegMap(rtc, c.rtcOffset, c.regBytes) ++
|
||||
pmuRegMap):_*)
|
||||
|
||||
}
|
||||
|
||||
class MockAON(c: MockAONConfig)(implicit val p: Parameters)
|
||||
extends TLRegisterRouter(c.address, interrupts = 2, size = c.size, beatBytes = p(PeripheryBusConfig).beatBytes, concurrency = 1)(
|
||||
new TLRegBundle((c, p), _) with MockAONBundle)(
|
||||
new TLRegModule((c, p), _, _) with MockAONModule)
|
42
src/main/scala/devices/mockaon/MockAONPeriphery.scala
Normal file
42
src/main/scala/devices/mockaon/MockAONPeriphery.scala
Normal file
@ -0,0 +1,42 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
import uncore.tilelink2.{IntXing, TLAsyncCrossingSource, TLFragmenter}
|
||||
import coreplex._
|
||||
|
||||
trait PeripheryMockAON extends TopNetwork {
|
||||
val mockAONConfig: MockAONConfig
|
||||
val coreplex: CoreplexRISCVPlatform
|
||||
|
||||
// We override the clock & Reset here so that all synchronizers, etc
|
||||
// are in the proper clock domain.
|
||||
val aon = LazyModule(new MockAONWrapper(mockAONConfig))
|
||||
val aon_int = LazyModule(new IntXing)
|
||||
aon.node := TLAsyncCrossingSource()(TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node))
|
||||
aon_int.intnode := aon.intnode
|
||||
intBus.intnode := aon_int.intnode
|
||||
}
|
||||
|
||||
trait PeripheryMockAONBundle {
|
||||
val aon = new MockAONWrapperBundle()
|
||||
}
|
||||
|
||||
trait PeripheryMockAONModule {
|
||||
this: TopNetworkModule {
|
||||
val outer: PeripheryMockAON
|
||||
val io: PeripheryMockAONBundle
|
||||
} =>
|
||||
|
||||
io.aon <> outer.aon.module.io
|
||||
|
||||
// Explicit clock & reset are unused in MockAONWrapper.
|
||||
// Tie to check this assumption.
|
||||
outer.aon.module.clock := Bool(false).asClock
|
||||
outer.aon.module.reset := Bool(true)
|
||||
|
||||
outer.coreplex.module.io.rtcToggle := outer.aon.module.io.rtc.asUInt.toBool
|
||||
|
||||
}
|
181
src/main/scala/devices/mockaon/MockAONWrapper.scala
Normal file
181
src/main/scala/devices/mockaon/MockAONWrapper.scala
Normal file
@ -0,0 +1,181 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
|
||||
import sifive.blocks.util.{DeglitchShiftRegister, ResetCatchAndSync}
|
||||
import util._
|
||||
/* 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()
|
||||
}
|
||||
|
||||
class MockAONWrapperPadsIO extends Bundle {
|
||||
val erst_n = new GPIOPin()
|
||||
val lfextclk = new GPIOPin()
|
||||
val pmu = new MockAONWrapperPMUIO()
|
||||
}
|
||||
|
||||
class MockAONWrapperBundle extends Bundle {
|
||||
val pads = new MockAONWrapperPadsIO()
|
||||
val rsts = new MockAONMOffRstIO()
|
||||
}
|
||||
|
||||
class MockAONWrapper(c: MockAONConfig)(implicit val p: Parameters) extends LazyModule {
|
||||
|
||||
val node = TLAsyncInputNode()
|
||||
val intnode = IntOutputNode()
|
||||
val aon = LazyModule (new MockAON(c)(p))
|
||||
|
||||
// We only need to isolate the signals
|
||||
// coming from MOFF to AON,
|
||||
// since AON is never off while MOFF is on.
|
||||
// The MOFF is on the "in" side of the Isolation.
|
||||
// AON is on the "out" side of the Isolation.
|
||||
|
||||
def isoOut(iso: Bool, x: UInt): UInt = IsoZero(iso, x)
|
||||
def isoIn(iso: Bool, x: UInt): UInt = x
|
||||
val isolation = LazyModule(new TLIsolation(fOut = isoOut, fIn = isoIn))
|
||||
val crossing = LazyModule(new TLAsyncCrossingSink(depth = 1))
|
||||
|
||||
isolation.node := node
|
||||
crossing.node := isolation.node
|
||||
val crossing_monitor = (aon.node := crossing.node)
|
||||
|
||||
// crossing lives outside in Periphery
|
||||
intnode := aon.intnode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new MockAONWrapperBundle {
|
||||
val in = node.bundleIn
|
||||
val ip = intnode.bundleOut
|
||||
val rtc = Clock(OUTPUT)
|
||||
}
|
||||
|
||||
val aon_io = aon.module.io
|
||||
val pads = io.pads
|
||||
|
||||
// -----------------------------------------------
|
||||
// Generation of aonrst
|
||||
// -----------------------------------------------
|
||||
|
||||
// ERST
|
||||
val erst = ~ GPIOInputPinCtrl(pads.erst_n, pue = Bool(true))
|
||||
aon_io.resetCauses.erst := erst
|
||||
aon_io.resetCauses.wdogrst := aon_io.wdog_rst
|
||||
|
||||
// PORRST
|
||||
val porrst = Bool(false) // TODO
|
||||
aon_io.resetCauses.porrst := porrst
|
||||
|
||||
//--------------------------------------------------
|
||||
// Drive "Mostly Off" Reset Signals (these
|
||||
// are synchronized inside MOFF as needed)
|
||||
//--------------------------------------------------
|
||||
|
||||
io.rsts.hfclkrst := aon_io.moff.hfclkrst
|
||||
io.rsts.corerst := aon_io.moff.corerst
|
||||
|
||||
//--------------------------------------------------
|
||||
// Generate the LFCLK input to AON
|
||||
// This is the same clock that is driven to this
|
||||
// block as 'clock'.
|
||||
//--------------------------------------------------
|
||||
|
||||
// LFCLK Override
|
||||
// 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))
|
||||
aon_io.lfextclk := lfextclk.asClock
|
||||
|
||||
// Drive AON's clock and Reset
|
||||
val lfclk = aon_io.lfclk
|
||||
|
||||
val aonrst_catch = Module (new ResetCatchAndSync(3))
|
||||
aonrst_catch.reset := erst | aon_io.wdog_rst
|
||||
aonrst_catch.clock := lfclk
|
||||
aon.module.reset := aonrst_catch.io.sync_reset
|
||||
|
||||
aon.module.clock := lfclk
|
||||
|
||||
//--------------------------------------------------
|
||||
// TL2 Register Access Interface
|
||||
//--------------------------------------------------
|
||||
|
||||
// Safely cross TL2 into AON Domain
|
||||
// Ensure that both are reset and clocked
|
||||
// at the same time.
|
||||
// Note that aon.moff.corerst is synchronous
|
||||
// to aon.module.clock, so this is safe.
|
||||
val crossing_slave_reset = ResetCatchAndSync(lfclk,
|
||||
aon.module.io.moff.corerst | aon.module.reset)
|
||||
|
||||
crossing.module.clock := lfclk
|
||||
crossing.module.reset := crossing_slave_reset
|
||||
|
||||
crossing_monitor.foreach { lm =>
|
||||
lm.module.clock := lfclk
|
||||
lm.module.reset := crossing_slave_reset
|
||||
}
|
||||
|
||||
// Note that aon.moff.corerst is synchronous
|
||||
// to aon.module.clock, so this is safe.
|
||||
isolation.module.io.iso_out := aon.module.io.moff.corerst
|
||||
isolation.module.io.iso_in := Bool(true)
|
||||
|
||||
//--------------------------------------------------
|
||||
// PMU <--> pads Interface
|
||||
//--------------------------------------------------
|
||||
|
||||
val dwakeup_n_async = GPIOInputPinCtrl(pads.pmu.dwakeup_n, 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)
|
||||
|
||||
//--------------------------------------------------
|
||||
// Connect signals to MOFF
|
||||
//--------------------------------------------------
|
||||
|
||||
io.rtc := aon_io.lfclk
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
// Isolation Cells
|
||||
// -----------------------------------------------
|
||||
|
||||
class IsoZero extends Module {
|
||||
val io = new Bundle {
|
||||
val in = Bool(INPUT)
|
||||
val iso = Bool(INPUT)
|
||||
val out = Bool(OUTPUT)
|
||||
}
|
||||
io.out := io.in & ~io.iso
|
||||
}
|
||||
|
||||
object IsoZero {
|
||||
def apply (iso: Bool, in: UInt): UInt = {
|
||||
|
||||
val w = in.getWidth
|
||||
val isos: List[IsoZero] = List.tabulate(in.getWidth)(
|
||||
x => Module(new IsoZero).suggestName(s"iso_$x")
|
||||
)
|
||||
for ((z, i) <- isos.zipWithIndex) {
|
||||
z.io.in := in(i)
|
||||
z.io.iso := iso
|
||||
}
|
||||
isos.map(_.io.out).asUInt
|
||||
}
|
||||
}
|
152
src/main/scala/devices/mockaon/PMU.scala
Normal file
152
src/main/scala/devices/mockaon/PMU.scala
Normal file
@ -0,0 +1,152 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import Chisel.ImplicitConversions._
|
||||
import util._
|
||||
import sifive.blocks.util.SRLatch
|
||||
|
||||
import sifive.blocks.util.{SlaveRegIF}
|
||||
|
||||
class WakeupCauses extends Bundle {
|
||||
val awakeup = Bool()
|
||||
val dwakeup = Bool()
|
||||
val rtc = Bool()
|
||||
val reset = Bool()
|
||||
}
|
||||
|
||||
class ResetCauses extends Bundle {
|
||||
val wdogrst = Bool()
|
||||
val erst = Bool()
|
||||
val porrst = Bool()
|
||||
}
|
||||
|
||||
class PMUSignals extends Bundle {
|
||||
val hfclkrst = Bool()
|
||||
val corerst = Bool()
|
||||
val reserved1 = Bool()
|
||||
val vddpaden = Bool()
|
||||
val reserved0 = Bool()
|
||||
}
|
||||
|
||||
class PMUInstruction extends Bundle {
|
||||
val sigs = new PMUSignals
|
||||
val dt = UInt(width = 4)
|
||||
}
|
||||
|
||||
class PMUConfig(wakeupProgramIn: Seq[Int],
|
||||
sleepProgramIn: Seq[Int]) {
|
||||
val programLength = 8
|
||||
val nWakeupCauses = new WakeupCauses().elements.size
|
||||
val wakeupProgram = wakeupProgramIn.padTo(programLength, wakeupProgramIn.last)
|
||||
val sleepProgram = sleepProgramIn.padTo(programLength, sleepProgramIn.last)
|
||||
require(wakeupProgram.length == programLength)
|
||||
require(sleepProgram.length == programLength)
|
||||
}
|
||||
|
||||
class DevKitPMUConfig extends PMUConfig( // TODO
|
||||
Seq(0x1f0, 0x0f8, 0x030),
|
||||
Seq(0x0f0, 0x1f0, 0x1d0, 0x1c0))
|
||||
|
||||
class PMURegs(c: PMUConfig) extends Bundle {
|
||||
val ie = new SlaveRegIF(c.nWakeupCauses)
|
||||
val cause = new SlaveRegIF(32)
|
||||
val sleep = new SlaveRegIF(32)
|
||||
val key = new SlaveRegIF(32)
|
||||
val wakeupProgram = Vec(c.programLength, new SlaveRegIF(32))
|
||||
val sleepProgram = Vec(c.programLength, new SlaveRegIF(32))
|
||||
}
|
||||
|
||||
class PMUCore(c: PMUConfig)(resetIn: Bool) extends Module(_reset = resetIn) {
|
||||
val io = new Bundle {
|
||||
val wakeup = new WakeupCauses().asInput
|
||||
val control = Valid(new PMUSignals)
|
||||
val resetCause = UInt(INPUT, log2Ceil(new ResetCauses().getWidth))
|
||||
val regs = new PMURegs(c)
|
||||
}
|
||||
|
||||
val run = Reg(init = Bool(true))
|
||||
val awake = Reg(init = Bool(true))
|
||||
val unlocked = {
|
||||
val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
|
||||
RegEnable(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, Bool(false), io.regs.key.write.valid || writeAny)
|
||||
}
|
||||
val wantSleep = RegEnable(Bool(true), Bool(false), io.regs.sleep.write.valid && unlocked)
|
||||
val pc = Reg(init = UInt(0, log2Ceil(c.programLength)))
|
||||
val wakeupCause = Reg(init = UInt(0, log2Ceil(c.nWakeupCauses)))
|
||||
val ie = RegEnable(io.regs.ie.write.bits, io.regs.ie.write.valid && unlocked) | 1 /* POR always enabled */
|
||||
|
||||
val insnWidth = new PMUInstruction().getWidth
|
||||
val wakeupProgram = c.wakeupProgram.map(v => Reg(init = UInt(v, insnWidth)))
|
||||
val sleepProgram = c.sleepProgram.map(v => Reg(init = UInt(v, insnWidth)))
|
||||
val insnBits = Mux(awake, wakeupProgram(pc), sleepProgram(pc))
|
||||
val insn = new PMUInstruction().fromBits(insnBits)
|
||||
|
||||
val count = Reg(init = UInt(0, 1 << insn.dt.getWidth))
|
||||
val tick = (count ^ (count + 1))(insn.dt)
|
||||
val npc = pc +& 1
|
||||
val last = npc >= c.programLength
|
||||
io.control.valid := run && !last && tick
|
||||
io.control.bits := insn.sigs
|
||||
|
||||
when (run) {
|
||||
count := count + 1
|
||||
when (tick) {
|
||||
count := 0
|
||||
|
||||
require(isPow2(c.programLength))
|
||||
run := !last
|
||||
pc := npc
|
||||
}
|
||||
}.otherwise {
|
||||
val maskedWakeupCauses = ie & io.wakeup.asUInt
|
||||
when (!awake && maskedWakeupCauses.orR) {
|
||||
run := true
|
||||
awake := true
|
||||
wakeupCause := PriorityEncoder(maskedWakeupCauses)
|
||||
}
|
||||
when (awake && wantSleep) {
|
||||
run := true
|
||||
awake := false
|
||||
wantSleep := false
|
||||
}
|
||||
}
|
||||
|
||||
io.regs.cause.read := wakeupCause | (io.resetCause << 8)
|
||||
io.regs.ie.read := ie
|
||||
io.regs.key.read := unlocked
|
||||
io.regs.sleep.read := 0
|
||||
|
||||
for ((port, reg) <- (io.regs.wakeupProgram ++ io.regs.sleepProgram) zip (wakeupProgram ++ sleepProgram)) {
|
||||
port.read := reg
|
||||
when (port.write.valid && unlocked) { reg := port.write.bits }
|
||||
}
|
||||
}
|
||||
|
||||
class PMU(val c: PMUConfig) extends Module {
|
||||
val io = new Bundle {
|
||||
val wakeup = new WakeupCauses().asInput
|
||||
val control = new PMUSignals().asOutput
|
||||
val regs = new PMURegs(c)
|
||||
val resetCauses = new ResetCauses().asInput
|
||||
}
|
||||
|
||||
val core = Module(new PMUCore(c)(resetIn = Reg(next = Reg(next = reset))))
|
||||
io <> core.io
|
||||
core.io.wakeup.reset := false // this is implied by resetting the PMU
|
||||
|
||||
// during aonrst, hold all control signals high
|
||||
val latch = ~AsyncResetReg(~core.io.control.bits.asUInt, core.io.control.valid)
|
||||
io.control := io.control.fromBits(latch)
|
||||
|
||||
core.io.resetCause := {
|
||||
val cause = io.resetCauses.asUInt
|
||||
val latches = for (i <- 0 until cause.getWidth) yield {
|
||||
val latch = Module(new SRLatch)
|
||||
latch.io.set := cause(i)
|
||||
latch.io.reset := (0 until cause.getWidth).filter(_ != i).map(cause(_)).reduce(_||_)
|
||||
latch.io.q
|
||||
}
|
||||
OHToUInt(latches)
|
||||
}
|
||||
}
|
58
src/main/scala/devices/mockaon/WatchdogTimer.scala
Normal file
58
src/main/scala/devices/mockaon/WatchdogTimer.scala
Normal file
@ -0,0 +1,58 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import Chisel.ImplicitConversions._
|
||||
import util.AsyncResetReg
|
||||
|
||||
import sifive.blocks.util.{SlaveRegIF, GenericTimer}
|
||||
|
||||
object WatchdogTimer {
|
||||
def writeAnyExceptKey(regs: Bundle, keyReg: SlaveRegIF): Bool = {
|
||||
regs.elements.values.filter(_ ne keyReg).map({
|
||||
case v: Vec[SlaveRegIF] @unchecked => v.map(_.write.valid).reduce(_||_)
|
||||
case s: SlaveRegIF => s.write.valid
|
||||
}).reduce(_||_)
|
||||
}
|
||||
|
||||
val key = 0x51F15E
|
||||
}
|
||||
|
||||
class WatchdogTimer extends GenericTimer {
|
||||
protected def countWidth = 31
|
||||
protected def cmpWidth = 16
|
||||
protected def ncmp = 1
|
||||
protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
|
||||
override protected lazy val countAwake = AsyncResetReg(io.regs.cfg.write.bits(13), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val countEn = {
|
||||
val corerstSynchronized = Reg(next = Reg(next = io.corerst))
|
||||
countAlways || (countAwake && !corerstSynchronized)
|
||||
}
|
||||
override protected lazy val rsten = AsyncResetReg(io.regs.cfg.write.bits(8), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val ip = RegEnable(io.regs.cfg.write.bits(28) || elapsed(0), (io.regs.cfg.write.valid && unlocked) || elapsed(0))
|
||||
override protected lazy val unlocked = {
|
||||
val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
|
||||
AsyncResetReg(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, io.regs.key.write.valid || writeAny)(0)
|
||||
}
|
||||
protected lazy val feed = {
|
||||
val food = 0xD09F00D
|
||||
unlocked && io.regs.feed.write.valid && io.regs.feed.write.bits === food
|
||||
}
|
||||
lazy val io = new GenericTimerIO {
|
||||
val corerst = Bool(INPUT)
|
||||
val rst = Bool(OUTPUT)
|
||||
}
|
||||
io.rst := AsyncResetReg(Bool(true), rsten && elapsed(0))
|
||||
}
|
||||
|
||||
class RTC extends GenericTimer {
|
||||
protected def countWidth = 48
|
||||
protected def cmpWidth = 32
|
||||
protected def ncmp = 1
|
||||
protected def countEn = countAlways
|
||||
override protected lazy val ip = Reg(next = elapsed(0))
|
||||
override protected lazy val zerocmp = Bool(false)
|
||||
protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val feed = Bool(false)
|
||||
lazy val io = new GenericTimerIO
|
||||
}
|
82
src/main/scala/devices/pwm/PWM.scala
Normal file
82
src/main/scala/devices/pwm/PWM.scala
Normal file
@ -0,0 +1,82 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.pwm
|
||||
|
||||
import Chisel._
|
||||
import Chisel.ImplicitConversions._
|
||||
import config._
|
||||
import regmapper._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
import uncore.tilelink2._
|
||||
import util._
|
||||
|
||||
import sifive.blocks.util.GenericTimer
|
||||
|
||||
// Core PWM Functionality & Register Interface
|
||||
|
||||
class PWM(val ncmp: Int = 4, val cmpWidth: Int = 16)(implicit p: Parameters) extends GenericTimer {
|
||||
protected def countWidth = ((1 << scaleWidth) - 1) + cmpWidth
|
||||
protected lazy val countAlways = RegEnable(io.regs.cfg.write.bits(12), Bool(false), io.regs.cfg.write.valid && unlocked)
|
||||
protected lazy val feed = count.carryOut(scale + UInt(cmpWidth))
|
||||
protected lazy val countEn = Wire(Bool())
|
||||
override protected lazy val oneShot = RegEnable(io.regs.cfg.write.bits(13) && !countReset, Bool(false), (io.regs.cfg.write.valid && unlocked) || countReset)
|
||||
override protected lazy val center = RegEnable(io.regs.cfg.write.bits(16 + ncmp - 1, 16), io.regs.cfg.write.valid && unlocked)
|
||||
override protected lazy val gang = RegEnable(io.regs.cfg.write.bits(24 + ncmp - 1, 24), io.regs.cfg.write.valid && unlocked)
|
||||
override protected lazy val deglitch = RegEnable(io.regs.cfg.write.bits(10), io.regs.cfg.write.valid && unlocked)(0)
|
||||
override protected lazy val sticky = RegEnable(io.regs.cfg.write.bits(8), io.regs.cfg.write.valid && unlocked)(0)
|
||||
override protected lazy val ip = {
|
||||
val doSticky = Reg(next = (deglitch && !countReset) || sticky)
|
||||
val sel = ((0 until ncmp).map(i => s(cmpWidth-1) && center(i))).asUInt
|
||||
val reg = Reg(UInt(width = ncmp))
|
||||
reg := (sel & elapsed.asUInt) | (~sel & (elapsed.asUInt | (Fill(ncmp, doSticky) & reg)))
|
||||
when (io.regs.cfg.write.valid && unlocked) { reg := io.regs.cfg.write.bits(28 + ncmp - 1, 28) }
|
||||
reg
|
||||
}
|
||||
lazy val io = new GenericTimerIO {
|
||||
val gpio = Vec(ncmp, Bool()).asOutput
|
||||
}
|
||||
io.gpio := io.gpio.fromBits(ip & ~(gang & Cat(ip(0), ip >> 1)))
|
||||
countEn := countAlways || oneShot
|
||||
}
|
||||
|
||||
case class PWMConfig(
|
||||
address: BigInt,
|
||||
size: Int = 0x1000,
|
||||
regBytes: Int = 4,
|
||||
ncmp: Int = 4,
|
||||
cmpWidth: Int = 16)
|
||||
{
|
||||
val bc = new PWMBundleConfig(ncmp)
|
||||
}
|
||||
|
||||
case class PWMBundleConfig(
|
||||
ncmp: Int)
|
||||
{
|
||||
def union(that: PWMBundleConfig): PWMBundleConfig =
|
||||
PWMBundleConfig(scala.math.max(ncmp, that.ncmp))
|
||||
}
|
||||
|
||||
trait HasPWMParameters {
|
||||
val params: (PWMConfig, Parameters)
|
||||
val c = params._1
|
||||
implicit val p = params._2
|
||||
}
|
||||
|
||||
trait PWMBundle extends Bundle with HasPWMParameters {
|
||||
val gpio = Vec(c.ncmp, Bool()).asOutput
|
||||
}
|
||||
|
||||
trait PWMModule extends Module with HasRegMap with HasPWMParameters {
|
||||
val io: PWMBundle
|
||||
|
||||
val pwm = Module(new PWM(c.ncmp, c.cmpWidth))
|
||||
|
||||
interrupts := pwm.io.ip
|
||||
io.gpio := pwm.io.gpio
|
||||
|
||||
regmap((GenericTimer.timerRegMap(pwm, 0, c.regBytes)):_*)
|
||||
}
|
||||
|
||||
class TLPWM(c: PWMConfig)(implicit val p: Parameters)
|
||||
extends TLRegisterRouter(c.address, interrupts = c.ncmp, size = c.size, beatBytes = p(PeripheryBusConfig).beatBytes)(
|
||||
new TLRegBundle((c, p), _) with PWMBundle)(
|
||||
new TLRegModule((c, p), _, _) with PWMModule)
|
58
src/main/scala/devices/pwm/PWMPeriphery.scala
Normal file
58
src/main/scala/devices/pwm/PWMPeriphery.scala
Normal file
@ -0,0 +1,58 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.pwm
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy.LazyModule
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
import uncore.tilelink2.TLFragmenter
|
||||
|
||||
import sifive.blocks.devices.gpio._
|
||||
|
||||
class PWMPortIO(c: PWMBundleConfig)(implicit p: Parameters) extends Bundle {
|
||||
val port = Vec(c.ncmp, Bool()).asOutput
|
||||
override def cloneType: this.type = new PWMPortIO(c).asInstanceOf[this.type]
|
||||
}
|
||||
|
||||
class PWMPinsIO(c: PWMBundleConfig)(implicit p: Parameters) extends Bundle {
|
||||
val pwm = Vec(c.ncmp, new GPIOPin)
|
||||
}
|
||||
|
||||
class PWMGPIOPort(c: PWMBundleConfig)(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val pwm = new PWMPortIO(c).flip()
|
||||
val pins = new PWMPinsIO(c)
|
||||
}
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.pwm, io.pwm.port.asUInt)
|
||||
}
|
||||
|
||||
trait PeripheryPWM {
|
||||
this: TopNetwork { val pwmConfigs: Seq[PWMConfig] } =>
|
||||
|
||||
val pwmDevices = (pwmConfigs.zipWithIndex) map { case (c, i) =>
|
||||
val pwm = LazyModule(new TLPWM(c) { override lazy val valName = Some(s"pwm$i") })
|
||||
pwm.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
intBus.intnode := pwm.intnode
|
||||
pwm
|
||||
}
|
||||
}
|
||||
|
||||
trait PeripheryPWMBundle {
|
||||
this: {
|
||||
val p: Parameters
|
||||
val pwmConfigs: Seq[PWMConfig]
|
||||
} =>
|
||||
val pwm_bc = pwmConfigs.map(_.bc).reduce(_.union(_))
|
||||
val pwms = Vec(pwmConfigs.size, new PWMPortIO(pwm_bc)(p))
|
||||
}
|
||||
|
||||
trait PeripheryPWMModule {
|
||||
this: TopNetworkModule {
|
||||
val outer: PeripheryPWM
|
||||
val io: PeripheryPWMBundle
|
||||
} =>
|
||||
(io.pwms.zipWithIndex zip outer.pwmDevices) foreach { case ((io, i), device) =>
|
||||
io.port := device.module.io.gpio
|
||||
}
|
||||
}
|
40
src/main/scala/devices/spi/SPIArbiter.scala
Normal file
40
src/main/scala/devices/spi/SPIArbiter.scala
Normal file
@ -0,0 +1,40 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIInnerIO(c: SPIConfigBase) extends SPILinkIO(c) {
|
||||
val lock = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
class SPIArbiter(c: SPIConfigBase, n: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val inner = Vec(n, new SPIInnerIO(c)).flip
|
||||
val outer = new SPILinkIO(c)
|
||||
val sel = UInt(INPUT, log2Up(n))
|
||||
}
|
||||
|
||||
val sel = Reg(init = Vec(Bool(true) +: Seq.fill(n-1)(Bool(false))))
|
||||
|
||||
io.outer.tx.valid := Mux1H(sel, io.inner.map(_.tx.valid))
|
||||
io.outer.tx.bits := Mux1H(sel, io.inner.map(_.tx.bits))
|
||||
io.outer.cnt := Mux1H(sel, io.inner.map(_.cnt))
|
||||
io.outer.fmt := Mux1H(sel, io.inner.map(_.fmt))
|
||||
io.outer.cs := Mux1H(sel, io.inner.map(_.cs))
|
||||
|
||||
(io.inner zip sel).foreach { case (inner, s) =>
|
||||
inner.tx.ready := io.outer.tx.ready && s
|
||||
inner.rx.valid := io.outer.rx.valid && s
|
||||
inner.rx.bits := io.outer.rx.bits
|
||||
inner.active := io.outer.active && s
|
||||
}
|
||||
|
||||
val nsel = Vec.tabulate(n)(io.sel === UInt(_))
|
||||
val lock = Mux1H(sel, io.inner.map(_.lock))
|
||||
when (!lock) {
|
||||
sel := nsel
|
||||
when (sel.asUInt =/= nsel.asUInt) {
|
||||
io.outer.cs.clear := Bool(true)
|
||||
}
|
||||
}
|
||||
}
|
106
src/main/scala/devices/spi/SPIBundle.scala
Normal file
106
src/main/scala/devices/spi/SPIBundle.scala
Normal file
@ -0,0 +1,106 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
abstract class SPIBundle(val c: SPIConfigBase) extends Bundle {
|
||||
override def cloneType: SPIBundle.this.type =
|
||||
this.getClass.getConstructors.head.newInstance(c).asInstanceOf[this.type]
|
||||
}
|
||||
|
||||
class SPIDataIO extends Bundle {
|
||||
val i = Bool(INPUT)
|
||||
val o = Bool(OUTPUT)
|
||||
val oe = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
class SPIPortIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = Bool(OUTPUT)
|
||||
val dq = Vec(4, new SPIDataIO)
|
||||
val cs = Vec(c.csWidth, Bool(OUTPUT))
|
||||
}
|
||||
|
||||
trait HasSPIProtocol {
|
||||
val proto = Bits(width = SPIProtocol.width)
|
||||
}
|
||||
trait HasSPIEndian {
|
||||
val endian = Bits(width = SPIEndian.width)
|
||||
}
|
||||
class SPIFormat(c: SPIConfigBase) extends SPIBundle(c)
|
||||
with HasSPIProtocol
|
||||
with HasSPIEndian {
|
||||
val iodir = Bits(width = SPIDirection.width)
|
||||
}
|
||||
|
||||
trait HasSPILength extends SPIBundle {
|
||||
val len = UInt(width = c.lengthBits)
|
||||
}
|
||||
|
||||
class SPIClocking(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val div = UInt(width = c.divisorBits)
|
||||
val pol = Bool()
|
||||
val pha = Bool()
|
||||
}
|
||||
|
||||
class SPIChipSelect(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val id = UInt(width = c.csIdBits)
|
||||
val dflt = Vec(c.csWidth, Bool())
|
||||
|
||||
def toggle(en: Bool): Vec[Bool] = {
|
||||
val mask = en << id
|
||||
val out = Cat(dflt.reverse) ^ mask
|
||||
Vec.tabulate(c.csWidth)(out(_))
|
||||
}
|
||||
}
|
||||
|
||||
trait HasSPICSMode {
|
||||
val mode = Bits(width = SPICSMode.width)
|
||||
}
|
||||
|
||||
class SPIDelay(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val cssck = UInt(width = c.delayBits)
|
||||
val sckcs = UInt(width = c.delayBits)
|
||||
val intercs = UInt(width = c.delayBits)
|
||||
val interxfr = UInt(width = c.delayBits)
|
||||
}
|
||||
|
||||
class SPIWatermark(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val tx = UInt(width = c.txDepthBits)
|
||||
val rx = UInt(width = c.rxDepthBits)
|
||||
}
|
||||
|
||||
class SPIControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fmt = new SPIFormat(c) with HasSPILength
|
||||
val sck = new SPIClocking(c)
|
||||
val cs = new SPIChipSelect(c) with HasSPICSMode
|
||||
val dla = new SPIDelay(c)
|
||||
val wm = new SPIWatermark(c)
|
||||
}
|
||||
|
||||
object SPIControl {
|
||||
def init(c: SPIConfigBase): SPIControl = {
|
||||
val ctrl = Wire(new SPIControl(c))
|
||||
ctrl.fmt.proto := SPIProtocol.Single
|
||||
ctrl.fmt.iodir := SPIDirection.Rx
|
||||
ctrl.fmt.endian := SPIEndian.MSB
|
||||
ctrl.fmt.len := UInt(math.min(c.frameBits, 8))
|
||||
ctrl.sck.div := UInt(3)
|
||||
ctrl.sck.pol := Bool(false)
|
||||
ctrl.sck.pha := Bool(false)
|
||||
ctrl.cs.id := UInt(0)
|
||||
ctrl.cs.dflt.foreach { _ := Bool(true) }
|
||||
ctrl.cs.mode := SPICSMode.Auto
|
||||
ctrl.dla.cssck := UInt(1)
|
||||
ctrl.dla.sckcs := UInt(1)
|
||||
ctrl.dla.intercs := UInt(1)
|
||||
ctrl.dla.interxfr := UInt(0)
|
||||
ctrl.wm.tx := UInt(0)
|
||||
ctrl.wm.rx := UInt(0)
|
||||
ctrl
|
||||
}
|
||||
}
|
||||
|
||||
class SPIInterrupts extends Bundle {
|
||||
val txwm = Bool()
|
||||
val rxwm = Bool()
|
||||
}
|
33
src/main/scala/devices/spi/SPIConsts.scala
Normal file
33
src/main/scala/devices/spi/SPIConsts.scala
Normal file
@ -0,0 +1,33 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
object SPIProtocol {
|
||||
val width = 2
|
||||
val Single = UInt(0, width)
|
||||
val Dual = UInt(1, width)
|
||||
val Quad = UInt(2, width)
|
||||
|
||||
val cases = Seq(Single, Dual, Quad)
|
||||
def decode(x: UInt): Seq[Bool] = cases.map(_ === x)
|
||||
}
|
||||
|
||||
object SPIDirection {
|
||||
val width = 1
|
||||
val Rx = UInt(0, width)
|
||||
val Tx = UInt(1, width)
|
||||
}
|
||||
|
||||
object SPIEndian {
|
||||
val width = 1
|
||||
val MSB = UInt(0, width)
|
||||
val LSB = UInt(1, width)
|
||||
}
|
||||
|
||||
object SPICSMode {
|
||||
val width = 2
|
||||
val Auto = UInt(0, width)
|
||||
val Hold = UInt(2, width)
|
||||
val Off = UInt(3, width)
|
||||
}
|
62
src/main/scala/devices/spi/SPIFIFO.scala
Normal file
62
src/main/scala/devices/spi/SPIFIFO.scala
Normal file
@ -0,0 +1,62 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIFIFOControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fmt = new SPIFormat(c) with HasSPILength
|
||||
val cs = new Bundle with HasSPICSMode
|
||||
val wm = new SPIWatermark(c)
|
||||
}
|
||||
|
||||
class SPIFIFO(c: SPIConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val ctrl = new SPIFIFOControl(c).asInput
|
||||
val link = new SPIInnerIO(c)
|
||||
val tx = Decoupled(Bits(width = c.frameBits)).flip
|
||||
val rx = Decoupled(Bits(width = c.frameBits))
|
||||
val ip = new SPIInterrupts().asOutput
|
||||
}
|
||||
|
||||
val txq = Module(new Queue(io.tx.bits, c.txDepth))
|
||||
val rxq = Module(new Queue(io.rx.bits, c.rxDepth))
|
||||
|
||||
txq.io.enq <> io.tx
|
||||
io.link.tx <> txq.io.deq
|
||||
|
||||
val fire_tx = io.link.tx.fire()
|
||||
val fire_rx = io.link.rx.fire()
|
||||
val rxen = Reg(init = Bool(false))
|
||||
|
||||
rxq.io.enq.valid := io.link.rx.valid && rxen
|
||||
rxq.io.enq.bits := io.link.rx.bits
|
||||
io.rx <> rxq.io.deq
|
||||
|
||||
when (fire_rx) {
|
||||
rxen := Bool(false)
|
||||
}
|
||||
when (fire_tx) {
|
||||
rxen := (io.link.fmt.iodir === SPIDirection.Rx)
|
||||
}
|
||||
|
||||
val proto = SPIProtocol.decode(io.link.fmt.proto).zipWithIndex
|
||||
val cnt_quot = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len >> i) })
|
||||
val cnt_rmdr = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len(i, 0).orR) })
|
||||
io.link.fmt <> io.ctrl.fmt
|
||||
io.link.cnt := cnt_quot + cnt_rmdr
|
||||
|
||||
val cs_mode = RegNext(io.ctrl.cs.mode, SPICSMode.Auto)
|
||||
val cs_mode_hold = (cs_mode === SPICSMode.Hold)
|
||||
val cs_mode_off = (cs_mode === SPICSMode.Off)
|
||||
val cs_update = (cs_mode =/= io.ctrl.cs.mode)
|
||||
val cs_clear = !(cs_mode_hold || cs_mode_off)
|
||||
|
||||
io.link.cs.set := !cs_mode_off
|
||||
io.link.cs.clear := cs_update || (fire_tx && cs_clear)
|
||||
io.link.cs.hold := Bool(false)
|
||||
|
||||
io.link.lock := io.link.tx.valid || rxen
|
||||
|
||||
io.ip.txwm := (txq.io.count < io.ctrl.wm.tx)
|
||||
io.ip.rxwm := (rxq.io.count > io.ctrl.wm.rx)
|
||||
}
|
162
src/main/scala/devices/spi/SPIFlash.scala
Normal file
162
src/main/scala/devices/spi/SPIFlash.scala
Normal file
@ -0,0 +1,162 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIFlashInsn(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val cmd = new Bundle with HasSPIProtocol {
|
||||
val code = Bits(width = c.insnCmdBits)
|
||||
val en = Bool()
|
||||
}
|
||||
val addr = new Bundle with HasSPIProtocol {
|
||||
val len = UInt(width = c.insnAddrLenBits)
|
||||
}
|
||||
val pad = new Bundle {
|
||||
val code = Bits(width = c.frameBits)
|
||||
val cnt = Bits(width = c.insnPadLenBits)
|
||||
}
|
||||
val data = new Bundle with HasSPIProtocol
|
||||
}
|
||||
|
||||
class SPIFlashControl(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val insn = new SPIFlashInsn(c)
|
||||
val fmt = new Bundle with HasSPIEndian
|
||||
}
|
||||
|
||||
object SPIFlashInsn {
|
||||
def init(c: SPIFlashConfigBase): SPIFlashInsn = {
|
||||
val insn = Wire(new SPIFlashInsn(c))
|
||||
insn.cmd.en := Bool(true)
|
||||
insn.cmd.code := Bits(0x03)
|
||||
insn.cmd.proto := SPIProtocol.Single
|
||||
insn.addr.len := UInt(3)
|
||||
insn.addr.proto := SPIProtocol.Single
|
||||
insn.pad.cnt := UInt(0)
|
||||
insn.pad.code := Bits(0)
|
||||
insn.data.proto := SPIProtocol.Single
|
||||
insn
|
||||
}
|
||||
}
|
||||
|
||||
class SPIFlashAddr(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val next = UInt(width = c.insnAddrBits)
|
||||
val hold = UInt(width = c.insnAddrBits)
|
||||
}
|
||||
|
||||
class SPIFlashMap(c: SPIFlashConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val en = Bool(INPUT)
|
||||
val ctrl = new SPIFlashControl(c).asInput
|
||||
val addr = Decoupled(new SPIFlashAddr(c)).flip
|
||||
val data = Decoupled(UInt(width = c.frameBits))
|
||||
val link = new SPIInnerIO(c)
|
||||
}
|
||||
|
||||
val addr = io.addr.bits.hold + UInt(1)
|
||||
val merge = io.link.active && (io.addr.bits.next === addr)
|
||||
|
||||
private val insn = io.ctrl.insn
|
||||
io.link.tx.valid := Bool(true)
|
||||
io.link.fmt.proto := insn.addr.proto
|
||||
io.link.fmt.iodir := SPIDirection.Tx
|
||||
io.link.fmt.endian := io.ctrl.fmt.endian
|
||||
io.link.cnt := Mux1H(
|
||||
SPIProtocol.decode(io.link.fmt.proto).zipWithIndex.map {
|
||||
case (s, i) => (s -> UInt(c.frameBits >> i))
|
||||
})
|
||||
io.link.cs.set := Bool(true)
|
||||
io.link.cs.clear := Bool(false)
|
||||
io.link.cs.hold := Bool(true)
|
||||
io.link.lock := Bool(true)
|
||||
|
||||
io.addr.ready := Bool(false)
|
||||
io.data.valid := Bool(false)
|
||||
io.data.bits := io.link.rx.bits
|
||||
|
||||
val cnt = Reg(UInt(width = math.max(c.insnPadLenBits, c.insnAddrLenBits)))
|
||||
val cnt_en = Wire(init = Bool(false))
|
||||
val cnt_cmp = (0 to c.insnAddrBytes).map(cnt === UInt(_))
|
||||
val cnt_zero = cnt_cmp(0)
|
||||
val cnt_last = cnt_cmp(1) && io.link.tx.ready
|
||||
val cnt_done = cnt_last || cnt_zero
|
||||
when (cnt_en) {
|
||||
io.link.tx.valid := !cnt_zero
|
||||
when (io.link.tx.fire()) {
|
||||
cnt := cnt - UInt(1)
|
||||
}
|
||||
}
|
||||
|
||||
val (s_idle :: s_cmd :: s_addr :: s_pad :: s_data_pre :: s_data_post :: Nil) = Enum(UInt(), 6)
|
||||
val state = Reg(init = s_idle)
|
||||
|
||||
switch (state) {
|
||||
is (s_idle) {
|
||||
io.link.tx.valid := Bool(false)
|
||||
when (io.en) {
|
||||
io.addr.ready := Bool(true)
|
||||
when (io.addr.valid) {
|
||||
when (merge) {
|
||||
state := s_data_pre
|
||||
} .otherwise {
|
||||
state := Mux(insn.cmd.en, s_cmd, s_addr)
|
||||
io.link.cs.clear := Bool(true)
|
||||
}
|
||||
} .otherwise {
|
||||
io.link.lock := Bool(false)
|
||||
}
|
||||
} .otherwise {
|
||||
io.data.valid := io.addr.valid
|
||||
io.addr.ready := io.data.ready
|
||||
io.data.bits := UInt(0)
|
||||
io.link.lock := Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
is (s_cmd) {
|
||||
io.link.fmt.proto := insn.cmd.proto
|
||||
io.link.tx.bits := insn.cmd.code
|
||||
when (io.link.tx.ready) {
|
||||
state := s_addr
|
||||
cnt := insn.addr.len
|
||||
}
|
||||
}
|
||||
|
||||
is (s_addr) {
|
||||
io.link.tx.bits := Mux1H(cnt_cmp.tail.zipWithIndex.map {
|
||||
case (s, i) =>
|
||||
val n = i * c.frameBits
|
||||
val m = n + (c.frameBits - 1)
|
||||
s -> io.addr.bits.hold(m, n)
|
||||
})
|
||||
|
||||
cnt_en := Bool(true)
|
||||
when (cnt_done) {
|
||||
state := s_pad
|
||||
}
|
||||
}
|
||||
|
||||
is (s_pad) {
|
||||
io.link.cnt := insn.pad.cnt
|
||||
io.link.tx.bits := insn.pad.code
|
||||
when (io.link.tx.ready) {
|
||||
state := s_data_pre
|
||||
}
|
||||
}
|
||||
|
||||
is (s_data_pre) {
|
||||
io.link.fmt.proto := insn.data.proto
|
||||
io.link.fmt.iodir := SPIDirection.Rx
|
||||
when (io.link.tx.ready) {
|
||||
state := s_data_post
|
||||
}
|
||||
}
|
||||
|
||||
is (s_data_post) {
|
||||
io.link.tx.valid := Bool(false)
|
||||
io.data.valid := io.link.rx.valid
|
||||
when (io.data.fire()) {
|
||||
state := s_idle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
121
src/main/scala/devices/spi/SPIMedia.scala
Normal file
121
src/main/scala/devices/spi/SPIMedia.scala
Normal file
@ -0,0 +1,121 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPILinkIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val tx = Decoupled(Bits(width = c.frameBits))
|
||||
val rx = Valid(Bits(width = c.frameBits)).flip
|
||||
|
||||
val cnt = UInt(OUTPUT, c.countBits)
|
||||
val fmt = new SPIFormat(c).asOutput
|
||||
val cs = new Bundle {
|
||||
val set = Bool(OUTPUT)
|
||||
val clear = Bool(OUTPUT) // Deactivate CS
|
||||
val hold = Bool(OUTPUT) // Supress automatic CS deactivation
|
||||
}
|
||||
val active = Bool(INPUT)
|
||||
}
|
||||
|
||||
class SPIMedia(c: SPIConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val port = new SPIPortIO(c)
|
||||
val ctrl = new Bundle {
|
||||
val sck = new SPIClocking(c).asInput
|
||||
val dla = new SPIDelay(c).asInput
|
||||
val cs = new SPIChipSelect(c).asInput
|
||||
}
|
||||
val link = new SPILinkIO(c).flip
|
||||
}
|
||||
|
||||
val phy = Module(new SPIPhysical(c))
|
||||
phy.io.ctrl.sck := io.ctrl.sck
|
||||
phy.io.ctrl.fmt := io.link.fmt
|
||||
|
||||
private val op = phy.io.op
|
||||
op.valid := Bool(true)
|
||||
op.bits.fn := SPIMicroOp.Delay
|
||||
op.bits.stb := Bool(false)
|
||||
op.bits.cnt := io.link.cnt
|
||||
op.bits.data := io.link.tx.bits
|
||||
|
||||
val cs = Reg(io.ctrl.cs)
|
||||
val cs_set = Reg(Bool())
|
||||
val cs_active = io.ctrl.cs.toggle(io.link.cs.set)
|
||||
val cs_update = (cs_active.asUInt =/= cs.dflt.asUInt)
|
||||
|
||||
val clear = Reg(init = Bool(false))
|
||||
val cs_assert = Reg(init = Bool(false))
|
||||
val cs_deassert = clear || (cs_update && !io.link.cs.hold)
|
||||
|
||||
clear := clear || (io.link.cs.clear && cs_assert)
|
||||
|
||||
val continuous = (io.ctrl.dla.interxfr === UInt(0))
|
||||
|
||||
io.port.sck := phy.io.port.sck
|
||||
io.port.dq <> phy.io.port.dq
|
||||
io.port.cs := cs.dflt
|
||||
|
||||
io.link.rx := phy.io.rx
|
||||
io.link.tx.ready := Bool(false)
|
||||
io.link.active := cs_assert
|
||||
|
||||
val (s_main :: s_interxfr :: s_intercs :: Nil) = Enum(UInt(), 3)
|
||||
val state = Reg(init = s_main)
|
||||
|
||||
switch (state) {
|
||||
is (s_main) {
|
||||
when (cs_assert) {
|
||||
when (cs_deassert) {
|
||||
op.bits.cnt := io.ctrl.dla.sckcs
|
||||
when (op.ready) {
|
||||
state := s_intercs
|
||||
}
|
||||
} .otherwise {
|
||||
op.bits.fn := SPIMicroOp.Transfer
|
||||
op.bits.stb := Bool(true)
|
||||
|
||||
op.valid := io.link.tx.valid
|
||||
io.link.tx.ready := op.ready
|
||||
when (op.fire()) {
|
||||
state := s_interxfr
|
||||
}
|
||||
}
|
||||
} .elsewhen (io.link.tx.valid) {
|
||||
// Assert CS
|
||||
op.bits.cnt := io.ctrl.dla.cssck
|
||||
when (op.ready) {
|
||||
cs_assert := Bool(true)
|
||||
cs_set := io.link.cs.set
|
||||
cs.dflt := cs_active
|
||||
}
|
||||
} .otherwise {
|
||||
// Idle
|
||||
op.bits.cnt := UInt(0)
|
||||
op.bits.stb := Bool(true)
|
||||
cs := io.ctrl.cs
|
||||
}
|
||||
}
|
||||
|
||||
is (s_interxfr) {
|
||||
// Skip if interxfr delay is zero
|
||||
op.valid := !continuous
|
||||
op.bits.cnt := io.ctrl.dla.interxfr
|
||||
when (op.ready || continuous) {
|
||||
state := s_main
|
||||
}
|
||||
}
|
||||
|
||||
is (s_intercs) {
|
||||
// Deassert CS
|
||||
op.bits.cnt := io.ctrl.dla.intercs
|
||||
op.bits.stb := Bool(true)
|
||||
cs_assert := Bool(false)
|
||||
clear := Bool(false)
|
||||
when (op.ready) {
|
||||
cs.dflt := cs.toggle(cs_set)
|
||||
state := s_main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/main/scala/devices/spi/SPIPeriphery.scala
Normal file
57
src/main/scala/devices/spi/SPIPeriphery.scala
Normal file
@ -0,0 +1,57 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import uncore.tilelink2._
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
|
||||
trait PeripherySPI {
|
||||
this: TopNetwork { val spiConfigs: Seq[SPIConfig] } =>
|
||||
val spiDevices = (spiConfigs.zipWithIndex) map {case (c, i) =>
|
||||
val spi = LazyModule(new TLSPI(c) { override lazy val valName = Some(s"spi$i") } )
|
||||
spi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
intBus.intnode := spi.intnode
|
||||
spi
|
||||
}
|
||||
}
|
||||
|
||||
trait PeripherySPIBundle {
|
||||
this: { val spiConfigs: Seq[SPIConfig] } =>
|
||||
val spi_bc = spiConfigs.map(_.bc).reduce(_.union(_))
|
||||
val spis = Vec(spiConfigs.size, new SPIPortIO(spi_bc.toSPIConfig))
|
||||
}
|
||||
|
||||
trait PeripherySPIModule {
|
||||
this: TopNetworkModule {
|
||||
val spiConfigs: Seq[SPIConfig]
|
||||
val outer: PeripherySPI
|
||||
val io: PeripherySPIBundle
|
||||
} =>
|
||||
(io.spis zip outer.spiDevices).foreach { case (io, device) =>
|
||||
io <> device.module.io.port
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait PeripherySPIFlash {
|
||||
this: TopNetwork { val spiFlashConfig: SPIFlashConfig } =>
|
||||
val qspi = LazyModule(new TLSPIFlash(spiFlashConfig))
|
||||
qspi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
qspi.fnode := TLFragmenter(1, cacheBlockBytes)(TLWidthWidget(peripheryBusConfig.beatBytes)(peripheryBus.node))
|
||||
intBus.intnode := qspi.intnode
|
||||
}
|
||||
|
||||
trait PeripherySPIFlashBundle {
|
||||
this: { val spiFlashConfig: SPIFlashConfig } =>
|
||||
val qspi = new SPIPortIO(spiFlashConfig)
|
||||
}
|
||||
|
||||
trait PeripherySPIFlashModule {
|
||||
this: TopNetworkModule {
|
||||
val spiConfigs: Seq[SPIConfig]
|
||||
val outer: PeripherySPIFlash
|
||||
val io: PeripherySPIFlashBundle
|
||||
} =>
|
||||
io.qspi <> outer.qspi.module.io.port
|
||||
}
|
157
src/main/scala/devices/spi/SPIPhysical.scala
Normal file
157
src/main/scala/devices/spi/SPIPhysical.scala
Normal file
@ -0,0 +1,157 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import sifive.blocks.util.ShiftRegisterInit
|
||||
|
||||
class SPIMicroOp(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fn = Bits(width = 1)
|
||||
val stb = Bool()
|
||||
val cnt = UInt(width = c.countBits)
|
||||
val data = Bits(width = c.frameBits)
|
||||
}
|
||||
|
||||
object SPIMicroOp {
|
||||
val Transfer = UInt(0, 1)
|
||||
val Delay = UInt(1, 1)
|
||||
}
|
||||
|
||||
class SPIPhyControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = new SPIClocking(c)
|
||||
val fmt = new SPIFormat(c)
|
||||
}
|
||||
|
||||
class SPIPhysical(c: SPIConfigBase) extends Module {
|
||||
val io = new SPIBundle(c) {
|
||||
val port = new SPIPortIO(c)
|
||||
val ctrl = new SPIPhyControl(c).asInput
|
||||
val op = Decoupled(new SPIMicroOp(c)).flip
|
||||
val rx = Valid(Bits(width = c.frameBits))
|
||||
}
|
||||
|
||||
private val op = io.op.bits
|
||||
val ctrl = Reg(io.ctrl)
|
||||
val proto = SPIProtocol.decode(ctrl.fmt.proto)
|
||||
|
||||
val accept = Wire(init = Bool(false))
|
||||
val sample = Wire(init = Bool(false))
|
||||
val setup = Wire(init = Bool(false))
|
||||
val last = Wire(init = Bool(false))
|
||||
// Delayed versions
|
||||
val setup_d = Reg(next = setup)
|
||||
val sample_d = ShiftRegisterInit(sample, c.sampleDelay, Bool(false))
|
||||
val last_d = ShiftRegisterInit(last, c.sampleDelay, Bool(false))
|
||||
|
||||
val scnt = Reg(init = UInt(0, c.countBits))
|
||||
val tcnt = Reg(io.ctrl.sck.div)
|
||||
|
||||
val stop = (scnt === UInt(0))
|
||||
val beat = (tcnt === UInt(0))
|
||||
val decr = Mux(beat, scnt, tcnt) - UInt(1)
|
||||
val sched = Wire(init = beat)
|
||||
tcnt := Mux(sched, ctrl.sck.div, decr)
|
||||
|
||||
val sck = Reg(Bool())
|
||||
val cref = Reg(init = Bool(true))
|
||||
val cinv = ctrl.sck.pha ^ ctrl.sck.pol
|
||||
|
||||
private def convert(data: UInt, fmt: SPIFormat) =
|
||||
Mux(fmt.endian === SPIEndian.MSB, data, Cat(data.toBools))
|
||||
|
||||
val rxd = Cat(io.port.dq.reverse.map(_.i))
|
||||
val samples = Seq(rxd(1), rxd(1, 0), rxd)
|
||||
|
||||
val buffer = Reg(op.data)
|
||||
val buffer_in = convert(io.op.bits.data, io.ctrl.fmt)
|
||||
val shift = if (c.sampleDelay > 0) setup_d || (sample_d && stop) else sample_d
|
||||
buffer := Mux1H(proto, samples.zipWithIndex.map { case (data, i) =>
|
||||
val n = 1 << i
|
||||
val m = c.frameBits -1
|
||||
Cat(Mux(shift, buffer(m-n, 0), buffer(m, n)),
|
||||
Mux(sample_d, data, buffer(n-1, 0)))
|
||||
})
|
||||
|
||||
private def upper(x: UInt, n: Int) = x(c.frameBits-1, c.frameBits-n)
|
||||
|
||||
val txd = Reg(init = Bits(0, io.port.dq.size))
|
||||
val txd_in = Mux(accept, upper(buffer_in, 4), upper(buffer, 4))
|
||||
val txd_sel = SPIProtocol.decode(Mux(accept, io.ctrl.fmt.proto, ctrl.fmt.proto))
|
||||
val txd_shf = (0 until txd_sel.size).map(i => txd_in(3, 4-(1<<i)))
|
||||
when (setup) {
|
||||
txd := Mux1H(txd_sel, txd_shf)
|
||||
}
|
||||
|
||||
val tx = (ctrl.fmt.iodir === SPIDirection.Tx)
|
||||
val txen_in = (proto.head +: proto.tail.map(_ && tx)).scanRight(Bool(false))(_ || _)
|
||||
val txen = txen_in :+ txen_in.last
|
||||
|
||||
io.port.sck := sck
|
||||
io.port.cs := Vec.fill(io.port.cs.size)(Bool(true)) // dummy
|
||||
(io.port.dq zip (txd.toBools zip txen)).foreach {
|
||||
case (dq, (o, oe)) =>
|
||||
dq.o := o
|
||||
dq.oe := oe
|
||||
}
|
||||
io.op.ready := Bool(false)
|
||||
|
||||
val done = Reg(init = Bool(true))
|
||||
done := done || last_d
|
||||
|
||||
io.rx.valid := done
|
||||
io.rx.bits := convert(buffer, ctrl.fmt)
|
||||
|
||||
val xfr = Reg(Bool())
|
||||
|
||||
when (stop) {
|
||||
sched := Bool(true)
|
||||
accept := Bool(true)
|
||||
} .otherwise {
|
||||
when (beat) {
|
||||
cref := !cref
|
||||
when (xfr) {
|
||||
sck := cref ^ cinv
|
||||
sample := cref
|
||||
setup := !cref
|
||||
}
|
||||
when (!cref) {
|
||||
scnt := decr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (scnt === UInt(1)) {
|
||||
last := beat && cref && xfr // Final sample
|
||||
when (beat && !cref) { // Final shift
|
||||
accept := Bool(true)
|
||||
setup := Bool(false)
|
||||
sck := ctrl.sck.pol
|
||||
}
|
||||
}
|
||||
|
||||
when (accept && done) {
|
||||
io.op.ready := Bool(true)
|
||||
when (io.op.valid) {
|
||||
scnt := op.cnt
|
||||
when (op.stb) {
|
||||
ctrl.fmt := io.ctrl.fmt
|
||||
}
|
||||
|
||||
xfr := Bool(false)
|
||||
switch (op.fn) {
|
||||
is (SPIMicroOp.Transfer) {
|
||||
buffer := buffer_in
|
||||
sck := cinv
|
||||
setup := Bool(true)
|
||||
done := (op.cnt === UInt(0))
|
||||
xfr := Bool(true)
|
||||
}
|
||||
is (SPIMicroOp.Delay) {
|
||||
when (op.stb) {
|
||||
sck := io.ctrl.sck.pol
|
||||
ctrl.sck := io.ctrl.sck
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/main/scala/devices/spi/SPIPins.scala
Normal file
34
src/main/scala/devices/spi/SPIPins.scala
Normal file
@ -0,0 +1,34 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
|
||||
|
||||
class SPIPinsIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = new GPIOPin
|
||||
val dq = Vec(4, new GPIOPin)
|
||||
val cs = Vec(c.csWidth, new GPIOPin)
|
||||
}
|
||||
|
||||
class SPIGPIOPort(c: SPIConfigBase, 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)
|
||||
}
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.sck, io.spi.sck, ds = driveStrength)
|
||||
|
||||
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
|
||||
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)
|
||||
}
|
30
src/main/scala/devices/spi/SPIRegs.scala
Normal file
30
src/main/scala/devices/spi/SPIRegs.scala
Normal file
@ -0,0 +1,30 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
object SPICRs {
|
||||
val sckdiv = 0x00
|
||||
val sckmode = 0x04
|
||||
val csid = 0x10
|
||||
val csdef = 0x14
|
||||
val csmode = 0x18
|
||||
val dcssck = 0x28
|
||||
val dsckcs = 0x2a
|
||||
val dintercs = 0x2c
|
||||
val dinterxfr = 0x2e
|
||||
|
||||
val fmt = 0x40
|
||||
val len = 0x42
|
||||
val txfifo = 0x48
|
||||
val rxfifo = 0x4c
|
||||
val txmark = 0x50
|
||||
val rxmark = 0x54
|
||||
|
||||
val insnmode = 0x60
|
||||
val insnfmt = 0x64
|
||||
val insnproto = 0x65
|
||||
val insncmd = 0x66
|
||||
val insnpad = 0x67
|
||||
|
||||
val ie = 0x70
|
||||
val ip = 0x74
|
||||
}
|
132
src/main/scala/devices/spi/TLSPI.scala
Normal file
132
src/main/scala/devices/spi/TLSPI.scala
Normal file
@ -0,0 +1,132 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import uncore.tilelink2._
|
||||
import diplomacy._
|
||||
import regmapper._
|
||||
import junctions._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
|
||||
|
||||
trait SPIConfigBase {
|
||||
val rAddress: BigInt
|
||||
val rSize: BigInt
|
||||
val rxDepth: Int
|
||||
val txDepth: Int
|
||||
|
||||
val csWidth: Int
|
||||
val frameBits: Int
|
||||
val delayBits: Int
|
||||
val divisorBits: Int
|
||||
|
||||
val sampleDelay: Int
|
||||
|
||||
lazy val csIdBits = log2Up(csWidth)
|
||||
lazy val lengthBits = log2Floor(frameBits) + 1
|
||||
lazy val countBits = math.max(lengthBits, delayBits)
|
||||
|
||||
lazy val txDepthBits = log2Floor(txDepth) + 1
|
||||
lazy val rxDepthBits = log2Floor(rxDepth) + 1
|
||||
|
||||
lazy val bc = new SPIBundleConfig(csWidth)
|
||||
}
|
||||
|
||||
case class SPIConfig(
|
||||
rAddress: BigInt,
|
||||
rSize: BigInt = 0x1000,
|
||||
rxDepth: Int = 8,
|
||||
txDepth: Int = 8,
|
||||
csWidth: Int = 1,
|
||||
frameBits: Int = 8,
|
||||
delayBits: Int = 8,
|
||||
divisorBits: Int = 12,
|
||||
sampleDelay: Int = 2)
|
||||
extends SPIConfigBase {
|
||||
|
||||
require(frameBits >= 4)
|
||||
require(sampleDelay >= 0)
|
||||
}
|
||||
|
||||
case class SPIBundleConfig(csWidth: Int)
|
||||
{
|
||||
def union(that: SPIBundleConfig): SPIBundleConfig =
|
||||
SPIBundleConfig(scala.math.max(csWidth, that.csWidth))
|
||||
|
||||
def toSPIConfig: SPIConfig = new SPIConfig(rAddress = -1,
|
||||
csWidth = csWidth)
|
||||
}
|
||||
|
||||
class SPITopBundle(val i: Vec[Vec[Bool]], val r: Vec[TLBundle]) extends Bundle
|
||||
|
||||
class SPITopModule[B <: SPITopBundle](c: SPIConfigBase, bundle: => B, outer: TLSPIBase)
|
||||
extends LazyModuleImp(outer) {
|
||||
|
||||
val io = new Bundle {
|
||||
val port = new SPIPortIO(c)
|
||||
val tl = bundle
|
||||
}
|
||||
|
||||
val ctrl = Reg(init = SPIControl.init(c))
|
||||
|
||||
val fifo = Module(new SPIFIFO(c))
|
||||
val mac = Module(new SPIMedia(c))
|
||||
io.port <> mac.io.port
|
||||
|
||||
fifo.io.ctrl.fmt := ctrl.fmt
|
||||
fifo.io.ctrl.cs <> ctrl.cs
|
||||
fifo.io.ctrl.wm := ctrl.wm
|
||||
mac.io.ctrl.sck := ctrl.sck
|
||||
mac.io.ctrl.dla := ctrl.dla
|
||||
mac.io.ctrl.cs <> ctrl.cs
|
||||
|
||||
val ie = Reg(init = new SPIInterrupts().fromBits(Bits(0)))
|
||||
val ip = fifo.io.ip
|
||||
io.tl.i(0)(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
|
||||
|
||||
protected val regmapBase = Seq(
|
||||
SPICRs.sckdiv -> Seq(RegField(c.divisorBits, ctrl.sck.div)),
|
||||
SPICRs.sckmode -> Seq(
|
||||
RegField(1, ctrl.sck.pha),
|
||||
RegField(1, ctrl.sck.pol)),
|
||||
SPICRs.csid -> Seq(RegField(c.csIdBits, ctrl.cs.id)),
|
||||
SPICRs.csdef -> ctrl.cs.dflt.map(x => RegField(1, x)),
|
||||
SPICRs.csmode -> Seq(RegField(SPICSMode.width, ctrl.cs.mode)),
|
||||
SPICRs.dcssck -> Seq(RegField(c.delayBits, ctrl.dla.cssck)),
|
||||
SPICRs.dsckcs -> Seq(RegField(c.delayBits, ctrl.dla.sckcs)),
|
||||
SPICRs.dintercs -> Seq(RegField(c.delayBits, ctrl.dla.intercs)),
|
||||
SPICRs.dinterxfr -> Seq(RegField(c.delayBits, ctrl.dla.interxfr)),
|
||||
|
||||
SPICRs.fmt -> Seq(
|
||||
RegField(SPIProtocol.width, ctrl.fmt.proto),
|
||||
RegField(SPIEndian.width, ctrl.fmt.endian),
|
||||
RegField(SPIDirection.width, ctrl.fmt.iodir)),
|
||||
SPICRs.len -> Seq(RegField(c.lengthBits, ctrl.fmt.len)),
|
||||
|
||||
SPICRs.txfifo -> NonBlockingEnqueue(fifo.io.tx),
|
||||
SPICRs.rxfifo -> NonBlockingDequeue(fifo.io.rx),
|
||||
|
||||
SPICRs.txmark -> Seq(RegField(c.txDepthBits, ctrl.wm.tx)),
|
||||
SPICRs.rxmark -> Seq(RegField(c.rxDepthBits, ctrl.wm.rx)),
|
||||
|
||||
SPICRs.ie -> Seq(
|
||||
RegField(1, ie.txwm),
|
||||
RegField(1, ie.rxwm)),
|
||||
SPICRs.ip -> Seq(
|
||||
RegField.r(1, ip.txwm),
|
||||
RegField.r(1, ip.rxwm)))
|
||||
}
|
||||
|
||||
abstract class TLSPIBase(c: SPIConfigBase)(implicit val p: Parameters) extends LazyModule {
|
||||
require(isPow2(c.rSize))
|
||||
val rnode = TLRegisterNode(address = AddressSet(c.rAddress, c.rSize-1), beatBytes = p(PeripheryBusConfig).beatBytes)
|
||||
val intnode = IntSourceNode(1)
|
||||
}
|
||||
|
||||
class TLSPI(c: SPIConfig)(implicit p: Parameters) extends TLSPIBase(c)(p) {
|
||||
lazy val module = new SPITopModule(c, new SPITopBundle(intnode.bundleOut, rnode.bundleIn), this) {
|
||||
mac.io.link <> fifo.io.link
|
||||
rnode.regmap(regmapBase:_*)
|
||||
}
|
||||
}
|
114
src/main/scala/devices/spi/TLSPIFlash.scala
Normal file
114
src/main/scala/devices/spi/TLSPIFlash.scala
Normal file
@ -0,0 +1,114 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
|
||||
trait SPIFlashConfigBase extends SPIConfigBase {
|
||||
val fAddress: BigInt
|
||||
val fSize: BigInt
|
||||
|
||||
val insnAddrBytes: Int
|
||||
val insnPadLenBits: Int
|
||||
lazy val insnCmdBits = frameBits
|
||||
lazy val insnAddrBits = insnAddrBytes * frameBits
|
||||
lazy val insnAddrLenBits = log2Floor(insnAddrBytes) + 1
|
||||
}
|
||||
|
||||
case class SPIFlashConfig(
|
||||
rAddress: BigInt,
|
||||
fAddress: BigInt,
|
||||
rSize: BigInt = 0x1000,
|
||||
fSize: BigInt = 0x20000000,
|
||||
rxDepth: Int = 8,
|
||||
txDepth: Int = 8,
|
||||
csWidth: Int = 1,
|
||||
delayBits: Int = 8,
|
||||
divisorBits: Int = 12,
|
||||
sampleDelay: Int = 2)
|
||||
extends SPIFlashConfigBase {
|
||||
val frameBits = 8
|
||||
val insnAddrBytes = 4
|
||||
val insnPadLenBits = 4
|
||||
|
||||
require(insnPadLenBits <= delayBits)
|
||||
require(sampleDelay >= 0)
|
||||
}
|
||||
|
||||
class SPIFlashTopBundle(i: Vec[Vec[Bool]], r: Vec[TLBundle], val f: Vec[TLBundle]) extends SPITopBundle(i, r)
|
||||
|
||||
class SPIFlashTopModule[B <: SPIFlashTopBundle]
|
||||
(c: SPIFlashConfigBase, bundle: => B, outer: TLSPIFlashBase)
|
||||
extends SPITopModule(c, bundle, outer) {
|
||||
|
||||
val flash = Module(new SPIFlashMap(c))
|
||||
val arb = Module(new SPIArbiter(c, 2))
|
||||
|
||||
private val f = io.tl.f.head
|
||||
// Tie unused channels
|
||||
f.b.valid := Bool(false)
|
||||
f.c.ready := Bool(true)
|
||||
f.e.ready := Bool(true)
|
||||
|
||||
val a = Reg(f.a.bits)
|
||||
val a_msb = log2Ceil(c.fSize) - 1
|
||||
|
||||
when (f.a.fire()) {
|
||||
a := f.a.bits
|
||||
}
|
||||
|
||||
flash.io.addr.bits.next := f.a.bits.address(a_msb, 0)
|
||||
flash.io.addr.bits.hold := a.address(a_msb, 0)
|
||||
flash.io.addr.valid := f.a.valid
|
||||
f.a.ready := flash.io.addr.ready
|
||||
|
||||
f.d.bits := outer.fnode.edgesIn.head.AccessAck(a, UInt(0), flash.io.data.bits)
|
||||
f.d.valid := flash.io.data.valid
|
||||
flash.io.data.ready := f.d.ready
|
||||
|
||||
val insn = Reg(init = SPIFlashInsn.init(c))
|
||||
val flash_en = Reg(init = Bool(true))
|
||||
|
||||
flash.io.ctrl.insn := insn
|
||||
flash.io.ctrl.fmt <> ctrl.fmt
|
||||
flash.io.en := flash_en
|
||||
arb.io.sel := !flash_en
|
||||
|
||||
protected val regmapFlash = Seq(
|
||||
SPICRs.insnmode -> Seq(RegField(1, flash_en)),
|
||||
SPICRs.insnfmt -> Seq(
|
||||
RegField(1, insn.cmd.en),
|
||||
RegField(c.insnAddrLenBits, insn.addr.len),
|
||||
RegField(c.insnPadLenBits, insn.pad.cnt)),
|
||||
SPICRs.insnproto -> Seq(
|
||||
RegField(SPIProtocol.width, insn.cmd.proto),
|
||||
RegField(SPIProtocol.width, insn.addr.proto),
|
||||
RegField(SPIProtocol.width, insn.data.proto)),
|
||||
SPICRs.insncmd -> Seq(RegField(c.insnCmdBits, insn.cmd.code)),
|
||||
SPICRs.insnpad -> Seq(RegField(c.frameBits, insn.pad.code)))
|
||||
}
|
||||
|
||||
abstract class TLSPIFlashBase(c: SPIFlashConfigBase)(implicit p: Parameters) extends TLSPIBase(c)(p) {
|
||||
require(isPow2(c.fSize))
|
||||
val fnode = TLManagerNode(1, TLManagerParameters(
|
||||
address = Seq(AddressSet(c.fAddress, c.fSize-1)),
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = true,
|
||||
supportsGet = TransferSizes(1, 1),
|
||||
fifoId = Some(0)))
|
||||
}
|
||||
|
||||
class TLSPIFlash(c: SPIFlashConfig)(implicit p: Parameters) extends TLSPIFlashBase(c)(p) {
|
||||
lazy val module = new SPIFlashTopModule(c,
|
||||
new SPIFlashTopBundle(intnode.bundleOut, rnode.bundleIn, fnode.bundleIn), this) {
|
||||
|
||||
arb.io.inner(0) <> flash.io.link
|
||||
arb.io.inner(1) <> fifo.io.link
|
||||
mac.io.link <> arb.io.outer
|
||||
|
||||
rnode.regmap(regmapBase ++ regmapFlash:_*)
|
||||
}
|
||||
}
|
275
src/main/scala/devices/uart/UART.scala
Normal file
275
src/main/scala/devices/uart/UART.scala
Normal file
@ -0,0 +1,275 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.uart
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
import junctions._
|
||||
import util._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
|
||||
|
||||
case class UARTConfig(
|
||||
address: BigInt,
|
||||
dataBits: Int = 8,
|
||||
stopBits: Int = 2,
|
||||
divisorBits: Int = 16,
|
||||
oversample: Int = 4,
|
||||
nSamples: Int = 3,
|
||||
nTxEntries: Int = 8,
|
||||
nRxEntries: Int = 8)
|
||||
|
||||
trait HasUARTParameters {
|
||||
val c: UARTConfig
|
||||
val uartDataBits = c.dataBits
|
||||
val uartStopBits = c.stopBits
|
||||
val uartDivisorBits = c.divisorBits
|
||||
|
||||
val uartOversample = c.oversample
|
||||
val uartOversampleFactor = 1 << uartOversample
|
||||
val uartNSamples = c.nSamples
|
||||
|
||||
val uartNTxEntries = c.nTxEntries
|
||||
val uartNRxEntries = c.nRxEntries
|
||||
|
||||
require(uartDivisorBits > uartOversample)
|
||||
require(uartOversampleFactor > uartNSamples)
|
||||
}
|
||||
|
||||
abstract class UARTModule(val c: UARTConfig)(implicit val p: Parameters)
|
||||
extends Module with HasUARTParameters
|
||||
|
||||
class UARTPortIO extends Bundle {
|
||||
val txd = Bool(OUTPUT)
|
||||
val rxd = Bool(INPUT)
|
||||
}
|
||||
|
||||
trait MixUARTParameters {
|
||||
val params: (UARTConfig, Parameters)
|
||||
val c = params._1
|
||||
implicit val p = params._2
|
||||
}
|
||||
|
||||
trait UARTTopBundle extends Bundle with MixUARTParameters with HasUARTParameters {
|
||||
val port = new UARTPortIO
|
||||
}
|
||||
|
||||
class UARTTx(c: UARTConfig)(implicit p: Parameters) extends UARTModule(c)(p) {
|
||||
val io = new Bundle {
|
||||
val en = Bool(INPUT)
|
||||
val in = Decoupled(Bits(width = uartDataBits)).flip
|
||||
val out = Bits(OUTPUT, 1)
|
||||
val div = UInt(INPUT, uartDivisorBits)
|
||||
val nstop = UInt(INPUT, log2Up(uartStopBits))
|
||||
}
|
||||
|
||||
val prescaler = Reg(init = UInt(0, uartDivisorBits))
|
||||
val pulse = (prescaler === UInt(0))
|
||||
|
||||
private val n = uartDataBits + 1
|
||||
val counter = Reg(init = UInt(0, log2Floor(n + uartStopBits) + 1))
|
||||
val shifter = Reg(Bits(width = n))
|
||||
val out = Reg(init = Bits(1, 1))
|
||||
io.out := out
|
||||
|
||||
val busy = (counter =/= UInt(0))
|
||||
io.in.ready := io.en && !busy
|
||||
when (io.in.fire()) {
|
||||
printf("%c", io.in.bits)
|
||||
shifter := Cat(io.in.bits, Bits(0, 1))
|
||||
counter := Mux1H((0 until uartStopBits).map(i =>
|
||||
(io.nstop === UInt(i)) -> UInt(n + i + 1)))
|
||||
}
|
||||
when (busy) {
|
||||
prescaler := Mux(pulse, io.div, prescaler - UInt(1))
|
||||
}
|
||||
when (pulse && busy) {
|
||||
counter := counter - UInt(1)
|
||||
shifter := Cat(Bits(1, 1), shifter >> 1)
|
||||
out := shifter(0)
|
||||
}
|
||||
}
|
||||
|
||||
class UARTRx(c: UARTConfig)(implicit p: Parameters) extends UARTModule(c)(p) {
|
||||
val io = new Bundle {
|
||||
val en = Bool(INPUT)
|
||||
val in = Bits(INPUT, 1)
|
||||
val out = Valid(Bits(width = uartDataBits))
|
||||
val div = UInt(INPUT, uartDivisorBits)
|
||||
}
|
||||
|
||||
val debounce = Reg(init = UInt(0, 2))
|
||||
val debounce_max = (debounce === UInt(3))
|
||||
val debounce_min = (debounce === UInt(0))
|
||||
|
||||
val prescaler = Reg(init = UInt(0, uartDivisorBits - uartOversample))
|
||||
val start = Wire(init = Bool(false))
|
||||
val busy = Wire(init = Bool(false))
|
||||
val pulse = (prescaler === UInt(0)) && busy
|
||||
|
||||
when (busy) {
|
||||
prescaler := prescaler - UInt(1)
|
||||
}
|
||||
when (start || pulse) {
|
||||
prescaler := io.div >> uartOversample
|
||||
}
|
||||
|
||||
val sample = Reg(Bits(width = uartNSamples))
|
||||
val voter = new Majority(sample.toBools.toSet)
|
||||
when (pulse) {
|
||||
sample := Cat(sample, io.in)
|
||||
}
|
||||
|
||||
private val delay0 = (uartOversampleFactor + uartNSamples) >> 1
|
||||
private val delay1 = uartOversampleFactor
|
||||
|
||||
val timer = Reg(UInt(width = uartOversample + 1))
|
||||
val counter = Reg(UInt(width = log2Floor(uartDataBits) + 1))
|
||||
val shifter = Reg(Bits(width = uartDataBits))
|
||||
val expire = (timer === UInt(0)) && pulse
|
||||
|
||||
val sched = Wire(init = Bool(false))
|
||||
when (pulse) {
|
||||
timer := timer - UInt(1)
|
||||
}
|
||||
when (sched) {
|
||||
timer := UInt(delay1-1)
|
||||
}
|
||||
|
||||
val valid = Reg(init = Bool(false))
|
||||
valid := Bool(false)
|
||||
io.out.valid := valid
|
||||
io.out.bits := shifter
|
||||
|
||||
val (s_idle :: s_start :: s_data :: Nil) = Enum(UInt(), 3)
|
||||
val state = Reg(init = s_idle)
|
||||
|
||||
switch (state) {
|
||||
is (s_idle) {
|
||||
when (!(!io.in) && !debounce_min) {
|
||||
debounce := debounce - UInt(1)
|
||||
}
|
||||
when (!io.in) {
|
||||
debounce := debounce + UInt(1)
|
||||
when (debounce_max) {
|
||||
state := s_start
|
||||
start := Bool(true)
|
||||
timer := UInt(delay0-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is (s_start) {
|
||||
busy := Bool(true)
|
||||
when (expire) {
|
||||
sched := Bool(true)
|
||||
when (voter.out) {
|
||||
state := s_idle
|
||||
} .otherwise {
|
||||
state := s_data
|
||||
counter := UInt(uartDataBits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is (s_data) {
|
||||
busy := Bool(true)
|
||||
when (expire) {
|
||||
counter := counter - UInt(1)
|
||||
when (counter === UInt(0)) {
|
||||
state := s_idle
|
||||
valid := Bool(true)
|
||||
} .otherwise {
|
||||
shifter := Cat(voter.out, shifter >> 1)
|
||||
sched := Bool(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (!io.en) {
|
||||
debounce := UInt(0)
|
||||
}
|
||||
}
|
||||
|
||||
class UARTInterrupts extends Bundle {
|
||||
val rxwm = Bool()
|
||||
val txwm = Bool()
|
||||
}
|
||||
|
||||
trait UARTTopModule extends Module with MixUARTParameters with HasUARTParameters with HasRegMap {
|
||||
val io: UARTTopBundle
|
||||
|
||||
val txm = Module(new UARTTx(c))
|
||||
val txq = Module(new Queue(txm.io.in.bits, uartNTxEntries))
|
||||
|
||||
val rxm = Module(new UARTRx(c))
|
||||
val rxq = Module(new Queue(rxm.io.out.bits, uartNRxEntries))
|
||||
|
||||
val divinit = 542 // (62.5MHz / 115200)
|
||||
val div = Reg(init = UInt(divinit, uartDivisorBits))
|
||||
|
||||
private val stopCountBits = log2Up(uartStopBits)
|
||||
private val txCountBits = log2Floor(uartNTxEntries) + 1
|
||||
private val rxCountBits = log2Floor(uartNRxEntries) + 1
|
||||
|
||||
val txen = Reg(init = Bool(false))
|
||||
val rxen = Reg(init = Bool(false))
|
||||
val txwm = Reg(init = UInt(0, txCountBits))
|
||||
val rxwm = Reg(init = UInt(0, rxCountBits))
|
||||
val nstop = Reg(init = UInt(0, stopCountBits))
|
||||
|
||||
txm.io.en := txen
|
||||
txm.io.in <> txq.io.deq
|
||||
txm.io.div := div
|
||||
txm.io.nstop := nstop
|
||||
io.port.txd := txm.io.out
|
||||
|
||||
rxm.io.en := rxen
|
||||
rxm.io.in := io.port.rxd
|
||||
rxq.io.enq <> rxm.io.out
|
||||
rxm.io.div := div
|
||||
|
||||
val ie = Reg(init = new UARTInterrupts().fromBits(Bits(0)))
|
||||
val ip = Wire(new UARTInterrupts)
|
||||
|
||||
ip.txwm := (txq.io.count < txwm)
|
||||
ip.rxwm := (rxq.io.count > rxwm)
|
||||
interrupts(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
|
||||
|
||||
regmap(
|
||||
UARTCtrlRegs.txfifo -> NonBlockingEnqueue(txq.io.enq),
|
||||
UARTCtrlRegs.rxfifo -> NonBlockingDequeue(rxq.io.deq),
|
||||
|
||||
UARTCtrlRegs.txctrl -> Seq(
|
||||
RegField(1, txen),
|
||||
RegField(stopCountBits, nstop)),
|
||||
UARTCtrlRegs.rxctrl -> Seq(RegField(1, rxen)),
|
||||
UARTCtrlRegs.txmark -> Seq(RegField(txCountBits, txwm)),
|
||||
UARTCtrlRegs.rxmark -> Seq(RegField(rxCountBits, rxwm)),
|
||||
|
||||
UARTCtrlRegs.ie -> Seq(
|
||||
RegField(1, ie.txwm),
|
||||
RegField(1, ie.rxwm)),
|
||||
|
||||
UARTCtrlRegs.ip -> Seq(
|
||||
RegField.r(1, ip.txwm),
|
||||
RegField.r(1, ip.rxwm)),
|
||||
|
||||
UARTCtrlRegs.div -> Seq(
|
||||
RegField(uartDivisorBits, div))
|
||||
)
|
||||
}
|
||||
|
||||
class Majority(in: Set[Bool]) {
|
||||
private val n = (in.size >> 1) + 1
|
||||
private val clauses = in.subsets(n).map(_.reduce(_ && _))
|
||||
val out = clauses.reduce(_ || _)
|
||||
}
|
||||
|
||||
// Magic TL2 Incantation to create a TL2 Slave
|
||||
class UART(c: UARTConfig)(implicit val p: Parameters)
|
||||
extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = p(PeripheryBusConfig).beatBytes)(
|
||||
new TLRegBundle((c, p), _) with UARTTopBundle)(
|
||||
new TLRegModule((c, p), _, _) with UARTTopModule)
|
15
src/main/scala/devices/uart/UARTCtrlRegs.scala
Normal file
15
src/main/scala/devices/uart/UARTCtrlRegs.scala
Normal file
@ -0,0 +1,15 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.uart
|
||||
|
||||
object UARTCtrlRegs {
|
||||
val txfifo = 0x00
|
||||
val rxfifo = 0x04
|
||||
val txctrl = 0x08
|
||||
val txmark = 0x0a
|
||||
val rxctrl = 0x0c
|
||||
val rxmark = 0x0e
|
||||
|
||||
val ie = 0x10
|
||||
val ip = 0x14
|
||||
val div = 0x18
|
||||
}
|
54
src/main/scala/devices/uart/UARTPeriphery.scala
Normal file
54
src/main/scala/devices/uart/UARTPeriphery.scala
Normal file
@ -0,0 +1,54 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.uart
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
import rocketchip._
|
||||
|
||||
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
|
||||
import sifive.blocks.util.ShiftRegisterInit
|
||||
|
||||
trait PeripheryUART {
|
||||
this: TopNetwork {
|
||||
val uartConfigs: Seq[UARTConfig]
|
||||
} =>
|
||||
val uartDevices = uartConfigs.zipWithIndex.map { case (c, i) =>
|
||||
val uart = LazyModule(new UART(c) { override lazy val valName = Some(s"uart$i") } )
|
||||
uart.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
intBus.intnode := uart.intnode
|
||||
uart
|
||||
}
|
||||
}
|
||||
|
||||
trait PeripheryUARTBundle {
|
||||
this: { val uartConfigs: Seq[UARTConfig] } =>
|
||||
val uarts = Vec(uartConfigs.size, new UARTPortIO)
|
||||
}
|
||||
|
||||
trait PeripheryUARTModule {
|
||||
this: TopNetworkModule {
|
||||
val outer: PeripheryUART
|
||||
val io: PeripheryUARTBundle
|
||||
} =>
|
||||
(io.uarts zip outer.uartDevices).foreach { case (io, device) =>
|
||||
io <> device.module.io.port
|
||||
}
|
||||
}
|
||||
|
||||
class UARTPinsIO extends Bundle {
|
||||
val rxd = new GPIOPin
|
||||
val txd = new GPIOPin
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
158
src/main/scala/devices/xilinxvc707mig/XilinxVC707MIG.scala
Normal file
158
src/main/scala/devices/xilinxvc707mig/XilinxVC707MIG.scala
Normal file
@ -0,0 +1,158 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.xilinxvc707mig
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
import uncore.axi4._
|
||||
import rocketchip._
|
||||
import sifive.blocks.ip.xilinx.vc707mig.{VC707MIGUnidirectionalIOClocksReset, VC707MIGUnidirectionalIODDR, vc707mig}
|
||||
|
||||
trait HasXilinxVC707MIGParameters {
|
||||
}
|
||||
|
||||
class XilinxVC707MIGPads extends Bundle with VC707MIGUnidirectionalIODDR {
|
||||
val _inout_ddr3_dq = Bits(OUTPUT,64)
|
||||
val _inout_ddr3_dqs_n = Bits(OUTPUT,8)
|
||||
val _inout_ddr3_dqs_p = Bits(OUTPUT,8)
|
||||
}
|
||||
|
||||
class XilinxVC707MIGIO extends Bundle with VC707MIGUnidirectionalIODDR
|
||||
with VC707MIGUnidirectionalIOClocksReset {
|
||||
val _inout_ddr3_dq = Bits(OUTPUT,64)
|
||||
val _inout_ddr3_dqs_n = Bits(OUTPUT,8)
|
||||
val _inout_ddr3_dqs_p = Bits(OUTPUT,8)
|
||||
}
|
||||
|
||||
class XilinxVC707MIG(implicit p: Parameters) extends LazyModule with HasXilinxVC707MIGParameters {
|
||||
val node = TLInputNode()
|
||||
val axi4 = AXI4InternalOutputNode(AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = Seq(AddressSet(p(ExtMem).base, p(ExtMem).size-1)),
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = true,
|
||||
supportsWrite = TransferSizes(1, 256*8),
|
||||
supportsRead = TransferSizes(1, 256*8),
|
||||
interleavedId = Some(0))),
|
||||
beatBytes = 8))
|
||||
|
||||
val xing = LazyModule(new TLAsyncCrossing)
|
||||
val toaxi4 = LazyModule(new TLToAXI4(idBits = 4))
|
||||
|
||||
xing.node := node
|
||||
val monitor = (toaxi4.node := xing.node)
|
||||
axi4 := toaxi4.node
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new Bundle {
|
||||
val port = new XilinxVC707MIGIO
|
||||
val tl = node.bundleIn
|
||||
}
|
||||
|
||||
//MIG black box instantiation
|
||||
val blackbox = Module(new vc707mig)
|
||||
|
||||
//pins to top level
|
||||
|
||||
//inouts
|
||||
io.port._inout_ddr3_dq := blackbox.io.ddr3_dq
|
||||
io.port._inout_ddr3_dqs_n := blackbox.io.ddr3_dqs_n
|
||||
io.port._inout_ddr3_dqs_p := blackbox.io.ddr3_dqs_p
|
||||
|
||||
//outputs
|
||||
io.port.ddr3_addr := blackbox.io.ddr3_addr
|
||||
io.port.ddr3_ba := blackbox.io.ddr3_ba
|
||||
io.port.ddr3_ras_n := blackbox.io.ddr3_ras_n
|
||||
io.port.ddr3_cas_n := blackbox.io.ddr3_cas_n
|
||||
io.port.ddr3_we_n := blackbox.io.ddr3_we_n
|
||||
io.port.ddr3_reset_n := blackbox.io.ddr3_reset_n
|
||||
io.port.ddr3_ck_p := blackbox.io.ddr3_ck_p
|
||||
io.port.ddr3_ck_n := blackbox.io.ddr3_ck_n
|
||||
io.port.ddr3_cke := blackbox.io.ddr3_cke
|
||||
io.port.ddr3_cs_n := blackbox.io.ddr3_cs_n
|
||||
io.port.ddr3_dm := blackbox.io.ddr3_dm
|
||||
io.port.ddr3_odt := blackbox.io.ddr3_odt
|
||||
|
||||
//inputs
|
||||
//differential system clock
|
||||
blackbox.io.sys_clk_n := io.port.sys_clk_n
|
||||
blackbox.io.sys_clk_p := io.port.sys_clk_p
|
||||
|
||||
//user interface signals
|
||||
val axi_async = axi4.bundleIn(0)
|
||||
xing.module.io.in_clock := clock
|
||||
xing.module.io.in_reset := reset
|
||||
xing.module.io.out_clock := blackbox.io.ui_clk
|
||||
xing.module.io.out_reset := blackbox.io.ui_clk_sync_rst
|
||||
toaxi4.module.clock := blackbox.io.ui_clk
|
||||
toaxi4.module.reset := blackbox.io.ui_clk_sync_rst
|
||||
monitor.foreach { lm =>
|
||||
lm.module.clock := blackbox.io.ui_clk
|
||||
lm.module.reset := blackbox.io.ui_clk_sync_rst
|
||||
}
|
||||
|
||||
io.port.ui_clk := blackbox.io.ui_clk
|
||||
io.port.ui_clk_sync_rst := blackbox.io.ui_clk_sync_rst
|
||||
io.port.mmcm_locked := blackbox.io.mmcm_locked
|
||||
blackbox.io.aresetn := io.port.aresetn
|
||||
blackbox.io.app_sr_req := Bool(false)
|
||||
blackbox.io.app_ref_req := Bool(false)
|
||||
blackbox.io.app_zq_req := Bool(false)
|
||||
//app_sr_active := unconnected
|
||||
//app_ref_ack := unconnected
|
||||
//app_zq_ack := unconnected
|
||||
|
||||
//slave AXI interface write address ports
|
||||
blackbox.io.s_axi_awid := axi_async.aw.bits.id
|
||||
blackbox.io.s_axi_awaddr := axi_async.aw.bits.addr //truncation ??
|
||||
blackbox.io.s_axi_awlen := axi_async.aw.bits.len
|
||||
blackbox.io.s_axi_awsize := axi_async.aw.bits.size
|
||||
blackbox.io.s_axi_awburst := axi_async.aw.bits.burst
|
||||
blackbox.io.s_axi_awlock := axi_async.aw.bits.lock
|
||||
blackbox.io.s_axi_awcache := UInt("b0011")
|
||||
blackbox.io.s_axi_awprot := axi_async.aw.bits.prot
|
||||
blackbox.io.s_axi_awqos := axi_async.aw.bits.qos
|
||||
blackbox.io.s_axi_awvalid := axi_async.aw.valid
|
||||
axi_async.aw.ready := blackbox.io.s_axi_awready
|
||||
|
||||
//slave interface write data ports
|
||||
blackbox.io.s_axi_wdata := axi_async.w.bits.data
|
||||
blackbox.io.s_axi_wstrb := axi_async.w.bits.strb
|
||||
blackbox.io.s_axi_wlast := axi_async.w.bits.last
|
||||
blackbox.io.s_axi_wvalid := axi_async.w.valid
|
||||
axi_async.w.ready := blackbox.io.s_axi_wready
|
||||
|
||||
//slave interface write response
|
||||
blackbox.io.s_axi_bready := axi_async.b.ready
|
||||
axi_async.b.bits.id := blackbox.io.s_axi_bid
|
||||
axi_async.b.bits.resp := blackbox.io.s_axi_bresp
|
||||
axi_async.b.valid := blackbox.io.s_axi_bvalid
|
||||
|
||||
//slave AXI interface read address ports
|
||||
blackbox.io.s_axi_arid := axi_async.ar.bits.id
|
||||
blackbox.io.s_axi_araddr := axi_async.ar.bits.addr //truncation ??
|
||||
blackbox.io.s_axi_arlen := axi_async.ar.bits.len
|
||||
blackbox.io.s_axi_arsize := axi_async.ar.bits.size
|
||||
blackbox.io.s_axi_arburst := axi_async.ar.bits.burst
|
||||
blackbox.io.s_axi_arlock := axi_async.ar.bits.lock
|
||||
blackbox.io.s_axi_arcache := UInt("b0011")
|
||||
blackbox.io.s_axi_arprot := axi_async.ar.bits.prot
|
||||
blackbox.io.s_axi_arqos := axi_async.ar.bits.qos
|
||||
blackbox.io.s_axi_arvalid := axi_async.ar.valid
|
||||
axi_async.ar.ready := blackbox.io.s_axi_arready
|
||||
|
||||
//slace AXI interface read data ports
|
||||
blackbox.io.s_axi_rready := axi_async.r.ready
|
||||
axi_async.r.bits.id := blackbox.io.s_axi_rid
|
||||
axi_async.r.bits.data := blackbox.io.s_axi_rdata
|
||||
axi_async.r.bits.resp := blackbox.io.s_axi_rresp
|
||||
axi_async.r.bits.last := blackbox.io.s_axi_rlast
|
||||
axi_async.r.valid := blackbox.io.s_axi_rvalid
|
||||
|
||||
//misc
|
||||
io.port.init_calib_complete := blackbox.io.init_calib_complete
|
||||
blackbox.io.sys_rst :=io.port.sys_rst
|
||||
//mig.device_temp :- unconnceted
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.xilinxvc707mig
|
||||
|
||||
import Chisel._
|
||||
import diplomacy._
|
||||
import rocketchip.{TopNetwork,TopNetworkModule,TopNetworkBundle}
|
||||
import coreplex.BankedL2Config
|
||||
|
||||
trait PeripheryXilinxVC707MIG extends TopNetwork {
|
||||
val module: PeripheryXilinxVC707MIGModule
|
||||
|
||||
val xilinxvc707mig = LazyModule(new XilinxVC707MIG)
|
||||
require(p(BankedL2Config).nMemoryChannels == 1, "Coreplex must have 1 master memory port")
|
||||
val mem = Seq(xilinxvc707mig.node)
|
||||
}
|
||||
|
||||
trait PeripheryXilinxVC707MIGBundle extends TopNetworkBundle {
|
||||
val xilinxvc707mig = new XilinxVC707MIGIO
|
||||
}
|
||||
|
||||
trait PeripheryXilinxVC707MIGModule extends TopNetworkModule {
|
||||
val outer: PeripheryXilinxVC707MIG
|
||||
val io: PeripheryXilinxVC707MIGBundle
|
||||
|
||||
io.xilinxvc707mig <> outer.xilinxvc707mig.module.io.port
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.xilinxvc707pciex1
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
import uncore.axi4._
|
||||
import rocketchip._
|
||||
import sifive.blocks.ip.xilinx.vc707axi_to_pcie_x1.{VC707AXIToPCIeX1, VC707AXIToPCIeX1IOClocksReset, VC707AXIToPCIeX1IOSerial}
|
||||
import sifive.blocks.ip.xilinx.ibufds_gte2.IBUFDS_GTE2
|
||||
|
||||
class XilinxVC707PCIeX1Pads extends Bundle with VC707AXIToPCIeX1IOSerial
|
||||
|
||||
class XilinxVC707PCIeX1IO extends Bundle with VC707AXIToPCIeX1IOSerial
|
||||
with VC707AXIToPCIeX1IOClocksReset {
|
||||
val axi_ctl_aresetn = Bool(INPUT)
|
||||
val REFCLK_rxp = Bool(INPUT)
|
||||
val REFCLK_rxn = Bool(INPUT)
|
||||
}
|
||||
|
||||
class XilinxVC707PCIeX1(implicit p: Parameters) extends LazyModule {
|
||||
val slave = TLInputNode()
|
||||
val control = TLInputNode()
|
||||
val master = TLOutputNode()
|
||||
val intnode = IntSourceNode(1)
|
||||
|
||||
val axi_to_pcie_x1 = LazyModule(new VC707AXIToPCIeX1)
|
||||
axi_to_pcie_x1.slave := TLToAXI4(idBits=4)(slave)
|
||||
axi_to_pcie_x1.control := AXI4Fragmenter(lite=true, maxInFlight=4)(TLToAXI4(idBits=0)(control))
|
||||
master := TLWidthWidget(64)(AXI4ToTL()(AXI4Fragmenter()(axi_to_pcie_x1.master)))
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new Bundle {
|
||||
val port = new XilinxVC707PCIeX1IO
|
||||
val slave_in = slave.bundleIn
|
||||
val control_in = control.bundleIn
|
||||
val master_out = master.bundleOut
|
||||
val interrupt = intnode.bundleOut
|
||||
}
|
||||
|
||||
io.port <> axi_to_pcie_x1.module.io.port
|
||||
io.interrupt(0)(0) := axi_to_pcie_x1.module.io.interrupt_out
|
||||
|
||||
//PCIe Reference Clock
|
||||
val ibufds_gte2 = Module(new IBUFDS_GTE2)
|
||||
axi_to_pcie_x1.module.io.REFCLK := ibufds_gte2.io.O
|
||||
ibufds_gte2.io.CEB := UInt(0)
|
||||
ibufds_gte2.io.I := io.port.REFCLK_rxp
|
||||
ibufds_gte2.io.IB := io.port.REFCLK_rxn
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.xilinxvc707pciex1
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import rocketchip.{L2Crossbar,L2CrossbarModule,L2CrossbarBundle}
|
||||
import uncore.tilelink2.TLWidthWidget
|
||||
|
||||
trait PeripheryXilinxVC707PCIeX1 extends L2Crossbar {
|
||||
|
||||
val xilinxvc707pcie = LazyModule(new XilinxVC707PCIeX1)
|
||||
l2.node := xilinxvc707pcie.master
|
||||
xilinxvc707pcie.slave := TLWidthWidget(socBusConfig.beatBytes)(socBus.node)
|
||||
xilinxvc707pcie.control := TLWidthWidget(socBusConfig.beatBytes)(socBus.node)
|
||||
intBus.intnode := xilinxvc707pcie.intnode
|
||||
}
|
||||
|
||||
trait PeripheryXilinxVC707PCIeX1Bundle extends L2CrossbarBundle {
|
||||
val xilinxvc707pcie = new XilinxVC707PCIeX1IO
|
||||
}
|
||||
|
||||
trait PeripheryXilinxVC707PCIeX1Module extends L2CrossbarModule {
|
||||
val outer: PeripheryXilinxVC707PCIeX1
|
||||
val io: PeripheryXilinxVC707PCIeX1Bundle
|
||||
|
||||
io.xilinxvc707pcie <> outer.xilinxvc707pcie.module.io.port
|
||||
}
|
Reference in New Issue
Block a user