1
0
Fork 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

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016 SiFive, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

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

22
vsrc/SRLatch.v Normal file
View File

@ -0,0 +1,22 @@
// See LICENSE for license details.
module SRLatch (
input set,
input reset,
output q
);
reg latch;
// synopsys async_set_reset "set"
// synopsys one_hot "set, reset"
always @(set or reset)
begin
if (set)
latch <= 1'b1;
else if (reset)
latch <= 1'b0;
end
assign q = latch;
endmodule

78
vsrc/vc707reset.v Normal file
View File

@ -0,0 +1,78 @@
// See LICENSE for license details.
`timescale 1ns/1ps
`default_nettype none
`define RESET_SYNC 4
`define DEBOUNCE_BITS 8
module vc707reset(
// Asynchronous reset input, should be held high until
// all clocks are locked and power is stable.
input wire areset,
// Clock domains are brought up in increasing order
// All clocks are reset for at least 2^DEBOUNCE_BITS * period(clock1)
input wire clock1,
output wire reset1,
input wire clock2,
output wire reset2,
input wire clock3,
output wire reset3,
input wire clock4,
output wire reset4
);
sifive_reset_hold hold_clock0(areset, clock1, reset1);
sifive_reset_sync sync_clock2(reset1, clock2, reset2);
sifive_reset_sync sync_clock3(reset2, clock3, reset3);
sifive_reset_sync sync_clock4(reset3, clock4, reset4);
endmodule
// Assumes that areset is held for more than one clock
// Allows areset to be deasserted asynchronously
module sifive_reset_sync(
input wire areset,
input wire clock,
output wire reset
);
reg [`RESET_SYNC-1:0] gen_reset = {`RESET_SYNC{1'b1}};
always @(posedge clock, posedge areset) begin
if (areset) begin
gen_reset <= {`RESET_SYNC{1'b1}};
end else begin
gen_reset <= {1'b0,gen_reset[`RESET_SYNC-1:1]};
end
end
assign reset = gen_reset[0];
endmodule
module sifive_reset_hold(
input wire areset,
input wire clock,
output wire reset
);
wire raw_reset;
reg [`RESET_SYNC-1:0] sync_reset = {`RESET_SYNC{1'b1}};
reg [`DEBOUNCE_BITS:0] debounce_reset = {`DEBOUNCE_BITS{1'b1}};
wire out_reset;
// Captures reset even if clock is not running
sifive_reset_sync capture(areset, clock, raw_reset);
// Remove any glitches due to runt areset
always @(posedge clock) begin
sync_reset <= {raw_reset,sync_reset[`RESET_SYNC-1:1]};
end
// Debounce the reset
assign out_reset = debounce_reset[`DEBOUNCE_BITS];
always @(posedge clock) begin
if (sync_reset[0]) begin
debounce_reset <= {(`DEBOUNCE_BITS+1){1'b1}};
end else begin
debounce_reset <= debounce_reset - out_reset;
end
end
assign reset = out_reset;
endmodule
`default_nettype wire