--- /dev/null
+
+ 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.
--- /dev/null
+// 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)
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+ }
+
+}
--- /dev/null
+// 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)
--- /dev/null
+// 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
+
+}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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)
+ }
+ }
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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
+ }
+ }
+ }
+}
--- /dev/null
+// 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
+ }
+ }
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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:_*)
+ }
+}
--- /dev/null
+// 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:_*)
+ }
+}
--- /dev/null
+// 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)
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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))
+ }
+}
--- /dev/null
+// 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))
+
+}
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+// 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())
+ }
+}
--- /dev/null
+// 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
--- /dev/null
+// 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