1
0

Initial commit.

This commit is contained in:
SiFive
2016-11-29 04:08:44 -08:00
commit 7916ef5249
42 changed files with 3763 additions and 0 deletions

View 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)

View 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
}

View 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
}

View 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
}
}

View 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)

View 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
}

View 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
}
}

View 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)
}
}

View 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
}

View 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)

View 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
}
}

View 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)
}
}
}

View 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()
}

View 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)
}

View 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)
}

View 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
}
}
}
}

View 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
}
}
}
}

View 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
}

View 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
}
}
}
}
}
}

View 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)
}

View 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
}

View 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:_*)
}
}

View 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:_*)
}
}

View 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)

View 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
}

View 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))
}

View 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
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -0,0 +1,18 @@
// See LICENSE for license details.
package sifive.blocks.ip.xilinx.ibufds_gte2
import Chisel._
//IP : xilinx unisim IBUFDS_GTE2
//Differential Signaling Input Buffer
//unparameterized
class IBUFDS_GTE2 extends BlackBox {
val io = new Bundle {
val O = Bool(OUTPUT)
val ODIV2 = Bool(OUTPUT)
val CEB = Bool(INPUT)
val I = Bool(INPUT)
val IB = Bool(INPUT)
}
}

View File

@ -0,0 +1,374 @@
// See LICENSE for license details.
package sifive.blocks.ip.xilinx.vc707axi_to_pcie_x1
import Chisel._
import config._
import diplomacy._
import uncore.axi4._
import junctions._
// IP VLNV: xilinx.com:customize_ip:vc707pcietoaxi:1.0
// Black Box
// Signals named _exactly_ as per Vivado generated verilog
// s : -{lock, cache, prot, qos}
trait VC707AXIToPCIeX1IOSerial extends Bundle {
//serial external pins
val pci_exp_txp = Bits(OUTPUT,1)
val pci_exp_txn = Bits(OUTPUT,1)
val pci_exp_rxp = Bits(INPUT,1)
val pci_exp_rxn = Bits(INPUT,1)
}
trait VC707AXIToPCIeX1IOClocksReset extends Bundle {
//clock, reset, control
val axi_aresetn = Bool(INPUT)
val axi_aclk_out = Clock(OUTPUT)
val axi_ctl_aclk_out = Clock(OUTPUT)
val mmcm_lock = Bool(OUTPUT)
}
//scalastyle:off
//turn off linter: blackbox name must match verilog module
class vc707axi_to_pcie_x1() extends BlackBox
{
val io = new Bundle with VC707AXIToPCIeX1IOSerial
with VC707AXIToPCIeX1IOClocksReset {
//refclk
val REFCLK = Bool(INPUT)
//clock, reset, control
val INTX_MSI_Request = Bool(INPUT)
val INTX_MSI_Grant = Bool(OUTPUT)
val MSI_enable = Bool(OUTPUT)
val MSI_Vector_Num = Bits(INPUT,5)
val MSI_Vector_Width = Bits(OUTPUT,3)
//interrupt
val interrupt_out = Bool(OUTPUT)
//axi slave
//-{lock, cache, prot, qos}
//slave interface write address
val s_axi_awid = Bits(INPUT,4)
val s_axi_awaddr = Bits(INPUT,32)
val s_axi_awregion = Bits(INPUT,4)
val s_axi_awlen = Bits(INPUT,8)
val s_axi_awsize = Bits(INPUT,3)
val s_axi_awburst = Bits(INPUT,2)
//val s_axi_awlock = Bool(INPUT)
//val s_axi_awcache = Bits(INPUT,4)
//val s_axi_awprot = Bits(INPUT,3)
//val s_axi_awqos = Bits(INPUT,4)
val s_axi_awvalid = Bool(INPUT)
val s_axi_awready = Bool(OUTPUT)
//slave interface write data
val s_axi_wdata = Bits(INPUT,64)
val s_axi_wstrb = Bits(INPUT,8)
val s_axi_wlast = Bool(INPUT)
val s_axi_wvalid = Bool(INPUT)
val s_axi_wready = Bool(OUTPUT)
//slave interface write response
val s_axi_bready = Bool(INPUT)
val s_axi_bid = Bits(OUTPUT,4)
val s_axi_bresp = Bits(OUTPUT,2)
val s_axi_bvalid = Bool(OUTPUT)
//slave interface read address
val s_axi_arid = Bits(INPUT,4)
val s_axi_araddr = Bits(INPUT,32)
val s_axi_arregion = Bits(INPUT,4)
val s_axi_arlen = Bits(INPUT,8)
val s_axi_arsize = Bits(INPUT,3)
val s_axi_arburst = Bits(INPUT,2)
//val s_axi_arlock = Bits(INPUT,1)
//val s_axi_arcache = Bits(INPUT,4)
//val s_axi_arprot = Bits(INPUT,3)
//val s_axi_arqos = Bits(INPUT,4)
val s_axi_arvalid = Bool(INPUT)
val s_axi_arready = Bool(OUTPUT)
//slave interface read data
val s_axi_rready = Bool(INPUT)
val s_axi_rid = Bits(OUTPUT,4)
val s_axi_rdata = Bits(OUTPUT,64)
val s_axi_rresp = Bits(OUTPUT,2)
val s_axi_rlast = Bool(OUTPUT)
val s_axi_rvalid = Bool(OUTPUT)
//axi master
//-{id,region,qos}
//slave interface write address ports
//val m_axi_awid = Bits(OUTPUT,4)
val m_axi_awaddr = Bits(OUTPUT,32)
//val m_axi_awregion = Bits(OUTPUT,4)
val m_axi_awlen = Bits(OUTPUT,8)
val m_axi_awsize = Bits(OUTPUT,3)
val m_axi_awburst = Bits(OUTPUT,2)
val m_axi_awlock = Bool(OUTPUT)
val m_axi_awcache = Bits(OUTPUT,4)
val m_axi_awprot = Bits(OUTPUT,3)
//val m_axi_awqos = Bits(OUTPUT,4)
val m_axi_awvalid = Bool(OUTPUT)
val m_axi_awready = Bool(INPUT)
//slave interface write data ports
val m_axi_wdata = Bits(OUTPUT,64)
val m_axi_wstrb = Bits(OUTPUT,8)
val m_axi_wlast = Bool(OUTPUT)
val m_axi_wvalid = Bool(OUTPUT)
val m_axi_wready = Bool(INPUT)
//slave interface write response ports
val m_axi_bready = Bool(OUTPUT)
//val m_axi_bid = Bits(INPUT,4)
val m_axi_bresp = Bits(INPUT,2)
val m_axi_bvalid = Bool(INPUT)
//slave interface read address ports
//val m_axi_arid = Bits(OUTPUT,4)
val m_axi_araddr = Bits(OUTPUT,32)
//val m_axi_arregion = Bits(OUTPUT,4)
val m_axi_arlen = Bits(OUTPUT,8)
val m_axi_arsize = Bits(OUTPUT,3)
val m_axi_arburst = Bits(OUTPUT,2)
val m_axi_arlock = Bits(OUTPUT,1)
val m_axi_arcache = Bits(OUTPUT,4)
val m_axi_arprot = Bits(OUTPUT,3)
//val m_axi_arqos = Bits(OUTPUT,4)
val m_axi_arvalid = Bool(OUTPUT)
val m_axi_arready = Bool(INPUT)
//slave interface read data ports
val m_axi_rready = Bool(OUTPUT)
//val m_axi_rid = Bits(INPUT,4)
val m_axi_rdata = Bits(INPUT,64)
val m_axi_rresp = Bits(INPUT,2)
val m_axi_rlast = Bool(INPUT)
val m_axi_rvalid = Bool(INPUT)
//axi lite slave for control
val s_axi_ctl_awaddr = Bits(INPUT,32)
val s_axi_ctl_awvalid = Bool(INPUT)
val s_axi_ctl_awready = Bool(OUTPUT)
val s_axi_ctl_wdata = Bits(INPUT,32)
val s_axi_ctl_wstrb = Bits(INPUT,4)
val s_axi_ctl_wvalid = Bool(INPUT)
val s_axi_ctl_wready = Bool(OUTPUT)
val s_axi_ctl_bresp = Bits(OUTPUT,2)
val s_axi_ctl_bvalid = Bool(OUTPUT)
val s_axi_ctl_bready = Bool(INPUT)
val s_axi_ctl_araddr = Bits(INPUT,32)
val s_axi_ctl_arvalid = Bool(INPUT)
val s_axi_ctl_arready = Bool(OUTPUT)
val s_axi_ctl_rdata = Bits(OUTPUT,32)
val s_axi_ctl_rresp = Bits(OUTPUT,2)
val s_axi_ctl_rvalid = Bool(OUTPUT)
val s_axi_ctl_rready = Bool(INPUT)
}
}
//scalastyle:off
//wrap vc707_axi_to_pcie_x1 black box in Nasti Bundles
class VC707AXIToPCIeX1(implicit p:Parameters) extends LazyModule
{
val slave = AXI4SlaveNode(AXI4SlavePortParameters(
slaves = Seq(AXI4SlaveParameters(
address = List(AddressSet(0x60000000L, 0x1fffffffL)),
executable = true,
supportsWrite = TransferSizes(1, 256),
supportsRead = TransferSizes(1, 256),
interleavedId = Some(0))), // the Xilinx IP is friendly
beatBytes = 8))
val control = AXI4SlaveNode(AXI4SlavePortParameters(
slaves = Seq(AXI4SlaveParameters(
address = List(AddressSet(0x50000000L, 0x03ffffffL)),
supportsWrite = TransferSizes(1, 4),
supportsRead = TransferSizes(1, 4),
interleavedId = Some(0))), // no read interleaving b/c AXI-lite
beatBytes = 4))
val master = AXI4MasterNode(AXI4MasterPortParameters(
masters = Seq(AXI4MasterParameters(
id = IdRange(0, 1),
aligned = false))))
lazy val module = new LazyModuleImp(this) {
// The master on the control port must be AXI-lite
require (control.edgesIn(0).master.endId == 1)
// Must have exactly the right number of idBits
require (slave.edgesIn(0).bundle.idBits == 4)
class VC707AXIToPCIeX1IOBundle extends Bundle with VC707AXIToPCIeX1IOSerial
with VC707AXIToPCIeX1IOClocksReset;
val io = new Bundle {
val port = new VC707AXIToPCIeX1IOBundle
val slave_in = slave.bundleIn
val control_in = control.bundleIn
val master_out = master.bundleOut
val REFCLK = Bool(INPUT)
val interrupt_out = Bool(OUTPUT)
}
val blackbox = Module(new vc707axi_to_pcie_x1)
val s = io.slave_in(0)
val c = io.control_in(0)
val m = io.master_out(0)
//to top level
blackbox.io.axi_aresetn := io.port.axi_aresetn
io.port.axi_aclk_out := blackbox.io.axi_aclk_out
io.port.axi_ctl_aclk_out := blackbox.io.axi_ctl_aclk_out
io.port.mmcm_lock := blackbox.io.mmcm_lock
io.port.pci_exp_txp := blackbox.io.pci_exp_txp
io.port.pci_exp_txn := blackbox.io.pci_exp_txn
blackbox.io.pci_exp_rxp := io.port.pci_exp_rxp
blackbox.io.pci_exp_rxn := io.port.pci_exp_rxn
io.interrupt_out := blackbox.io.interrupt_out
blackbox.io.REFCLK := io.REFCLK
//s
//AXI4 signals ordered as per AXI4 Specification (Release D) Section A.2
//-{lock, cache, prot, qos}
//-{aclk, aresetn, awuser, wid, wuser, buser, ruser}
//global signals
//aclk :=
//aresetn :=
//slave interface write address
blackbox.io.s_axi_awid := s.aw.bits.id
blackbox.io.s_axi_awaddr := s.aw.bits.addr
blackbox.io.s_axi_awlen := s.aw.bits.len
blackbox.io.s_axi_awsize := s.aw.bits.size
blackbox.io.s_axi_awburst := s.aw.bits.burst
//blackbox.io.s_axi_awlock := s.aw.bits.lock
//blackbox.io.s_axi_awcache := s.aw.bits.cache
//blackbox.io.s_axi_awprot := s.aw.bits.prot
//blackbox.io.s_axi_awqos := s.aw.bits.qos
blackbox.io.s_axi_awregion := UInt(0)
//blackbox.io.awuser := s.aw.bits.user
blackbox.io.s_axi_awvalid := s.aw.valid
s.aw.ready := blackbox.io.s_axi_awready
//slave interface write data ports
//blackbox.io.s_axi_wid := s.w.bits.id
blackbox.io.s_axi_wdata := s.w.bits.data
blackbox.io.s_axi_wstrb := s.w.bits.strb
blackbox.io.s_axi_wlast := s.w.bits.last
//blackbox.io.s_axi_wuser := s.w.bits.user
blackbox.io.s_axi_wvalid := s.w.valid
s.w.ready := blackbox.io.s_axi_wready
//slave interface write response
s.b.bits.id := blackbox.io.s_axi_bid
s.b.bits.resp := blackbox.io.s_axi_bresp
//s.b.bits.user := blackbox.io.s_axi_buser
s.b.valid := blackbox.io.s_axi_bvalid
blackbox.io.s_axi_bready := s.b.ready
//slave AXI interface read address ports
blackbox.io.s_axi_arid := s.ar.bits.id
blackbox.io.s_axi_araddr := s.ar.bits.addr
blackbox.io.s_axi_arlen := s.ar.bits.len
blackbox.io.s_axi_arsize := s.ar.bits.size
blackbox.io.s_axi_arburst := s.ar.bits.burst
//blackbox.io.s_axi_arlock := s.ar.bits.lock
//blackbox.io.s_axi_arcache := s.ar.bits.cache
//blackbox.io.s_axi_arprot := s.ar.bits.prot
//blackbox.io.s_axi_arqos := s.ar.bits.qos
blackbox.io.s_axi_arregion := UInt(0)
//blackbox.io.s_axi_aruser := s.ar.bits.user
blackbox.io.s_axi_arvalid := s.ar.valid
s.ar.ready := blackbox.io.s_axi_arready
//slave AXI interface read data ports
s.r.bits.id := blackbox.io.s_axi_rid
s.r.bits.data := blackbox.io.s_axi_rdata
s.r.bits.resp := blackbox.io.s_axi_rresp
s.r.bits.last := blackbox.io.s_axi_rlast
//s.r.bits.ruser := blackbox.io.s_axi_ruser
s.r.valid := blackbox.io.s_axi_rvalid
blackbox.io.s_axi_rready := s.r.ready
//ctl
//axi-lite slave interface write address
blackbox.io.s_axi_ctl_awaddr := c.aw.bits.addr
blackbox.io.s_axi_ctl_awvalid := c.aw.valid
c.aw.ready := blackbox.io.s_axi_ctl_awready
//axi-lite slave interface write data ports
blackbox.io.s_axi_ctl_wdata := c.w.bits.data
blackbox.io.s_axi_ctl_wstrb := c.w.bits.strb
blackbox.io.s_axi_ctl_wvalid := c.w.valid
c.w.ready := blackbox.io.s_axi_ctl_wready
//axi-lite slave interface write response
blackbox.io.s_axi_ctl_bready := c.b.ready
c.b.bits.id := UInt(0)
c.b.bits.resp := blackbox.io.s_axi_ctl_bresp
c.b.valid := blackbox.io.s_axi_ctl_bvalid
//axi-lite slave AXI interface read address ports
blackbox.io.s_axi_ctl_araddr := c.ar.bits.addr
blackbox.io.s_axi_ctl_arvalid := c.ar.valid
c.ar.ready := blackbox.io.s_axi_ctl_arready
//slave AXI interface read data ports
blackbox.io.s_axi_ctl_rready := c.r.ready
c.r.bits.id := UInt(0)
c.r.bits.data := blackbox.io.s_axi_ctl_rdata
c.r.bits.resp := blackbox.io.s_axi_ctl_rresp
c.r.bits.last := Bool(true)
c.r.valid := blackbox.io.s_axi_ctl_rvalid
//m
//AXI4 signals ordered per AXI4 Specification (Release D) Section A.2
//-{id,region,qos}
//-{aclk, aresetn, awuser, wid, wuser, buser, ruser}
//global signals
//aclk :=
//aresetn :=
//master interface write address
m.aw.bits.id := UInt(0)
m.aw.bits.addr := blackbox.io.m_axi_awaddr
m.aw.bits.len := blackbox.io.m_axi_awlen
m.aw.bits.size := blackbox.io.m_axi_awsize
m.aw.bits.burst := blackbox.io.m_axi_awburst
m.aw.bits.lock := blackbox.io.m_axi_awlock
m.aw.bits.cache := blackbox.io.m_axi_awcache
m.aw.bits.prot := blackbox.io.m_axi_awprot
m.aw.bits.qos := UInt(0)
//m.aw.bits.region := blackbox.io.m_axi_awregion
//m.aw.bits.user := blackbox.io.m_axi_awuser
m.aw.valid := blackbox.io.m_axi_awvalid
blackbox.io.m_axi_awready := m.aw.ready
//master interface write data ports
m.w.bits.data := blackbox.io.m_axi_wdata
m.w.bits.strb := blackbox.io.m_axi_wstrb
m.w.bits.last := blackbox.io.m_axi_wlast
//m.w.bits.user := blackbox.io.m_axi_wuser
m.w.valid := blackbox.io.m_axi_wvalid
blackbox.io.m_axi_wready := m.w.ready
//master interface write response
//blackbox.io.m_axi_bid := m.b.bits.id
blackbox.io.m_axi_bresp := m.b.bits.resp
//blackbox.io.m_axi_buser := m.b.bits.user
blackbox.io.m_axi_bvalid := m.b.valid
m.b.ready := blackbox.io.m_axi_bready
//master AXI interface read address ports
m.ar.bits.id := UInt(0)
m.ar.bits.addr := blackbox.io.m_axi_araddr
m.ar.bits.len := blackbox.io.m_axi_arlen
m.ar.bits.size := blackbox.io.m_axi_arsize
m.ar.bits.burst := blackbox.io.m_axi_arburst
m.ar.bits.lock := blackbox.io.m_axi_arlock
m.ar.bits.cache := blackbox.io.m_axi_arcache
m.ar.bits.prot := blackbox.io.m_axi_arprot
m.ar.bits.qos := UInt(0)
//m.ar.bits.region := blackbox.io.m_axi_arregion
//m.ar.bits.user := blackbox.io.s_axi_aruser
m.ar.valid := blackbox.io.m_axi_arvalid
blackbox.io.m_axi_arready := m.ar.ready
//master AXI interface read data ports
//blackbox.io.m_axi_rid := m.r.bits.id
blackbox.io.m_axi_rdata := m.r.bits.data
blackbox.io.m_axi_rresp := m.r.bits.resp
blackbox.io.m_axi_rlast := m.r.bits.last
//blackbox.io.s_axi_ruser := s.bits.ruser
blackbox.io.m_axi_rvalid := m.r.valid
m.r.ready := blackbox.io.m_axi_rready
}
}

View File

@ -0,0 +1,110 @@
// See LICENSE for license details.
package sifive.blocks.ip.xilinx.vc707mig
import Chisel._
import config._
import junctions._
// IP VLNV: xilinx.com:customize_ip:vc707mig:1.0
// Black Box
// Signals named _exactly_ as per MIG generated verilog
trait VC707MIGUnidirectionalIODDR extends Bundle {
//outputs
val ddr3_addr = Bits(OUTPUT,14)
val ddr3_ba = Bits(OUTPUT,3)
val ddr3_ras_n = Bool(OUTPUT)
val ddr3_cas_n = Bool(OUTPUT)
val ddr3_we_n = Bool(OUTPUT)
val ddr3_reset_n = Bool(OUTPUT)
val ddr3_ck_p = Bits(OUTPUT,1)
val ddr3_ck_n = Bits(OUTPUT,1)
val ddr3_cke = Bits(OUTPUT,1)
val ddr3_cs_n = Bits(OUTPUT,1)
val ddr3_dm = Bits(OUTPUT,8)
val ddr3_odt = Bits(OUTPUT,1)
}
//reused directly in io bundle for sifive.blocks.devices.xilinxvc707mig
trait VC707MIGUnidirectionalIOClocksReset extends Bundle {
//inputs
//differential system clocks
val sys_clk_n = Bool(INPUT)
val sys_clk_p = Bool(INPUT)
//user interface signals
val ui_clk = Clock(OUTPUT)
val ui_clk_sync_rst = Bool(OUTPUT)
val mmcm_locked = Bool(OUTPUT)
val aresetn = Bool(INPUT)
//misc
val init_calib_complete = Bool(OUTPUT)
val sys_rst = Bool(INPUT)
}
//scalastyle:off
//turn off linter: blackbox name must match verilog module
class vc707mig(implicit val p:Parameters) extends BlackBox
{
val io = new Bundle with VC707MIGUnidirectionalIODDR
with VC707MIGUnidirectionalIOClocksReset {
// bidirectional signals on blackbox interface
// defined here as an output so "__inout" signal name does not have to be used
// verilog does not check the
val ddr3_dq = Bits(OUTPUT,64)
val ddr3_dqs_n = Bits(OUTPUT,8)
val ddr3_dqs_p = Bits(OUTPUT,8)
// User interface signals
val app_sr_req = Bool(INPUT)
val app_ref_req = Bool(INPUT)
val app_zq_req = Bool(INPUT)
val app_sr_active = Bool(OUTPUT)
val app_ref_ack = Bool(OUTPUT)
val app_zq_ack = Bool(OUTPUT)
//axi_s
//slave interface write address ports
val s_axi_awid = Bits(INPUT,4)
val s_axi_awaddr = Bits(INPUT,30)
val s_axi_awlen = Bits(INPUT,8)
val s_axi_awsize = Bits(INPUT,3)
val s_axi_awburst = Bits(INPUT,2)
val s_axi_awlock = Bits(INPUT,1)
val s_axi_awcache = Bits(INPUT,4)
val s_axi_awprot = Bits(INPUT,3)
val s_axi_awqos = Bits(INPUT,4)
val s_axi_awvalid = Bool(INPUT)
val s_axi_awready = Bool(OUTPUT)
//slave interface write data ports
val s_axi_wdata = Bits(INPUT,64)
val s_axi_wstrb = Bits(INPUT,8)
val s_axi_wlast = Bool(INPUT)
val s_axi_wvalid = Bool(INPUT)
val s_axi_wready = Bool(OUTPUT)
//slave interface write response ports
val s_axi_bready = Bool(INPUT)
val s_axi_bid = Bits(OUTPUT,4)
val s_axi_bresp = Bits(OUTPUT,2)
val s_axi_bvalid = Bool(OUTPUT)
//slave interface read address ports
val s_axi_arid = Bits(INPUT,4)
val s_axi_araddr = Bits(INPUT,30)
val s_axi_arlen = Bits(INPUT,8)
val s_axi_arsize = Bits(INPUT,3)
val s_axi_arburst = Bits(INPUT,2)
val s_axi_arlock = Bits(INPUT,1)
val s_axi_arcache = Bits(INPUT,4)
val s_axi_arprot = Bits(INPUT,3)
val s_axi_arqos = Bits(INPUT,4)
val s_axi_arvalid = Bool(INPUT)
val s_axi_arready = Bool(OUTPUT)
//slave interface read data ports
val s_axi_rready = Bool(INPUT)
val s_axi_rid = Bits(OUTPUT,4)
val s_axi_rdata = Bits(OUTPUT,64)
val s_axi_rresp = Bits(OUTPUT,2)
val s_axi_rlast = Bool(OUTPUT)
val s_axi_rvalid = Bool(OUTPUT)
//misc
val device_temp = Bits(OUTPUT,12)
}
}
//scalastyle:on

View File

@ -0,0 +1,28 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
//Allows us to specify a different clock for a shift register
// and to force input to be high for > 1 cycle.
class DeglitchShiftRegister(shift: Int) extends Module {
val io = new Bundle {
val d = Bool(INPUT)
val q = Bool(OUTPUT)
}
val sync = ShiftRegister(io.d, shift)
val last = ShiftRegister(sync, 1)
io.q := sync & last
}
object DeglitchShiftRegister {
def apply (shift: Int, d: Bool, clock: Clock,
name: Option[String] = None): Bool = {
val deglitch = Module (new DeglitchShiftRegister(shift))
name.foreach(deglitch.suggestName(_))
deglitch.clock := clock
deglitch.reset := Bool(false)
deglitch.io.d := d
deglitch.io.q
}
}

View File

@ -0,0 +1,41 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
import regmapper._
// MSB indicates full status
object NonBlockingEnqueue {
def apply(enq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
val enqWidth = enq.bits.getWidth
require(enqWidth > 0)
require(regWidth > enqWidth)
Seq(
RegField(enqWidth,
RegReadFn(UInt(0)),
RegWriteFn((valid, data) => {
enq.valid := valid
enq.bits := data
Bool(true)
})),
RegField(regWidth - enqWidth - 1),
RegField.r(1, !enq.ready))
}
}
// MSB indicates empty status
object NonBlockingDequeue {
def apply(deq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
val deqWidth = deq.bits.getWidth
require(deqWidth > 0)
require(regWidth > deqWidth)
Seq(
RegField.r(deqWidth,
RegReadFn(ready => {
deq.ready := ready
(Bool(true), deq.bits)
})),
RegField(regWidth - deqWidth - 1),
RegField.r(1, !deq.valid))
}
}

View File

@ -0,0 +1,42 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
import util.AsyncResetRegVec
/** Reset: asynchronous assert,
* synchronous de-assert
*
*/
class ResetCatchAndSync (sync: Int = 3) extends Module {
val io = new Bundle {
val sync_reset = Bool(OUTPUT)
}
val reset_n_catch_reg = Module (new AsyncResetRegVec(sync, 0))
reset_n_catch_reg.io.en := Bool(true)
reset_n_catch_reg.io.d := Cat(Bool(true), reset_n_catch_reg.io.q >> 1)
io.sync_reset := ~reset_n_catch_reg.io.q(0)
}
object ResetCatchAndSync {
def apply(clk: Clock, rst: Bool, sync: Int = 3, name: Option[String] = None): Bool = {
val catcher = Module (new ResetCatchAndSync(sync))
if (name.isDefined) {catcher.suggestName(name.get)}
catcher.clock := clk
catcher.reset := rst
catcher.io.sync_reset
}
def apply(clk: Clock, rst: Bool, sync: Int, name: String): Bool = apply(clk, rst, sync, Some(name))
def apply(clk: Clock, rst: Bool, name: String): Bool = apply(clk, rst, name = Some(name))
}

View File

@ -0,0 +1,12 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
class SRLatch extends BlackBox {
val io = new Bundle {
val set = Bool(INPUT)
val reset = Bool(INPUT)
val q = Bool(OUTPUT)
}
}

View File

@ -0,0 +1,11 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
object ShiftRegisterInit {
def apply[T <: Data](in: T, n: Int, init: T): T =
(0 until n).foldLeft(in) {
case (next, _) => Reg(next, next = next, init = init)
}
}

View File

@ -0,0 +1,104 @@
// See LICENSE for license details.
package sifive.blocks.util
import Chisel._
import Chisel.ImplicitConversions._
import regmapper._
import util.WideCounter
class SlaveRegIF(w: Int) extends Bundle {
val write = Valid(UInt(width = w)).flip
val read = UInt(OUTPUT, w)
override def cloneType: this.type = new SlaveRegIF(w).asInstanceOf[this.type]
def toRegField(dummy: Int = 0): RegField = {
def writeFn(valid: Bool, data: UInt): Bool = {
write.valid := valid
write.bits := data
Bool(true)
}
RegField(w, RegReadFn(read), RegWriteFn((v, d) => writeFn(v, d)))
}
}
abstract class GenericTimer extends Module {
protected def countWidth: Int
protected def cmpWidth: Int
protected def ncmp: Int
protected def countAlways: Bool
protected def countEn: Bool
protected def feed: Bool
protected def ip: UInt
protected def countAwake: Bool = Bool(false)
protected def unlocked: Bool = Bool(true)
protected def rsten: Bool = Bool(false)
protected def deglitch: Bool = Bool(false)
protected def sticky: Bool = Bool(false)
protected def oneShot: Bool = Bool(false)
protected def center: UInt = UInt(0)
protected def gang: UInt = UInt(0)
protected val scaleWidth = 4
protected val regWidth = 32
val maxcmp = 4
require(ncmp <= maxcmp)
class GenericTimerIO extends Bundle {
val regs = new Bundle {
val cfg = new SlaveRegIF(regWidth)
val countLo = new SlaveRegIF(regWidth)
val countHi = new SlaveRegIF(regWidth)
val s = new SlaveRegIF(cmpWidth)
val cmp = Vec(ncmp, new SlaveRegIF(cmpWidth))
val feed = new SlaveRegIF(regWidth)
val key = new SlaveRegIF(regWidth)
}
val ip = Vec(ncmp, Bool()).asOutput
}
def io: GenericTimerIO
protected val scale = RegEnable(io.regs.cfg.write.bits(scaleWidth-1, 0), io.regs.cfg.write.valid && unlocked)
protected lazy val zerocmp = RegEnable(io.regs.cfg.write.bits(9), io.regs.cfg.write.valid && unlocked)
protected val cmp = io.regs.cmp.map(c => RegEnable(c.write.bits, c.write.valid && unlocked))
protected val count = WideCounter(countWidth, countEn, reset = false)
when (io.regs.countLo.write.valid && unlocked) { count := Cat(count >> regWidth, io.regs.countLo.write.bits) }
if (countWidth > regWidth) when (io.regs.countHi.write.valid && unlocked) { count := Cat(io.regs.countHi.write.bits, count(regWidth-1, 0)) }
// generate periodic interrupt
protected val s = (count >> scale)(cmpWidth-1, 0)
// reset counter when fed or elapsed
protected val elapsed =
for (i <- 0 until ncmp)
yield Mux(s(cmpWidth-1) && center(i), ~s, s) >= cmp(i)
protected val countReset = feed || (zerocmp && elapsed(0))
when (countReset) { count := 0 }
io.regs.cfg.read := Cat(ip, gang | UInt(0, maxcmp), UInt(0, maxcmp), center | UInt(0, maxcmp),
UInt(0, 2), countAwake || oneShot, countAlways, UInt(0, 1), deglitch, zerocmp, rsten || sticky, UInt(0, 8-scaleWidth), scale)
io.regs.countLo.read := count
io.regs.countHi.read := count >> regWidth
io.regs.s.read := s
(io.regs.cmp zip cmp) map { case (r, c) => r.read := c }
io.regs.feed.read := 0
io.regs.key.read := unlocked
io.ip := io.ip.fromBits(ip)
}
object GenericTimer {
def timerRegMap(t: GenericTimer, offset: Int, regBytes: Int): Seq[(Int, Seq[RegField])] = {
val regs = Seq(
0 -> t.io.regs.cfg,
2 -> t.io.regs.countLo,
3 -> t.io.regs.countHi,
4 -> t.io.regs.s,
6 -> t.io.regs.feed,
7 -> t.io.regs.key)
val cmpRegs = t.io.regs.cmp.zipWithIndex map { case (r, i) => (8 + i) -> r }
for ((i, r) <- (regs ++ cmpRegs))
yield (offset + regBytes*i) -> Seq(r.toRegField())
}
}