Initial commit.
authorSiFive <>
Tue, 29 Nov 2016 12:08:44 +0000 (04:08 -0800)
committerSiFive <>
Tue, 29 Nov 2016 12:08:44 +0000 (04:08 -0800)
42 files changed:
LICENSE [new file with mode: 0644]
src/main/scala/devices/gpio/GPIO.scala [new file with mode: 0644]
src/main/scala/devices/gpio/GPIOCtrlRegs.scala [new file with mode: 0644]
src/main/scala/devices/gpio/GPIOPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/gpio/JTAG.scala [new file with mode: 0644]
src/main/scala/devices/mockaon/MockAON.scala [new file with mode: 0644]
src/main/scala/devices/mockaon/MockAONPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/mockaon/MockAONWrapper.scala [new file with mode: 0644]
src/main/scala/devices/mockaon/PMU.scala [new file with mode: 0644]
src/main/scala/devices/mockaon/WatchdogTimer.scala [new file with mode: 0644]
src/main/scala/devices/pwm/PWM.scala [new file with mode: 0644]
src/main/scala/devices/pwm/PWMPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIArbiter.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIBundle.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIConsts.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIFIFO.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIFlash.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIMedia.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIPhysical.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIPins.scala [new file with mode: 0644]
src/main/scala/devices/spi/SPIRegs.scala [new file with mode: 0644]
src/main/scala/devices/spi/TLSPI.scala [new file with mode: 0644]
src/main/scala/devices/spi/TLSPIFlash.scala [new file with mode: 0644]
src/main/scala/devices/uart/UART.scala [new file with mode: 0644]
src/main/scala/devices/uart/UARTCtrlRegs.scala [new file with mode: 0644]
src/main/scala/devices/uart/UARTPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/xilinxvc707mig/XilinxVC707MIG.scala [new file with mode: 0644]
src/main/scala/devices/xilinxvc707mig/XilinxVC707MIGPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1.scala [new file with mode: 0644]
src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala [new file with mode: 0644]
src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala [new file with mode: 0644]
src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala [new file with mode: 0644]
src/main/scala/ip/xilinx/vc707mig/vc707mig.scala [new file with mode: 0644]
src/main/scala/util/DeglitchShiftRegister.scala [new file with mode: 0644]
src/main/scala/util/RegMapFIFO.scala [new file with mode: 0644]
src/main/scala/util/ResetCatchAndSync.scala [new file with mode: 0644]
src/main/scala/util/SRLatch.scala [new file with mode: 0644]
src/main/scala/util/ShiftReg.scala [new file with mode: 0644]
src/main/scala/util/Timer.scala [new file with mode: 0644]
vsrc/SRLatch.v [new file with mode: 0644]
vsrc/vc707reset.v [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..56daab2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2016 SiFive, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/src/main/scala/devices/gpio/GPIO.scala b/src/main/scala/devices/gpio/GPIO.scala
new file mode 100644 (file)
index 0000000..73ba3d0
--- /dev/null
@@ -0,0 +1,295 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.gpio
+
+import Chisel._
+import config._
+import regmapper._
+import uncore.tilelink2._
+import rocketchip.PeripheryBusConfig
+import util.AsyncResetRegVec
+
+case class GPIOConfig(address: BigInt, width: Int)
+
+trait HasGPIOParameters {
+  val params: Tuple2[Parameters, GPIOConfig]
+  implicit val p = params._1
+  val c = params._2
+}
+
+// YAGNI: Make the PUE, DS, and
+// these also optionally HW controllable.
+// This is the base class of things you "always"
+// want to control from a HW block.
+class GPIOCtrl extends Bundle {
+  val oval = Bool()
+  val oe   = Bool()
+  val ie   = Bool()
+}
+
+// This is the actual IOF interface.
+// Add a valid bit to indicate whether
+// there is something actually connected
+// to this.
+class GPIOPinIOFCtrl extends GPIOCtrl {
+  val valid = Bool()
+}
+
+// By default,
+object GPIOPinIOFCtrl {
+  def apply(): GPIOPinIOFCtrl = {
+    val iof = Wire(new GPIOPinIOFCtrl())
+    iof.valid := Bool(false)
+    iof.oval  := Bool(false)
+    iof.oe    := Bool(false)
+    iof.ie    := Bool(false)
+    iof
+  }
+}
+
+// This is the control for a physical
+// Pad.
+
+class GPIOPinCtrl extends GPIOCtrl {
+  val pue  = Bool() // Pull-up Enable
+  val ds   = Bool() // Drive Strength
+}
+
+object GPIOPinCtrl {
+  def apply(): GPIOPinCtrl = {
+    val pin = Wire(new GPIOPinCtrl())
+    pin.oval := Bool(false)
+    pin.oe   := Bool(false)
+    pin.pue  := Bool(false)
+    pin.ds   := Bool(false)
+    pin.ie   := Bool(false)
+    pin
+  }
+}
+
+// Package up the inputs and outputs
+// for the IOF
+class GPIOPinIOF extends Bundle {
+  val i = new Bundle {
+    val ival = Bool(INPUT)
+  }
+  val o = new GPIOPinIOFCtrl().asOutput
+}
+
+// Connect both the i and o side of the pin,
+// and drive the valid signal for the IOF.
+object GPIOPinToIOF {
+
+  def apply (pin: GPIOPin, iof: GPIOPinIOF): Unit = {
+    iof <> pin
+    iof.o.valid := Bool(true)
+  }
+
+}
+
+// Package up the inputs and outputs
+// for the Pin
+class GPIOPin extends Bundle {
+  val i = new Bundle {
+    val ival = Bool(INPUT)
+  }
+  val o = new GPIOPinCtrl().asOutput
+}
+
+// This is sort of weird because
+// the IOF end up at the RocketChipTop
+// level, and we have to do the pinmux
+// outside of RocketChipTop.
+
+class GPIOPortIO(c: GPIOConfig) extends Bundle {
+  val pins = Vec(c.width, new GPIOPin)
+  val iof_0 = Vec(c.width, new GPIOPinIOF).flip
+  val iof_1 = Vec(c.width, new GPIOPinIOF).flip
+}
+
+// It would be better if the IOF were here and
+// we could do the pinmux inside.
+trait GPIOBundle extends Bundle with HasGPIOParameters {
+  val port = new GPIOPortIO(c)
+}
+
+trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
+  val io: GPIOBundle
+
+  //--------------------------------------------------
+  // CSR Declarations
+  // -------------------------------------------------
+
+  // SW Control only.
+  val portReg = Reg(init = UInt(0, c.width))
+
+  val oeReg  = Module(new AsyncResetRegVec(c.width, 0))
+  val pueReg = Module(new AsyncResetRegVec(c.width, 0))
+  val dsReg  = Reg(init = UInt(0, c.width))
+  val ieReg  = Module(new AsyncResetRegVec(c.width, 0))
+
+  // Synchronize Input to get valueReg
+  val inVal = Wire(UInt(0, width=c.width))
+  inVal := Vec(io.port.pins.map(_.i.ival)).asUInt
+  val inSyncReg  = ShiftRegister(inVal, 3)
+  val valueReg   = Reg(init = UInt(0, c.width), next = inSyncReg)
+
+  // Interrupt Configuration
+  val highIeReg = Reg(init = UInt(0, c.width))
+  val lowIeReg  = Reg(init = UInt(0, c.width))
+  val riseIeReg = Reg(init = UInt(0, c.width))
+  val fallIeReg = Reg(init = UInt(0, c.width))
+  val highIpReg = Reg(init = UInt(0, c.width))
+  val lowIpReg  = Reg(init = UInt(0, c.width))
+  val riseIpReg = Reg(init = UInt(0, c.width))
+  val fallIpReg = Reg(init = UInt(0, c.width))
+
+  // HW IO Function
+  val iofEnReg  = Module(new AsyncResetRegVec(c.width, 0))
+  val iofSelReg = Reg(init = UInt(0, c.width))
+
+  // Invert Output
+  val xorReg    = Reg(init = UInt(0, c.width))
+
+  //--------------------------------------------------
+  // CSR Access Logic (most of this section is boilerplate)
+  // -------------------------------------------------
+
+  val rise = ~valueReg & inSyncReg;
+  val fall = valueReg & ~inSyncReg;
+
+  // Note that these are out of order.
+  regmap(
+    GPIOCtrlRegs.value     -> Seq(RegField.r(c.width, valueReg)),
+    GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io)),
+    GPIOCtrlRegs.rise_ie   -> Seq(RegField(c.width, riseIeReg)),
+    GPIOCtrlRegs.rise_ip   -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise)),
+    GPIOCtrlRegs.fall_ie   -> Seq(RegField(c.width, fallIeReg)),
+    GPIOCtrlRegs.fall_ip   -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall)),
+    GPIOCtrlRegs.high_ie   -> Seq(RegField(c.width, highIeReg)),
+    GPIOCtrlRegs.high_ip   -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg)),
+    GPIOCtrlRegs.low_ie    -> Seq(RegField(c.width, lowIeReg)),
+    GPIOCtrlRegs.low_ip    -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
+    GPIOCtrlRegs.port      -> Seq(RegField(c.width, portReg)),
+    GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
+    GPIOCtrlRegs.iof_en    -> Seq(RegField.rwReg(c.width, iofEnReg.io)),
+    GPIOCtrlRegs.iof_sel   -> Seq(RegField(c.width, iofSelReg)),
+    GPIOCtrlRegs.drive     -> Seq(RegField(c.width, dsReg)),
+    GPIOCtrlRegs.input_en  -> Seq(RegField.rwReg(c.width, ieReg.io)),
+    GPIOCtrlRegs.out_xor   -> Seq(RegField(c.width, xorReg))
+
+  )
+
+  //--------------------------------------------------
+  // Actual Pinmux
+  // -------------------------------------------------
+
+  val swPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+
+  // This strips off the valid.
+  val iof0Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
+  val iof1Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
+
+  val iofCtrl = Wire(Vec(c.width, new GPIOCtrl()))
+  val iofPlusSwPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+
+
+  for (pin <- 0 until c.width) {
+
+    // Software Pin Control
+    swPinCtrl(pin).pue    := pueReg.io.q(pin)
+    swPinCtrl(pin).oval   := portReg(pin)
+    swPinCtrl(pin).oe     := oeReg.io.q(pin)
+    swPinCtrl(pin).ds     := dsReg(pin)
+    swPinCtrl(pin).ie     := ieReg.io.q(pin)
+
+    // Allow SW Override for invalid inputs.
+    iof0Ctrl(pin)      <> swPinCtrl(pin)
+    when (io.port.iof_0(pin).o.valid) {
+      iof0Ctrl(pin)    <> io.port.iof_0(pin).o
+    }
+
+    iof1Ctrl(pin)      <> swPinCtrl(pin)
+    when (io.port.iof_1(pin).o.valid) {
+      iof1Ctrl(pin)    <> io.port.iof_1(pin).o
+    }
+
+    // Select IOF 0 vs. IOF 1.
+    iofCtrl(pin)       <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
+
+    // Allow SW Override for things IOF doesn't control.
+    iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
+    iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
+
+    // Final XOR & Pin Control
+    val pre_xor: GPIOPinCtrl = Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
+    io.port.pins(pin).o      := pre_xor
+    io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
+
+    // Generate Interrupts
+    interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) |
+                         (fallIpReg(pin) & fallIeReg(pin)) |
+                         (highIpReg(pin) & highIeReg(pin)) |
+                         (lowIpReg(pin) & lowIeReg(pin))
+
+    // Send Value to all consumers
+    io.port.iof_0(pin).i.ival := inSyncReg(pin)
+    io.port.iof_1(pin).i.ival := inSyncReg(pin)
+  }
+}
+
+object GPIOOutputPinCtrl {
+
+  def apply( pin: GPIOPin, signal: Bool,
+    pue: Bool = Bool(false),
+    ds:  Bool = Bool(false),
+    ie:  Bool = Bool(false)
+  ): Unit = {
+    pin.o.oval := signal
+    pin.o.oe   := Bool(true)
+    pin.o.pue  := pue
+    pin.o.ds   := ds
+    pin.o.ie   := ie
+  }
+
+  def apply(pins: Vec[GPIOPin], signals: Bits,
+    pue: Bool, ds:  Bool, ie:  Bool
+  ): Unit = {
+    for ((signal, pin) <- (signals.toBools zip pins)) {
+      apply(pin, signal, pue, ds, ie)
+    }
+  }
+
+  def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
+    Bool(false), Bool(false), Bool(false))
+
+}
+
+object GPIOInputPinCtrl {
+
+  def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
+    pin.o.oval := Bool(false)
+    pin.o.oe   := Bool(false)
+    pin.o.pue  := pue
+    pin.o.ds   := Bool(false)
+    pin.o.ie   := Bool(true)
+
+    pin.i.ival
+  }
+
+  def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
+    val signals = Wire(Vec.fill(pins.size)(Bool(false)))
+    for ((signal, pin) <- (signals zip pins)) {
+      signal := GPIOInputPinCtrl(pin, pue)
+    }
+    signals
+  }
+
+  def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
+
+}
+
+// Magic TL2 Incantation to create a TL2 Slave
+class TLGPIO(p: Parameters, c: GPIOConfig)
+  extends TLRegisterRouter(c.address, interrupts = c.width, beatBytes = p(PeripheryBusConfig).beatBytes)(
+  new TLRegBundle(Tuple2(p, c), _)    with GPIOBundle)(
+  new TLRegModule(Tuple2(p, c), _, _) with GPIOModule)
diff --git a/src/main/scala/devices/gpio/GPIOCtrlRegs.scala b/src/main/scala/devices/gpio/GPIOCtrlRegs.scala
new file mode 100644 (file)
index 0000000..fda6e88
--- /dev/null
@@ -0,0 +1,22 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.gpio
+
+object GPIOCtrlRegs {
+  val value       = 0x00
+  val input_en    = 0x04
+  val output_en   = 0x08
+  val port        = 0x0c
+  val pullup_en   = 0x10
+  val drive       = 0x14
+  val rise_ie     = 0x18
+  val rise_ip     = 0x1c
+  val fall_ie     = 0x20
+  val fall_ip     = 0x24
+  val high_ie     = 0x28
+  val high_ip     = 0x2c
+  val low_ie      = 0x30
+  val low_ip      = 0x34
+  val iof_en      = 0x38
+  val iof_sel     = 0x3c
+  val out_xor     = 0x40
+}
diff --git a/src/main/scala/devices/gpio/GPIOPeriphery.scala b/src/main/scala/devices/gpio/GPIOPeriphery.scala
new file mode 100644 (file)
index 0000000..414e713
--- /dev/null
@@ -0,0 +1,28 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.gpio
+
+import Chisel._
+import diplomacy.LazyModule
+import rocketchip.{TopNetwork,TopNetworkModule}
+import uncore.tilelink2.TLFragmenter
+
+trait PeripheryGPIO {
+  this: TopNetwork { val gpioConfig: GPIOConfig } =>
+  val gpio = LazyModule(new TLGPIO(p, gpioConfig))
+  gpio.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+  intBus.intnode := gpio.intnode
+}
+
+trait PeripheryGPIOBundle {
+  this: { val gpioConfig: GPIOConfig } =>
+  val gpio = new GPIOPortIO(gpioConfig)
+}
+
+trait PeripheryGPIOModule {
+  this: TopNetworkModule {
+    val gpioConfig: GPIOConfig
+    val outer: PeripheryGPIO
+    val io: PeripheryGPIOBundle
+  } =>
+  io.gpio <> outer.gpio.module.io.port
+}
diff --git a/src/main/scala/devices/gpio/JTAG.scala b/src/main/scala/devices/gpio/JTAG.scala
new file mode 100644 (file)
index 0000000..8734539
--- /dev/null
@@ -0,0 +1,43 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.gpio
+
+import Chisel._
+
+// ------------------------------------------------------------
+// SPI, UART, etc are with their
+// respective packages,
+// This file is for those that don't seem to have a good place
+// to put them otherwise.
+// ------------------------------------------------------------
+
+import config._
+import junctions.{JTAGIO}
+
+class JTAGPinsIO extends Bundle {
+
+  val TCK    = new GPIOPin()
+  val TMS    = new GPIOPin()
+  val TDI    = new GPIOPin()
+  val TDO    = new GPIOPin()
+  val TRST_n = new GPIOPin()
+
+}
+
+class JTAGGPIOPort(drvTdo: Boolean = false)(implicit p: Parameters) extends Module {
+
+  val io = new Bundle {
+    val jtag = new JTAGIO(drvTdo)
+    val pins = new JTAGPinsIO()
+  }
+
+  io.jtag.TCK  := GPIOInputPinCtrl(io.pins.TCK, pue = Bool(true)).asClock
+  io.jtag.TMS  := GPIOInputPinCtrl(io.pins.TMS, pue = Bool(true))
+  io.jtag.TDI  := GPIOInputPinCtrl(io.pins.TDI, pue = Bool(true))
+  io.jtag.TRST := ~GPIOInputPinCtrl(io.pins.TRST_n, pue = Bool(true))
+
+  GPIOOutputPinCtrl(io.pins.TDO, io.jtag.TDO)
+  if (drvTdo) {
+    io.pins.TDO.o.oe := io.jtag.DRV_TDO.get
+  }
+
+}
diff --git a/src/main/scala/devices/mockaon/MockAON.scala b/src/main/scala/devices/mockaon/MockAON.scala
new file mode 100644 (file)
index 0000000..914a92c
--- /dev/null
@@ -0,0 +1,105 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.mockaon
+
+import Chisel._
+import config._
+import regmapper._
+import uncore.tilelink2._
+import rocketchip.PeripheryBusConfig
+
+import sifive.blocks.util.GenericTimer
+
+case class MockAONConfig(
+  address: BigInt = BigInt(0x10000000),
+  nBackupRegs: Int = 16) {
+  def size: Int = 0x1000
+  def regBytes: Int = 4
+  def wdogOffset: Int = 0
+  def rtcOffset: Int = 0x40
+  def backupRegOffset: Int = 0x80
+  def pmuOffset: Int = 0x100
+}
+
+trait HasMockAONParameters {
+  val params: (MockAONConfig, Parameters)
+  val c = params._1
+  implicit val p = params._2
+}
+
+class MockAONPMUIO extends Bundle {
+  val vddpaden = Bool(OUTPUT)
+  val dwakeup = Bool(INPUT)
+}
+
+class MockAONMOffRstIO extends Bundle {
+  val hfclkrst = Bool(OUTPUT)
+  val corerst = Bool(OUTPUT)
+}
+
+trait MockAONBundle extends Bundle with HasMockAONParameters {
+
+  // Output of the Power Management Sequencer
+  val moff = new MockAONMOffRstIO ()
+
+  // This goes out to wrapper
+  // to be combined to create aon_rst.
+  val wdog_rst = Bool(OUTPUT)
+
+  // This goes out to wrapper
+  // and comes back as our clk
+  val lfclk = Clock(OUTPUT)
+
+  val pmu = new MockAONPMUIO
+
+  val lfextclk = Clock(INPUT)
+
+  val resetCauses = new ResetCauses().asInput
+}
+
+trait MockAONModule extends Module with HasRegMap with HasMockAONParameters {
+  val io: MockAONBundle
+
+  // the expectation here is that Chisel's implicit reset is aonrst,
+  // which is asynchronous, so don't use synchronous-reset registers.
+
+  val rtc = Module(new RTC)
+
+  val pmu = Module(new PMU(new DevKitPMUConfig))
+  io.moff <> pmu.io.control
+  io.pmu.vddpaden := pmu.io.control.vddpaden
+  pmu.io.wakeup.dwakeup := io.pmu.dwakeup
+  pmu.io.wakeup.awakeup := Bool(false)
+  pmu.io.wakeup.rtc := rtc.io.ip(0)
+  pmu.io.resetCauses := io.resetCauses
+  val pmuRegMap = {
+    val regs = pmu.io.regs.wakeupProgram ++ pmu.io.regs.sleepProgram ++
+      Seq(pmu.io.regs.ie, pmu.io.regs.cause, pmu.io.regs.sleep, pmu.io.regs.key)
+    for ((r, i) <- regs.zipWithIndex)
+      yield (c.pmuOffset + c.regBytes*i) -> Seq(r.toRegField())
+  }
+  interrupts(1) := rtc.io.ip(0)
+
+  val wdog = Module(new WatchdogTimer)
+  io.wdog_rst := wdog.io.rst
+  wdog.io.corerst := pmu.io.control.corerst
+  interrupts(0) := wdog.io.ip(0)
+
+  // If there are multiple lfclks to choose from, we can mux them here.
+  io.lfclk := io.lfextclk
+
+  val backupRegs = Seq.fill(c.nBackupRegs)(Reg(UInt(width = c.regBytes * 8)))
+  val backupRegMap =
+    for ((reg, i) <- backupRegs.zipWithIndex)
+      yield (c.backupRegOffset + c.regBytes*i) -> Seq(RegField(reg.getWidth, RegReadFn(reg), RegWriteFn(reg)))
+
+  regmap((backupRegMap ++
+    GenericTimer.timerRegMap(wdog, c.wdogOffset, c.regBytes) ++
+    GenericTimer.timerRegMap(rtc, c.rtcOffset, c.regBytes) ++
+    pmuRegMap):_*)
+
+}
+
+class MockAON(c: MockAONConfig)(implicit val p: Parameters)
+  extends TLRegisterRouter(c.address, interrupts = 2, size = c.size, beatBytes = p(PeripheryBusConfig).beatBytes, concurrency = 1)(
+  new TLRegBundle((c, p), _)    with MockAONBundle)(
+  new TLRegModule((c, p), _, _) with MockAONModule)
diff --git a/src/main/scala/devices/mockaon/MockAONPeriphery.scala b/src/main/scala/devices/mockaon/MockAONPeriphery.scala
new file mode 100644 (file)
index 0000000..870ba2e
--- /dev/null
@@ -0,0 +1,42 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.mockaon
+
+import Chisel._
+import diplomacy.LazyModule
+import rocketchip.{TopNetwork,TopNetworkModule}
+import uncore.tilelink2.{IntXing, TLAsyncCrossingSource, TLFragmenter}
+import coreplex._
+
+trait PeripheryMockAON extends TopNetwork {
+  val mockAONConfig: MockAONConfig
+  val coreplex: CoreplexRISCVPlatform
+
+  // We override the clock & Reset here so that all synchronizers, etc
+  // are in the proper clock domain.
+  val aon = LazyModule(new MockAONWrapper(mockAONConfig))
+  val aon_int = LazyModule(new IntXing)
+  aon.node := TLAsyncCrossingSource()(TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node))
+  aon_int.intnode := aon.intnode
+  intBus.intnode := aon_int.intnode
+}
+
+trait PeripheryMockAONBundle {
+  val aon = new MockAONWrapperBundle()
+}
+
+trait PeripheryMockAONModule {
+  this: TopNetworkModule {
+    val outer: PeripheryMockAON
+    val io: PeripheryMockAONBundle
+  } =>
+
+  io.aon <> outer.aon.module.io
+
+  // Explicit clock & reset are unused in MockAONWrapper.
+  // Tie  to check this assumption.
+  outer.aon.module.clock := Bool(false).asClock
+  outer.aon.module.reset := Bool(true)
+
+  outer.coreplex.module.io.rtcToggle := outer.aon.module.io.rtc.asUInt.toBool
+
+}
diff --git a/src/main/scala/devices/mockaon/MockAONWrapper.scala b/src/main/scala/devices/mockaon/MockAONWrapper.scala
new file mode 100644 (file)
index 0000000..15d755d
--- /dev/null
@@ -0,0 +1,181 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.mockaon
+
+import Chisel._
+import config._
+import diplomacy._
+import uncore.tilelink2._
+import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
+import sifive.blocks.util.{DeglitchShiftRegister, ResetCatchAndSync}
+import util._
+/* The wrapper handles the Clock and Reset Generation for The AON block itself,
+ and instantiates real pad controls (aka pull-ups)*/
+
+class MockAONWrapperPMUIO extends Bundle {
+  val dwakeup_n = new GPIOPin()
+  val vddpaden = new GPIOPin()
+}
+
+class MockAONWrapperPadsIO extends Bundle {
+  val erst_n = new GPIOPin()
+  val lfextclk = new GPIOPin()
+  val pmu = new MockAONWrapperPMUIO()
+}
+
+class MockAONWrapperBundle extends Bundle {
+  val pads = new MockAONWrapperPadsIO()
+  val rsts = new MockAONMOffRstIO()
+}
+
+class MockAONWrapper(c: MockAONConfig)(implicit val p: Parameters) extends LazyModule {
+
+  val node = TLAsyncInputNode()
+  val intnode = IntOutputNode()
+  val aon = LazyModule (new MockAON(c)(p))
+
+  // We only need to isolate the signals
+  // coming from MOFF to AON,
+  // since AON is never off while MOFF is on.
+  // The MOFF is on the "in" side of the Isolation.
+  // AON is on the "out" side of the Isolation.
+
+  def isoOut(iso: Bool, x: UInt): UInt = IsoZero(iso, x)
+  def isoIn(iso: Bool, x: UInt): UInt = x
+  val isolation = LazyModule(new TLIsolation(fOut = isoOut, fIn = isoIn))
+  val crossing = LazyModule(new TLAsyncCrossingSink(depth = 1))
+
+  isolation.node := node
+  crossing.node := isolation.node
+  val crossing_monitor = (aon.node := crossing.node)
+
+  // crossing lives outside in Periphery
+  intnode := aon.intnode
+
+  lazy val module = new LazyModuleImp(this) {
+    val io = new MockAONWrapperBundle {
+      val in = node.bundleIn
+      val ip = intnode.bundleOut
+      val rtc  = Clock(OUTPUT)
+    }
+
+    val aon_io = aon.module.io
+    val pads = io.pads
+
+    // -----------------------------------------------
+    // Generation of aonrst
+    // -----------------------------------------------
+
+    // ERST
+    val erst = ~ GPIOInputPinCtrl(pads.erst_n, pue = Bool(true))
+    aon_io.resetCauses.erst := erst
+    aon_io.resetCauses.wdogrst := aon_io.wdog_rst
+
+    // PORRST
+    val porrst = Bool(false) // TODO
+    aon_io.resetCauses.porrst := porrst
+
+    //--------------------------------------------------
+    // Drive "Mostly Off" Reset Signals (these
+    // are synchronized inside MOFF as needed)
+    //--------------------------------------------------
+
+    io.rsts.hfclkrst := aon_io.moff.hfclkrst
+    io.rsts.corerst  := aon_io.moff.corerst
+
+    //--------------------------------------------------
+    // Generate the LFCLK input to AON
+    // This is the same clock that is driven to this
+    // block as 'clock'.
+    //--------------------------------------------------
+
+    // LFCLK Override
+    // Note that the actual mux lives inside AON itself.
+    // Therefore, the lfclk which comes out of AON is the
+    // true clock that AON and AONWrapper are running off of.
+    val lfextclk = GPIOInputPinCtrl(pads.lfextclk, pue=Bool(true))
+    aon_io.lfextclk := lfextclk.asClock
+
+    // Drive AON's clock and Reset
+    val lfclk = aon_io.lfclk
+
+    val aonrst_catch = Module (new ResetCatchAndSync(3))
+    aonrst_catch.reset := erst | aon_io.wdog_rst
+    aonrst_catch.clock := lfclk
+    aon.module.reset := aonrst_catch.io.sync_reset
+
+    aon.module.clock := lfclk
+
+    //--------------------------------------------------
+    // TL2 Register Access Interface
+    //--------------------------------------------------
+
+    // Safely cross TL2 into AON Domain
+    // Ensure that both are reset and clocked
+    // at the same time.
+    // Note that aon.moff.corerst is synchronous
+    // to aon.module.clock, so this is safe.
+    val crossing_slave_reset  = ResetCatchAndSync(lfclk,
+      aon.module.io.moff.corerst | aon.module.reset)
+
+    crossing.module.clock := lfclk
+    crossing.module.reset := crossing_slave_reset
+
+    crossing_monitor.foreach { lm =>
+      lm.module.clock := lfclk
+      lm.module.reset := crossing_slave_reset
+    }
+
+    // Note that aon.moff.corerst is synchronous
+    // to aon.module.clock, so this is safe.
+    isolation.module.io.iso_out := aon.module.io.moff.corerst
+    isolation.module.io.iso_in  := Bool(true)
+
+    //--------------------------------------------------
+    // PMU <--> pads Interface
+    //--------------------------------------------------
+
+    val dwakeup_n_async = GPIOInputPinCtrl(pads.pmu.dwakeup_n, pue=Bool(true))
+
+    val dwakeup_deglitch = Module (new DeglitchShiftRegister(3))
+    dwakeup_deglitch.clock := lfclk
+    dwakeup_deglitch.io.d := ~dwakeup_n_async
+    aon.module.io.pmu.dwakeup := dwakeup_deglitch.io.q
+
+    GPIOOutputPinCtrl(pads.pmu.vddpaden, aon.module.io.pmu.vddpaden)
+
+    //--------------------------------------------------
+    // Connect signals to MOFF
+    //--------------------------------------------------
+
+    io.rtc := aon_io.lfclk
+  }
+
+}
+
+// -----------------------------------------------
+// Isolation Cells
+// -----------------------------------------------
+
+class IsoZero extends Module {
+  val io = new Bundle {
+    val in = Bool(INPUT)
+    val iso = Bool(INPUT)
+    val out = Bool(OUTPUT)
+  }
+  io.out := io.in & ~io.iso
+}
+
+object IsoZero {
+  def apply (iso: Bool, in: UInt): UInt = {
+
+    val w = in.getWidth
+    val isos: List[IsoZero] = List.tabulate(in.getWidth)(
+      x => Module(new IsoZero).suggestName(s"iso_$x")
+    )
+    for ((z, i) <- isos.zipWithIndex) {
+      z.io.in := in(i)
+      z.io.iso := iso
+    }
+    isos.map(_.io.out).asUInt
+  }
+}
diff --git a/src/main/scala/devices/mockaon/PMU.scala b/src/main/scala/devices/mockaon/PMU.scala
new file mode 100644 (file)
index 0000000..2c7964a
--- /dev/null
@@ -0,0 +1,152 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.mockaon
+
+import Chisel._
+import Chisel.ImplicitConversions._
+import util._
+import sifive.blocks.util.SRLatch
+
+import sifive.blocks.util.{SlaveRegIF}
+
+class WakeupCauses extends Bundle {
+  val awakeup = Bool()
+  val dwakeup = Bool()
+  val rtc = Bool()
+  val reset = Bool()
+}
+
+class ResetCauses extends Bundle {
+  val wdogrst = Bool()
+  val erst = Bool()
+  val porrst = Bool()
+}
+
+class PMUSignals extends Bundle {
+  val hfclkrst = Bool()
+  val corerst = Bool()
+  val reserved1 = Bool()
+  val vddpaden = Bool()
+  val reserved0 = Bool()
+}
+
+class PMUInstruction extends Bundle {
+  val sigs = new PMUSignals
+  val dt = UInt(width = 4)
+}
+
+class PMUConfig(wakeupProgramIn: Seq[Int],
+                sleepProgramIn: Seq[Int]) {
+  val programLength = 8
+  val nWakeupCauses = new WakeupCauses().elements.size
+  val wakeupProgram = wakeupProgramIn.padTo(programLength, wakeupProgramIn.last)
+  val sleepProgram = sleepProgramIn.padTo(programLength, sleepProgramIn.last)
+  require(wakeupProgram.length == programLength)
+  require(sleepProgram.length == programLength)
+}
+
+class DevKitPMUConfig extends PMUConfig( // TODO
+  Seq(0x1f0, 0x0f8, 0x030),
+  Seq(0x0f0, 0x1f0, 0x1d0, 0x1c0))
+
+class PMURegs(c: PMUConfig) extends Bundle {
+  val ie = new SlaveRegIF(c.nWakeupCauses)
+  val cause = new SlaveRegIF(32)
+  val sleep = new SlaveRegIF(32)
+  val key = new SlaveRegIF(32)
+  val wakeupProgram = Vec(c.programLength, new SlaveRegIF(32))
+  val sleepProgram = Vec(c.programLength, new SlaveRegIF(32))
+}
+
+class PMUCore(c: PMUConfig)(resetIn: Bool) extends Module(_reset = resetIn) {
+  val io = new Bundle {
+    val wakeup = new WakeupCauses().asInput
+    val control = Valid(new PMUSignals)
+    val resetCause = UInt(INPUT, log2Ceil(new ResetCauses().getWidth))
+    val regs = new PMURegs(c)
+  }
+
+  val run = Reg(init = Bool(true))
+  val awake = Reg(init = Bool(true))
+  val unlocked = {
+    val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
+    RegEnable(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, Bool(false), io.regs.key.write.valid || writeAny)
+  }
+  val wantSleep = RegEnable(Bool(true), Bool(false), io.regs.sleep.write.valid && unlocked)
+  val pc = Reg(init = UInt(0, log2Ceil(c.programLength)))
+  val wakeupCause = Reg(init = UInt(0, log2Ceil(c.nWakeupCauses)))
+  val ie = RegEnable(io.regs.ie.write.bits, io.regs.ie.write.valid && unlocked) | 1 /* POR always enabled */
+
+  val insnWidth = new PMUInstruction().getWidth
+  val wakeupProgram = c.wakeupProgram.map(v => Reg(init = UInt(v, insnWidth)))
+  val sleepProgram = c.sleepProgram.map(v => Reg(init = UInt(v, insnWidth)))
+  val insnBits = Mux(awake, wakeupProgram(pc), sleepProgram(pc))
+  val insn = new PMUInstruction().fromBits(insnBits)
+
+  val count = Reg(init = UInt(0, 1 << insn.dt.getWidth))
+  val tick = (count ^ (count + 1))(insn.dt)
+  val npc = pc +& 1
+  val last = npc >= c.programLength
+  io.control.valid := run && !last && tick
+  io.control.bits := insn.sigs
+
+  when (run) {
+    count := count + 1
+    when (tick) {
+      count := 0
+
+      require(isPow2(c.programLength))
+      run := !last
+      pc := npc
+    }
+  }.otherwise {
+    val maskedWakeupCauses = ie & io.wakeup.asUInt
+    when (!awake && maskedWakeupCauses.orR) {
+      run := true
+      awake := true
+      wakeupCause := PriorityEncoder(maskedWakeupCauses)
+    }
+    when (awake && wantSleep) {
+      run := true
+      awake := false
+      wantSleep := false
+    }
+  }
+
+  io.regs.cause.read := wakeupCause | (io.resetCause << 8)
+  io.regs.ie.read := ie
+  io.regs.key.read := unlocked
+  io.regs.sleep.read := 0
+
+  for ((port, reg) <- (io.regs.wakeupProgram ++ io.regs.sleepProgram) zip (wakeupProgram ++ sleepProgram)) {
+    port.read := reg
+    when (port.write.valid && unlocked) { reg := port.write.bits }
+  }
+}
+
+class PMU(val c: PMUConfig) extends Module {
+  val io = new Bundle {
+    val wakeup = new WakeupCauses().asInput
+    val control = new PMUSignals().asOutput
+    val regs = new PMURegs(c)
+    val resetCauses = new ResetCauses().asInput
+  }
+
+  val core = Module(new PMUCore(c)(resetIn = Reg(next = Reg(next = reset))))
+  io <> core.io
+  core.io.wakeup.reset := false // this is implied by resetting the PMU
+
+  // during aonrst, hold all control signals high
+  val latch = ~AsyncResetReg(~core.io.control.bits.asUInt, core.io.control.valid)
+  io.control := io.control.fromBits(latch)
+
+  core.io.resetCause := {
+    val cause = io.resetCauses.asUInt
+    val latches = for (i <- 0 until cause.getWidth) yield {
+      val latch = Module(new SRLatch)
+      latch.io.set := cause(i)
+      latch.io.reset := (0 until cause.getWidth).filter(_ != i).map(cause(_)).reduce(_||_)
+      latch.io.q
+    }
+    OHToUInt(latches)
+  }
+}
diff --git a/src/main/scala/devices/mockaon/WatchdogTimer.scala b/src/main/scala/devices/mockaon/WatchdogTimer.scala
new file mode 100644 (file)
index 0000000..5383dbe
--- /dev/null
@@ -0,0 +1,58 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.mockaon
+
+import Chisel._
+import Chisel.ImplicitConversions._
+import util.AsyncResetReg
+
+import sifive.blocks.util.{SlaveRegIF, GenericTimer}
+
+object WatchdogTimer {
+  def writeAnyExceptKey(regs: Bundle, keyReg: SlaveRegIF): Bool = {
+    regs.elements.values.filter(_ ne keyReg).map({
+      case v: Vec[SlaveRegIF] @unchecked => v.map(_.write.valid).reduce(_||_)
+      case s: SlaveRegIF => s.write.valid
+    }).reduce(_||_)
+  }
+
+  val key = 0x51F15E
+}
+
+class WatchdogTimer extends GenericTimer {
+  protected def countWidth = 31
+  protected def cmpWidth = 16
+  protected def ncmp = 1
+  protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
+  override protected lazy val countAwake = AsyncResetReg(io.regs.cfg.write.bits(13), io.regs.cfg.write.valid && unlocked)(0)
+  protected lazy val countEn = {
+    val corerstSynchronized = Reg(next = Reg(next = io.corerst))
+    countAlways || (countAwake && !corerstSynchronized)
+  }
+  override protected lazy val rsten = AsyncResetReg(io.regs.cfg.write.bits(8), io.regs.cfg.write.valid && unlocked)(0)
+  protected lazy val ip = RegEnable(io.regs.cfg.write.bits(28) || elapsed(0), (io.regs.cfg.write.valid && unlocked) || elapsed(0))
+  override protected lazy val unlocked = {
+    val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
+    AsyncResetReg(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, io.regs.key.write.valid || writeAny)(0)
+  }
+  protected lazy val feed = {
+    val food = 0xD09F00D
+    unlocked && io.regs.feed.write.valid && io.regs.feed.write.bits === food
+  }
+  lazy val io = new GenericTimerIO {
+    val corerst = Bool(INPUT)
+    val rst = Bool(OUTPUT)
+  }
+  io.rst := AsyncResetReg(Bool(true), rsten && elapsed(0))
+}
+
+class RTC extends GenericTimer {
+  protected def countWidth = 48
+  protected def cmpWidth = 32
+  protected def ncmp = 1
+  protected def countEn = countAlways
+  override protected lazy val ip = Reg(next = elapsed(0))
+  override protected lazy val zerocmp = Bool(false)
+  protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
+  protected lazy val feed = Bool(false)
+  lazy val io = new GenericTimerIO
+}
diff --git a/src/main/scala/devices/pwm/PWM.scala b/src/main/scala/devices/pwm/PWM.scala
new file mode 100644 (file)
index 0000000..2fd870c
--- /dev/null
@@ -0,0 +1,82 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.pwm
+
+import Chisel._
+import Chisel.ImplicitConversions._
+import config._
+import regmapper._
+import rocketchip.PeripheryBusConfig
+import uncore.tilelink2._
+import util._
+
+import sifive.blocks.util.GenericTimer
+
+// Core PWM Functionality  & Register Interface
+
+class PWM(val ncmp: Int = 4, val cmpWidth: Int = 16)(implicit p: Parameters) extends GenericTimer {
+  protected def countWidth = ((1 << scaleWidth) - 1) + cmpWidth
+  protected lazy val countAlways = RegEnable(io.regs.cfg.write.bits(12), Bool(false), io.regs.cfg.write.valid && unlocked)
+  protected lazy val feed = count.carryOut(scale + UInt(cmpWidth))
+  protected lazy val countEn = Wire(Bool())
+  override protected lazy val oneShot = RegEnable(io.regs.cfg.write.bits(13) && !countReset, Bool(false), (io.regs.cfg.write.valid && unlocked) || countReset)
+  override protected lazy val center = RegEnable(io.regs.cfg.write.bits(16 + ncmp - 1, 16), io.regs.cfg.write.valid && unlocked)
+  override protected lazy val gang = RegEnable(io.regs.cfg.write.bits(24 + ncmp - 1, 24), io.regs.cfg.write.valid && unlocked)
+  override protected lazy val deglitch = RegEnable(io.regs.cfg.write.bits(10), io.regs.cfg.write.valid && unlocked)(0)
+  override protected lazy val sticky = RegEnable(io.regs.cfg.write.bits(8), io.regs.cfg.write.valid && unlocked)(0)
+  override protected lazy val ip = {
+    val doSticky = Reg(next = (deglitch && !countReset) || sticky)
+    val sel = ((0 until ncmp).map(i => s(cmpWidth-1) && center(i))).asUInt
+    val reg = Reg(UInt(width = ncmp))
+    reg := (sel & elapsed.asUInt) | (~sel & (elapsed.asUInt | (Fill(ncmp, doSticky) & reg)))
+    when (io.regs.cfg.write.valid && unlocked) { reg := io.regs.cfg.write.bits(28 + ncmp - 1, 28) }
+    reg
+  }
+  lazy val io = new GenericTimerIO {
+    val gpio = Vec(ncmp, Bool()).asOutput
+  }
+  io.gpio := io.gpio.fromBits(ip & ~(gang & Cat(ip(0), ip >> 1)))
+  countEn := countAlways || oneShot
+}
+
+case class PWMConfig(
+  address: BigInt,
+  size: Int = 0x1000,
+  regBytes: Int = 4,
+  ncmp: Int = 4,
+  cmpWidth: Int = 16)
+{
+  val bc = new PWMBundleConfig(ncmp)
+}
+
+case class PWMBundleConfig(
+  ncmp: Int)
+{
+  def union(that: PWMBundleConfig): PWMBundleConfig =
+    PWMBundleConfig(scala.math.max(ncmp, that.ncmp))
+}
+
+trait HasPWMParameters {
+  val params: (PWMConfig, Parameters)
+  val c = params._1
+  implicit val p = params._2
+}
+
+trait PWMBundle extends Bundle with HasPWMParameters {
+  val gpio = Vec(c.ncmp, Bool()).asOutput
+}
+
+trait PWMModule extends Module with HasRegMap with HasPWMParameters {
+  val io: PWMBundle
+
+  val pwm = Module(new PWM(c.ncmp, c.cmpWidth))
+
+  interrupts := pwm.io.ip
+  io.gpio := pwm.io.gpio
+
+  regmap((GenericTimer.timerRegMap(pwm, 0, c.regBytes)):_*)
+}
+
+class TLPWM(c: PWMConfig)(implicit val p: Parameters)
+  extends TLRegisterRouter(c.address, interrupts = c.ncmp, size = c.size, beatBytes = p(PeripheryBusConfig).beatBytes)(
+  new TLRegBundle((c, p), _)    with PWMBundle)(
+  new TLRegModule((c, p), _, _) with PWMModule)
diff --git a/src/main/scala/devices/pwm/PWMPeriphery.scala b/src/main/scala/devices/pwm/PWMPeriphery.scala
new file mode 100644 (file)
index 0000000..992699f
--- /dev/null
@@ -0,0 +1,58 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.pwm
+
+import Chisel._
+import config._
+import diplomacy.LazyModule
+import rocketchip.{TopNetwork,TopNetworkModule}
+import uncore.tilelink2.TLFragmenter
+
+import sifive.blocks.devices.gpio._
+
+class PWMPortIO(c: PWMBundleConfig)(implicit p: Parameters) extends Bundle {
+  val port = Vec(c.ncmp, Bool()).asOutput
+  override def cloneType: this.type = new PWMPortIO(c).asInstanceOf[this.type]
+}
+
+class PWMPinsIO(c: PWMBundleConfig)(implicit p: Parameters) extends Bundle {
+  val pwm = Vec(c.ncmp, new GPIOPin)
+}
+
+class PWMGPIOPort(c: PWMBundleConfig)(implicit p: Parameters) extends Module {
+  val io = new Bundle {
+    val pwm = new PWMPortIO(c).flip()
+    val pins = new PWMPinsIO(c)
+  }
+
+  GPIOOutputPinCtrl(io.pins.pwm, io.pwm.port.asUInt)
+}
+
+trait PeripheryPWM {
+  this: TopNetwork { val pwmConfigs: Seq[PWMConfig] } =>
+
+  val pwmDevices = (pwmConfigs.zipWithIndex) map { case (c, i) =>
+    val pwm = LazyModule(new TLPWM(c) { override lazy val  valName = Some(s"pwm$i") })
+    pwm.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+    intBus.intnode := pwm.intnode
+    pwm
+  }
+}
+
+trait PeripheryPWMBundle {
+  this: {
+    val p: Parameters
+    val pwmConfigs: Seq[PWMConfig]
+  } =>
+  val pwm_bc = pwmConfigs.map(_.bc).reduce(_.union(_))
+  val pwms = Vec(pwmConfigs.size, new PWMPortIO(pwm_bc)(p))
+}
+
+trait PeripheryPWMModule {
+  this: TopNetworkModule {
+    val outer: PeripheryPWM
+    val io: PeripheryPWMBundle
+  } =>
+  (io.pwms.zipWithIndex zip outer.pwmDevices) foreach { case ((io, i), device) =>
+    io.port := device.module.io.gpio
+  }
+}
diff --git a/src/main/scala/devices/spi/SPIArbiter.scala b/src/main/scala/devices/spi/SPIArbiter.scala
new file mode 100644 (file)
index 0000000..b47cea3
--- /dev/null
@@ -0,0 +1,40 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+class SPIInnerIO(c: SPIConfigBase) extends SPILinkIO(c) {
+  val lock = Bool(OUTPUT)
+}
+
+class SPIArbiter(c: SPIConfigBase, n: Int) extends Module {
+  val io = new Bundle {
+    val inner = Vec(n, new SPIInnerIO(c)).flip
+    val outer = new SPILinkIO(c)
+    val sel = UInt(INPUT, log2Up(n))
+  }
+
+  val sel = Reg(init = Vec(Bool(true) +: Seq.fill(n-1)(Bool(false))))
+
+  io.outer.tx.valid := Mux1H(sel, io.inner.map(_.tx.valid))
+  io.outer.tx.bits := Mux1H(sel, io.inner.map(_.tx.bits))
+  io.outer.cnt := Mux1H(sel, io.inner.map(_.cnt))
+  io.outer.fmt := Mux1H(sel, io.inner.map(_.fmt))
+  io.outer.cs := Mux1H(sel, io.inner.map(_.cs))
+
+  (io.inner zip sel).foreach { case (inner, s) =>
+    inner.tx.ready := io.outer.tx.ready && s
+    inner.rx.valid := io.outer.rx.valid && s
+    inner.rx.bits := io.outer.rx.bits
+    inner.active := io.outer.active && s
+  }
+
+  val nsel = Vec.tabulate(n)(io.sel === UInt(_))
+  val lock = Mux1H(sel, io.inner.map(_.lock))
+  when (!lock) {
+    sel := nsel
+    when (sel.asUInt =/= nsel.asUInt) {
+      io.outer.cs.clear := Bool(true)
+    }
+  }
+}
diff --git a/src/main/scala/devices/spi/SPIBundle.scala b/src/main/scala/devices/spi/SPIBundle.scala
new file mode 100644 (file)
index 0000000..ed7a679
--- /dev/null
@@ -0,0 +1,106 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+abstract class SPIBundle(val c: SPIConfigBase) extends Bundle {
+  override def cloneType: SPIBundle.this.type =
+    this.getClass.getConstructors.head.newInstance(c).asInstanceOf[this.type]
+}
+
+class SPIDataIO extends Bundle {
+  val i = Bool(INPUT)
+  val o = Bool(OUTPUT)
+  val oe = Bool(OUTPUT)
+}
+
+class SPIPortIO(c: SPIConfigBase) extends SPIBundle(c) {
+  val sck = Bool(OUTPUT)
+  val dq = Vec(4, new SPIDataIO)
+  val cs = Vec(c.csWidth, Bool(OUTPUT))
+}
+
+trait HasSPIProtocol {
+  val proto = Bits(width = SPIProtocol.width)
+}
+trait HasSPIEndian {
+  val endian = Bits(width = SPIEndian.width)
+}
+class SPIFormat(c: SPIConfigBase) extends SPIBundle(c)
+    with HasSPIProtocol
+    with HasSPIEndian {
+  val iodir = Bits(width = SPIDirection.width)
+}
+
+trait HasSPILength extends SPIBundle {
+  val len = UInt(width = c.lengthBits)
+}
+
+class SPIClocking(c: SPIConfigBase) extends SPIBundle(c) {
+  val div = UInt(width = c.divisorBits)
+  val pol = Bool()
+  val pha = Bool()
+}
+
+class SPIChipSelect(c: SPIConfigBase) extends SPIBundle(c) {
+  val id = UInt(width = c.csIdBits)
+  val dflt = Vec(c.csWidth, Bool())
+
+  def toggle(en: Bool): Vec[Bool] = {
+    val mask = en << id
+    val out = Cat(dflt.reverse) ^ mask
+    Vec.tabulate(c.csWidth)(out(_))
+  }
+}
+
+trait HasSPICSMode {
+  val mode = Bits(width = SPICSMode.width)
+}
+
+class SPIDelay(c: SPIConfigBase) extends SPIBundle(c) {
+  val cssck = UInt(width = c.delayBits)
+  val sckcs = UInt(width = c.delayBits)
+  val intercs = UInt(width = c.delayBits)
+  val interxfr = UInt(width = c.delayBits)
+}
+
+class SPIWatermark(c: SPIConfigBase) extends SPIBundle(c) {
+  val tx = UInt(width = c.txDepthBits)
+  val rx = UInt(width = c.rxDepthBits)
+}
+
+class SPIControl(c: SPIConfigBase) extends SPIBundle(c) {
+  val fmt = new SPIFormat(c) with HasSPILength
+  val sck = new SPIClocking(c)
+  val cs = new SPIChipSelect(c) with HasSPICSMode
+  val dla = new SPIDelay(c)
+  val wm = new SPIWatermark(c)
+}
+
+object SPIControl {
+  def init(c: SPIConfigBase): SPIControl = {
+    val ctrl = Wire(new SPIControl(c))
+    ctrl.fmt.proto := SPIProtocol.Single
+    ctrl.fmt.iodir := SPIDirection.Rx
+    ctrl.fmt.endian := SPIEndian.MSB
+    ctrl.fmt.len := UInt(math.min(c.frameBits, 8))
+    ctrl.sck.div := UInt(3)
+    ctrl.sck.pol := Bool(false)
+    ctrl.sck.pha := Bool(false)
+    ctrl.cs.id := UInt(0)
+    ctrl.cs.dflt.foreach { _ := Bool(true) }
+    ctrl.cs.mode := SPICSMode.Auto
+    ctrl.dla.cssck := UInt(1)
+    ctrl.dla.sckcs := UInt(1)
+    ctrl.dla.intercs := UInt(1)
+    ctrl.dla.interxfr := UInt(0)
+    ctrl.wm.tx := UInt(0)
+    ctrl.wm.rx := UInt(0)
+    ctrl
+  }
+}
+
+class SPIInterrupts extends Bundle {
+  val txwm = Bool()
+  val rxwm = Bool()
+}
diff --git a/src/main/scala/devices/spi/SPIConsts.scala b/src/main/scala/devices/spi/SPIConsts.scala
new file mode 100644 (file)
index 0000000..b18b08a
--- /dev/null
@@ -0,0 +1,33 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+object SPIProtocol {
+  val width = 2
+  val Single = UInt(0, width)
+  val Dual   = UInt(1, width)
+  val Quad   = UInt(2, width)
+
+  val cases = Seq(Single, Dual, Quad)
+  def decode(x: UInt): Seq[Bool] = cases.map(_ === x)
+}
+
+object SPIDirection {
+  val width = 1
+  val Rx = UInt(0, width)
+  val Tx = UInt(1, width)
+}
+
+object SPIEndian {
+  val width = 1
+  val MSB = UInt(0, width)
+  val LSB = UInt(1, width)
+}
+
+object SPICSMode {
+  val width = 2
+  val Auto = UInt(0, width)
+  val Hold = UInt(2, width)
+  val Off  = UInt(3, width)
+}
diff --git a/src/main/scala/devices/spi/SPIFIFO.scala b/src/main/scala/devices/spi/SPIFIFO.scala
new file mode 100644 (file)
index 0000000..c7d8005
--- /dev/null
@@ -0,0 +1,62 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+class SPIFIFOControl(c: SPIConfigBase) extends SPIBundle(c) {
+  val fmt = new SPIFormat(c) with HasSPILength
+  val cs = new Bundle with HasSPICSMode
+  val wm = new SPIWatermark(c)
+}
+
+class SPIFIFO(c: SPIConfigBase) extends Module {
+  val io = new Bundle {
+    val ctrl = new SPIFIFOControl(c).asInput
+    val link = new SPIInnerIO(c)
+    val tx = Decoupled(Bits(width = c.frameBits)).flip
+    val rx = Decoupled(Bits(width = c.frameBits))
+    val ip = new SPIInterrupts().asOutput
+  }
+
+  val txq = Module(new Queue(io.tx.bits, c.txDepth))
+  val rxq = Module(new Queue(io.rx.bits, c.rxDepth))
+
+  txq.io.enq <> io.tx
+  io.link.tx <> txq.io.deq
+
+  val fire_tx = io.link.tx.fire()
+  val fire_rx = io.link.rx.fire()
+  val rxen = Reg(init = Bool(false))
+
+  rxq.io.enq.valid := io.link.rx.valid && rxen
+  rxq.io.enq.bits := io.link.rx.bits
+  io.rx <> rxq.io.deq
+
+  when (fire_rx) {
+    rxen := Bool(false)
+  }
+  when (fire_tx) {
+    rxen := (io.link.fmt.iodir === SPIDirection.Rx)
+  }
+
+  val proto = SPIProtocol.decode(io.link.fmt.proto).zipWithIndex
+  val cnt_quot = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len >> i) })
+  val cnt_rmdr = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len(i, 0).orR) })
+  io.link.fmt <> io.ctrl.fmt
+  io.link.cnt := cnt_quot + cnt_rmdr
+
+  val cs_mode = RegNext(io.ctrl.cs.mode, SPICSMode.Auto)
+  val cs_mode_hold = (cs_mode === SPICSMode.Hold)
+  val cs_mode_off = (cs_mode === SPICSMode.Off)
+  val cs_update = (cs_mode =/= io.ctrl.cs.mode)
+  val cs_clear = !(cs_mode_hold || cs_mode_off)
+
+  io.link.cs.set := !cs_mode_off
+  io.link.cs.clear := cs_update || (fire_tx && cs_clear)
+  io.link.cs.hold := Bool(false)
+
+  io.link.lock := io.link.tx.valid || rxen
+
+  io.ip.txwm := (txq.io.count < io.ctrl.wm.tx)
+  io.ip.rxwm := (rxq.io.count > io.ctrl.wm.rx)
+}
diff --git a/src/main/scala/devices/spi/SPIFlash.scala b/src/main/scala/devices/spi/SPIFlash.scala
new file mode 100644 (file)
index 0000000..1ad55ca
--- /dev/null
@@ -0,0 +1,162 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+class SPIFlashInsn(c: SPIFlashConfigBase) extends SPIBundle(c) {
+  val cmd = new Bundle with HasSPIProtocol {
+    val code = Bits(width = c.insnCmdBits)
+    val en = Bool()
+  }
+  val addr = new Bundle with HasSPIProtocol {
+    val len = UInt(width = c.insnAddrLenBits)
+  }
+  val pad = new Bundle {
+    val code = Bits(width = c.frameBits)
+    val cnt = Bits(width = c.insnPadLenBits)
+  }
+  val data = new Bundle with HasSPIProtocol
+}
+
+class SPIFlashControl(c: SPIFlashConfigBase) extends SPIBundle(c) {
+  val insn = new SPIFlashInsn(c)
+  val fmt = new Bundle with HasSPIEndian
+}
+
+object SPIFlashInsn {
+  def init(c: SPIFlashConfigBase): SPIFlashInsn = {
+    val insn = Wire(new SPIFlashInsn(c))
+    insn.cmd.en := Bool(true)
+    insn.cmd.code := Bits(0x03)
+    insn.cmd.proto := SPIProtocol.Single
+    insn.addr.len := UInt(3)
+    insn.addr.proto := SPIProtocol.Single
+    insn.pad.cnt := UInt(0)
+    insn.pad.code := Bits(0)
+    insn.data.proto := SPIProtocol.Single
+    insn
+  }
+}
+
+class SPIFlashAddr(c: SPIFlashConfigBase) extends SPIBundle(c) {
+  val next = UInt(width = c.insnAddrBits)
+  val hold = UInt(width = c.insnAddrBits)
+}
+
+class SPIFlashMap(c: SPIFlashConfigBase) extends Module {
+  val io = new Bundle {
+    val en = Bool(INPUT)
+    val ctrl = new SPIFlashControl(c).asInput
+    val addr = Decoupled(new SPIFlashAddr(c)).flip
+    val data = Decoupled(UInt(width = c.frameBits))
+    val link = new SPIInnerIO(c)
+  }
+
+  val addr = io.addr.bits.hold + UInt(1)
+  val merge = io.link.active && (io.addr.bits.next === addr)
+
+  private val insn = io.ctrl.insn
+  io.link.tx.valid := Bool(true)
+  io.link.fmt.proto := insn.addr.proto
+  io.link.fmt.iodir := SPIDirection.Tx
+  io.link.fmt.endian := io.ctrl.fmt.endian
+  io.link.cnt := Mux1H(
+    SPIProtocol.decode(io.link.fmt.proto).zipWithIndex.map {
+      case (s, i) => (s -> UInt(c.frameBits >> i))
+    })
+  io.link.cs.set := Bool(true)
+  io.link.cs.clear := Bool(false)
+  io.link.cs.hold := Bool(true)
+  io.link.lock := Bool(true)
+
+  io.addr.ready := Bool(false)
+  io.data.valid := Bool(false)
+  io.data.bits := io.link.rx.bits
+
+  val cnt = Reg(UInt(width = math.max(c.insnPadLenBits, c.insnAddrLenBits)))
+  val cnt_en = Wire(init = Bool(false))
+  val cnt_cmp = (0 to c.insnAddrBytes).map(cnt === UInt(_))
+  val cnt_zero = cnt_cmp(0)
+  val cnt_last = cnt_cmp(1) && io.link.tx.ready
+  val cnt_done = cnt_last || cnt_zero
+  when (cnt_en) {
+    io.link.tx.valid := !cnt_zero
+    when (io.link.tx.fire()) {
+      cnt := cnt - UInt(1)
+    }
+  }
+
+  val (s_idle :: s_cmd :: s_addr :: s_pad :: s_data_pre :: s_data_post :: Nil) = Enum(UInt(), 6)
+  val state = Reg(init = s_idle)
+
+  switch (state) {
+    is (s_idle) {
+      io.link.tx.valid := Bool(false)
+      when (io.en) {
+        io.addr.ready := Bool(true)
+        when (io.addr.valid) {
+          when (merge) {
+            state := s_data_pre
+          } .otherwise {
+            state := Mux(insn.cmd.en, s_cmd, s_addr)
+            io.link.cs.clear := Bool(true)
+          }
+        } .otherwise {
+          io.link.lock := Bool(false)
+        }
+      } .otherwise {
+        io.data.valid := io.addr.valid
+        io.addr.ready := io.data.ready
+        io.data.bits := UInt(0)
+        io.link.lock := Bool(false)
+      }
+    }
+
+    is (s_cmd) {
+      io.link.fmt.proto := insn.cmd.proto
+      io.link.tx.bits := insn.cmd.code
+      when (io.link.tx.ready) {
+        state := s_addr
+        cnt := insn.addr.len
+      }
+    }
+
+    is (s_addr) {
+      io.link.tx.bits := Mux1H(cnt_cmp.tail.zipWithIndex.map {
+        case (s, i) =>
+          val n = i * c.frameBits
+          val m = n + (c.frameBits - 1)
+          s -> io.addr.bits.hold(m, n)
+      })
+
+      cnt_en := Bool(true)
+      when (cnt_done) {
+        state := s_pad
+      }
+    }
+
+    is (s_pad) {
+      io.link.cnt := insn.pad.cnt
+      io.link.tx.bits := insn.pad.code
+      when (io.link.tx.ready) {
+        state := s_data_pre
+      }
+    }
+
+    is (s_data_pre) {
+      io.link.fmt.proto := insn.data.proto
+      io.link.fmt.iodir := SPIDirection.Rx
+      when (io.link.tx.ready) {
+        state := s_data_post
+      }
+    }
+
+    is (s_data_post) {
+      io.link.tx.valid := Bool(false)
+      io.data.valid := io.link.rx.valid
+      when (io.data.fire()) {
+        state := s_idle
+      }
+    }
+  }
+}
diff --git a/src/main/scala/devices/spi/SPIMedia.scala b/src/main/scala/devices/spi/SPIMedia.scala
new file mode 100644 (file)
index 0000000..1f049e3
--- /dev/null
@@ -0,0 +1,121 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+
+class SPILinkIO(c: SPIConfigBase) extends SPIBundle(c) {
+  val tx = Decoupled(Bits(width = c.frameBits))
+  val rx = Valid(Bits(width = c.frameBits)).flip
+
+  val cnt = UInt(OUTPUT, c.countBits)
+  val fmt = new SPIFormat(c).asOutput
+  val cs = new Bundle {
+    val set = Bool(OUTPUT)
+    val clear = Bool(OUTPUT) // Deactivate CS
+    val hold = Bool(OUTPUT) // Supress automatic CS deactivation
+  }
+  val active = Bool(INPUT)
+}
+
+class SPIMedia(c: SPIConfigBase) extends Module {
+  val io = new Bundle {
+    val port = new SPIPortIO(c)
+    val ctrl = new Bundle {
+      val sck = new SPIClocking(c).asInput
+      val dla = new SPIDelay(c).asInput
+      val cs = new SPIChipSelect(c).asInput
+    }
+    val link = new SPILinkIO(c).flip
+  }
+
+  val phy = Module(new SPIPhysical(c))
+  phy.io.ctrl.sck := io.ctrl.sck
+  phy.io.ctrl.fmt := io.link.fmt
+
+  private val op = phy.io.op
+  op.valid := Bool(true)
+  op.bits.fn := SPIMicroOp.Delay
+  op.bits.stb := Bool(false)
+  op.bits.cnt := io.link.cnt
+  op.bits.data := io.link.tx.bits
+
+  val cs = Reg(io.ctrl.cs)
+  val cs_set = Reg(Bool())
+  val cs_active = io.ctrl.cs.toggle(io.link.cs.set)
+  val cs_update = (cs_active.asUInt =/= cs.dflt.asUInt)
+
+  val clear = Reg(init = Bool(false))
+  val cs_assert = Reg(init = Bool(false))
+  val cs_deassert = clear || (cs_update && !io.link.cs.hold)
+
+  clear := clear || (io.link.cs.clear && cs_assert)
+
+  val continuous = (io.ctrl.dla.interxfr === UInt(0))
+
+  io.port.sck := phy.io.port.sck
+  io.port.dq <> phy.io.port.dq
+  io.port.cs := cs.dflt
+
+  io.link.rx := phy.io.rx
+  io.link.tx.ready := Bool(false)
+  io.link.active := cs_assert
+
+  val (s_main :: s_interxfr :: s_intercs :: Nil) = Enum(UInt(), 3)
+  val state = Reg(init = s_main)
+
+  switch (state) {
+    is (s_main) {
+      when (cs_assert) {
+        when (cs_deassert) {
+          op.bits.cnt := io.ctrl.dla.sckcs
+          when (op.ready) {
+            state := s_intercs
+          }
+        } .otherwise {
+          op.bits.fn := SPIMicroOp.Transfer
+          op.bits.stb := Bool(true)
+
+          op.valid := io.link.tx.valid
+          io.link.tx.ready := op.ready
+          when (op.fire()) {
+            state := s_interxfr
+          }
+        }
+      } .elsewhen (io.link.tx.valid) {
+        // Assert CS
+        op.bits.cnt := io.ctrl.dla.cssck
+        when (op.ready) {
+          cs_assert := Bool(true)
+          cs_set := io.link.cs.set
+          cs.dflt := cs_active
+        }
+      } .otherwise {
+        // Idle
+        op.bits.cnt := UInt(0)
+        op.bits.stb := Bool(true)
+        cs := io.ctrl.cs
+      }
+    }
+
+    is (s_interxfr) {
+      // Skip if interxfr delay is zero
+      op.valid := !continuous
+      op.bits.cnt := io.ctrl.dla.interxfr
+      when (op.ready || continuous) {
+        state := s_main
+      }
+    }
+
+    is (s_intercs) {
+      // Deassert CS
+      op.bits.cnt := io.ctrl.dla.intercs
+      op.bits.stb := Bool(true)
+      cs_assert := Bool(false)
+      clear := Bool(false)
+      when (op.ready) {
+        cs.dflt := cs.toggle(cs_set)
+        state := s_main
+      }
+    }
+  }
+}
diff --git a/src/main/scala/devices/spi/SPIPeriphery.scala b/src/main/scala/devices/spi/SPIPeriphery.scala
new file mode 100644 (file)
index 0000000..40bcec6
--- /dev/null
@@ -0,0 +1,57 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+import diplomacy.LazyModule
+import uncore.tilelink2._
+import rocketchip.{TopNetwork,TopNetworkModule}
+
+trait PeripherySPI {
+  this: TopNetwork { val spiConfigs: Seq[SPIConfig] } =>
+  val spiDevices = (spiConfigs.zipWithIndex) map {case (c, i) =>
+    val spi = LazyModule(new TLSPI(c) { override lazy val valName = Some(s"spi$i") } )
+    spi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+    intBus.intnode := spi.intnode
+    spi
+  }
+}
+
+trait PeripherySPIBundle {
+  this: { val spiConfigs: Seq[SPIConfig] } =>
+  val spi_bc = spiConfigs.map(_.bc).reduce(_.union(_))
+  val spis = Vec(spiConfigs.size, new SPIPortIO(spi_bc.toSPIConfig))
+}
+
+trait PeripherySPIModule {
+  this: TopNetworkModule {
+    val spiConfigs: Seq[SPIConfig]
+    val outer: PeripherySPI
+    val io: PeripherySPIBundle
+  } =>
+  (io.spis zip outer.spiDevices).foreach { case (io, device) =>
+    io <> device.module.io.port
+  }
+}
+
+
+trait PeripherySPIFlash {
+  this: TopNetwork { val spiFlashConfig: SPIFlashConfig } =>
+  val qspi = LazyModule(new TLSPIFlash(spiFlashConfig))
+  qspi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+  qspi.fnode := TLFragmenter(1, cacheBlockBytes)(TLWidthWidget(peripheryBusConfig.beatBytes)(peripheryBus.node))
+  intBus.intnode := qspi.intnode
+}
+
+trait PeripherySPIFlashBundle {
+  this: { val spiFlashConfig: SPIFlashConfig } =>
+  val qspi = new SPIPortIO(spiFlashConfig)
+}
+
+trait PeripherySPIFlashModule {
+  this: TopNetworkModule {
+    val spiConfigs: Seq[SPIConfig]
+    val outer: PeripherySPIFlash
+    val io: PeripherySPIFlashBundle
+  } =>
+  io.qspi <> outer.qspi.module.io.port
+}
diff --git a/src/main/scala/devices/spi/SPIPhysical.scala b/src/main/scala/devices/spi/SPIPhysical.scala
new file mode 100644 (file)
index 0000000..6584be8
--- /dev/null
@@ -0,0 +1,157 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+import sifive.blocks.util.ShiftRegisterInit
+
+class SPIMicroOp(c: SPIConfigBase) extends SPIBundle(c) {
+  val fn = Bits(width = 1)
+  val stb = Bool()
+  val cnt = UInt(width = c.countBits)
+  val data = Bits(width = c.frameBits)
+}
+
+object SPIMicroOp {
+  val Transfer = UInt(0, 1)
+  val Delay    = UInt(1, 1)
+}
+
+class SPIPhyControl(c: SPIConfigBase) extends SPIBundle(c) {
+  val sck = new SPIClocking(c)
+  val fmt = new SPIFormat(c)
+}
+
+class SPIPhysical(c: SPIConfigBase) extends Module {
+  val io = new SPIBundle(c) {
+    val port = new SPIPortIO(c)
+    val ctrl = new SPIPhyControl(c).asInput
+    val op = Decoupled(new SPIMicroOp(c)).flip
+    val rx = Valid(Bits(width = c.frameBits))
+  }
+
+  private val op = io.op.bits
+  val ctrl = Reg(io.ctrl)
+  val proto = SPIProtocol.decode(ctrl.fmt.proto)
+
+  val accept = Wire(init = Bool(false))
+  val sample = Wire(init = Bool(false))
+  val setup = Wire(init = Bool(false))
+  val last = Wire(init = Bool(false))
+  // Delayed versions
+  val setup_d = Reg(next = setup)
+  val sample_d = ShiftRegisterInit(sample, c.sampleDelay, Bool(false))
+  val last_d = ShiftRegisterInit(last, c.sampleDelay, Bool(false))
+
+  val scnt = Reg(init = UInt(0, c.countBits))
+  val tcnt = Reg(io.ctrl.sck.div)
+
+  val stop = (scnt === UInt(0))
+  val beat = (tcnt === UInt(0))
+  val decr = Mux(beat, scnt, tcnt) - UInt(1)
+  val sched = Wire(init = beat)
+  tcnt := Mux(sched, ctrl.sck.div, decr)
+
+  val sck = Reg(Bool())
+  val cref = Reg(init = Bool(true))
+  val cinv = ctrl.sck.pha ^ ctrl.sck.pol
+
+  private def convert(data: UInt, fmt: SPIFormat) =
+    Mux(fmt.endian === SPIEndian.MSB, data, Cat(data.toBools))
+
+  val rxd = Cat(io.port.dq.reverse.map(_.i))
+  val samples = Seq(rxd(1), rxd(1, 0), rxd)
+
+  val buffer = Reg(op.data)
+  val buffer_in = convert(io.op.bits.data, io.ctrl.fmt)
+  val shift = if (c.sampleDelay > 0) setup_d || (sample_d && stop) else sample_d
+  buffer := Mux1H(proto, samples.zipWithIndex.map { case (data, i) =>
+    val n = 1 << i
+    val m = c.frameBits -1
+    Cat(Mux(shift, buffer(m-n, 0), buffer(m, n)),
+        Mux(sample_d, data, buffer(n-1, 0)))
+  })
+
+  private def upper(x: UInt, n: Int) = x(c.frameBits-1, c.frameBits-n)
+
+  val txd = Reg(init = Bits(0, io.port.dq.size))
+  val txd_in = Mux(accept, upper(buffer_in, 4), upper(buffer, 4))
+  val txd_sel = SPIProtocol.decode(Mux(accept, io.ctrl.fmt.proto, ctrl.fmt.proto))
+  val txd_shf = (0 until txd_sel.size).map(i => txd_in(3, 4-(1<<i)))
+  when (setup) {
+    txd := Mux1H(txd_sel, txd_shf)
+  }
+
+  val tx = (ctrl.fmt.iodir === SPIDirection.Tx)
+  val txen_in = (proto.head +: proto.tail.map(_ && tx)).scanRight(Bool(false))(_ || _)
+  val txen = txen_in :+ txen_in.last
+
+  io.port.sck := sck
+  io.port.cs := Vec.fill(io.port.cs.size)(Bool(true)) // dummy
+  (io.port.dq zip (txd.toBools zip txen)).foreach {
+    case (dq, (o, oe)) =>
+      dq.o := o
+      dq.oe := oe
+  }
+  io.op.ready := Bool(false)
+
+  val done = Reg(init = Bool(true))
+  done := done || last_d
+
+  io.rx.valid := done
+  io.rx.bits := convert(buffer, ctrl.fmt)
+
+  val xfr = Reg(Bool())
+
+  when (stop) {
+    sched := Bool(true)
+    accept := Bool(true)
+  } .otherwise {
+    when (beat) {
+      cref := !cref
+      when (xfr) {
+        sck := cref ^ cinv
+        sample := cref
+        setup := !cref
+      }
+      when (!cref) {
+        scnt := decr
+      }
+    }
+  }
+
+  when (scnt === UInt(1)) {
+    last := beat && cref && xfr // Final sample
+    when (beat && !cref) { // Final shift
+      accept := Bool(true)
+      setup := Bool(false)
+      sck := ctrl.sck.pol
+    }
+  }
+
+  when (accept && done) {
+    io.op.ready := Bool(true)
+    when (io.op.valid) {
+      scnt := op.cnt
+      when (op.stb) {
+        ctrl.fmt := io.ctrl.fmt
+      }
+
+      xfr := Bool(false)
+      switch (op.fn) {
+        is (SPIMicroOp.Transfer) {
+          buffer := buffer_in
+          sck := cinv
+          setup := Bool(true)
+          done := (op.cnt === UInt(0))
+          xfr := Bool(true)
+        }
+        is (SPIMicroOp.Delay) {
+          when (op.stb) {
+            sck := io.ctrl.sck.pol
+            ctrl.sck := io.ctrl.sck
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/main/scala/devices/spi/SPIPins.scala b/src/main/scala/devices/spi/SPIPins.scala
new file mode 100644 (file)
index 0000000..48c3020
--- /dev/null
@@ -0,0 +1,34 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
+
+class SPIPinsIO(c: SPIConfigBase) extends SPIBundle(c) {
+  val sck = new GPIOPin
+  val dq = Vec(4, new GPIOPin)
+  val cs = Vec(c.csWidth, new GPIOPin)
+}
+
+class SPIGPIOPort(c: SPIConfigBase, syncStages: Int = 0, driveStrength: Bool = Bool(false)) extends Module {
+  val io = new SPIBundle(c) {
+    val spi = new SPIPortIO(c).flip
+    val pins = new SPIPinsIO(c)
+  }
+
+  GPIOOutputPinCtrl(io.pins.sck, io.spi.sck, ds = driveStrength)
+
+  GPIOOutputPinCtrl(io.pins.dq, Bits(0, io.spi.dq.size))
+  (io.pins.dq zip io.spi.dq).foreach {
+    case (p, s) =>
+      p.o.oval := s.o
+      p.o.oe  := s.oe
+      p.o.ie  := ~s.oe
+      p.o.pue := Bool(true)
+      p.o.ds  := driveStrength
+      s.i := ShiftRegister(p.i.ival, syncStages)
+  }
+
+  GPIOOutputPinCtrl(io.pins.cs, io.spi.cs.asUInt)
+  io.pins.cs.foreach(_.o.ds := driveStrength)
+}
diff --git a/src/main/scala/devices/spi/SPIRegs.scala b/src/main/scala/devices/spi/SPIRegs.scala
new file mode 100644 (file)
index 0000000..b10237d
--- /dev/null
@@ -0,0 +1,30 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+object SPICRs {
+  val sckdiv    = 0x00
+  val sckmode   = 0x04
+  val csid      = 0x10
+  val csdef     = 0x14
+  val csmode    = 0x18
+  val dcssck    = 0x28
+  val dsckcs    = 0x2a
+  val dintercs  = 0x2c
+  val dinterxfr = 0x2e
+
+  val fmt       = 0x40
+  val len       = 0x42
+  val txfifo    = 0x48
+  val rxfifo    = 0x4c
+  val txmark    = 0x50
+  val rxmark    = 0x54
+
+  val insnmode  = 0x60
+  val insnfmt   = 0x64
+  val insnproto = 0x65
+  val insncmd   = 0x66
+  val insnpad   = 0x67
+
+  val ie        = 0x70
+  val ip        = 0x74
+}
diff --git a/src/main/scala/devices/spi/TLSPI.scala b/src/main/scala/devices/spi/TLSPI.scala
new file mode 100644 (file)
index 0000000..bc920ea
--- /dev/null
@@ -0,0 +1,132 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+import config._
+import uncore.tilelink2._
+import diplomacy._
+import regmapper._
+import junctions._
+import rocketchip.PeripheryBusConfig
+import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
+
+trait SPIConfigBase {
+  val rAddress: BigInt
+  val rSize: BigInt
+  val rxDepth: Int
+  val txDepth: Int
+
+  val csWidth: Int
+  val frameBits: Int
+  val delayBits: Int
+  val divisorBits: Int
+
+  val sampleDelay: Int
+
+  lazy val csIdBits = log2Up(csWidth)
+  lazy val lengthBits = log2Floor(frameBits) + 1
+  lazy val countBits = math.max(lengthBits, delayBits)
+
+  lazy val txDepthBits = log2Floor(txDepth) + 1
+  lazy val rxDepthBits = log2Floor(rxDepth) + 1
+
+  lazy val bc = new SPIBundleConfig(csWidth)
+}
+
+case class SPIConfig(
+    rAddress: BigInt,
+    rSize: BigInt = 0x1000,
+    rxDepth: Int = 8,
+    txDepth: Int = 8,
+    csWidth: Int = 1,
+    frameBits: Int = 8,
+    delayBits: Int = 8,
+    divisorBits: Int = 12,
+    sampleDelay: Int = 2)
+  extends SPIConfigBase {
+
+  require(frameBits >= 4)
+  require(sampleDelay >= 0)
+}
+
+case class SPIBundleConfig(csWidth: Int)
+  {
+    def union(that: SPIBundleConfig): SPIBundleConfig =
+      SPIBundleConfig(scala.math.max(csWidth, that.csWidth))
+
+    def toSPIConfig: SPIConfig = new SPIConfig(rAddress = -1,
+      csWidth = csWidth)
+  }
+
+class SPITopBundle(val i: Vec[Vec[Bool]], val r: Vec[TLBundle]) extends Bundle
+
+class SPITopModule[B <: SPITopBundle](c: SPIConfigBase, bundle: => B, outer: TLSPIBase)
+  extends LazyModuleImp(outer) {
+
+  val io = new Bundle {
+    val port = new SPIPortIO(c)
+    val tl = bundle
+  }
+
+  val ctrl = Reg(init = SPIControl.init(c))
+
+  val fifo = Module(new SPIFIFO(c))
+  val mac = Module(new SPIMedia(c))
+  io.port <> mac.io.port
+
+  fifo.io.ctrl.fmt := ctrl.fmt
+  fifo.io.ctrl.cs <> ctrl.cs
+  fifo.io.ctrl.wm := ctrl.wm
+  mac.io.ctrl.sck := ctrl.sck
+  mac.io.ctrl.dla := ctrl.dla
+  mac.io.ctrl.cs <> ctrl.cs
+
+  val ie = Reg(init = new SPIInterrupts().fromBits(Bits(0)))
+  val ip = fifo.io.ip
+  io.tl.i(0)(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
+
+  protected val regmapBase = Seq(
+    SPICRs.sckdiv -> Seq(RegField(c.divisorBits, ctrl.sck.div)),
+    SPICRs.sckmode -> Seq(
+      RegField(1, ctrl.sck.pha),
+      RegField(1, ctrl.sck.pol)),
+    SPICRs.csid -> Seq(RegField(c.csIdBits, ctrl.cs.id)),
+    SPICRs.csdef -> ctrl.cs.dflt.map(x => RegField(1, x)),
+    SPICRs.csmode -> Seq(RegField(SPICSMode.width, ctrl.cs.mode)),
+    SPICRs.dcssck -> Seq(RegField(c.delayBits, ctrl.dla.cssck)),
+    SPICRs.dsckcs -> Seq(RegField(c.delayBits, ctrl.dla.sckcs)),
+    SPICRs.dintercs -> Seq(RegField(c.delayBits, ctrl.dla.intercs)),
+    SPICRs.dinterxfr -> Seq(RegField(c.delayBits, ctrl.dla.interxfr)),
+
+    SPICRs.fmt -> Seq(
+      RegField(SPIProtocol.width, ctrl.fmt.proto),
+      RegField(SPIEndian.width, ctrl.fmt.endian),
+      RegField(SPIDirection.width, ctrl.fmt.iodir)),
+    SPICRs.len -> Seq(RegField(c.lengthBits, ctrl.fmt.len)),
+
+    SPICRs.txfifo -> NonBlockingEnqueue(fifo.io.tx),
+    SPICRs.rxfifo -> NonBlockingDequeue(fifo.io.rx),
+
+    SPICRs.txmark -> Seq(RegField(c.txDepthBits, ctrl.wm.tx)),
+    SPICRs.rxmark -> Seq(RegField(c.rxDepthBits, ctrl.wm.rx)),
+
+    SPICRs.ie -> Seq(
+      RegField(1, ie.txwm),
+      RegField(1, ie.rxwm)),
+    SPICRs.ip -> Seq(
+      RegField.r(1, ip.txwm),
+      RegField.r(1, ip.rxwm)))
+}
+
+abstract class TLSPIBase(c: SPIConfigBase)(implicit val p: Parameters) extends LazyModule {
+  require(isPow2(c.rSize))
+  val rnode = TLRegisterNode(address = AddressSet(c.rAddress, c.rSize-1), beatBytes = p(PeripheryBusConfig).beatBytes)
+  val intnode = IntSourceNode(1)
+}
+
+class TLSPI(c: SPIConfig)(implicit p: Parameters) extends TLSPIBase(c)(p) {
+  lazy val module = new SPITopModule(c, new SPITopBundle(intnode.bundleOut, rnode.bundleIn), this) {
+    mac.io.link <> fifo.io.link
+    rnode.regmap(regmapBase:_*)
+  }
+}
diff --git a/src/main/scala/devices/spi/TLSPIFlash.scala b/src/main/scala/devices/spi/TLSPIFlash.scala
new file mode 100644 (file)
index 0000000..284692f
--- /dev/null
@@ -0,0 +1,114 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.spi
+
+import Chisel._
+import config._
+import diplomacy._
+import regmapper._
+import uncore.tilelink2._
+
+trait SPIFlashConfigBase extends SPIConfigBase {
+  val fAddress: BigInt
+  val fSize: BigInt
+
+  val insnAddrBytes: Int
+  val insnPadLenBits: Int
+  lazy val insnCmdBits = frameBits
+  lazy val insnAddrBits = insnAddrBytes * frameBits
+  lazy val insnAddrLenBits = log2Floor(insnAddrBytes) + 1
+}
+
+case class SPIFlashConfig(
+    rAddress: BigInt,
+    fAddress: BigInt,
+    rSize: BigInt = 0x1000,
+    fSize: BigInt = 0x20000000,
+    rxDepth: Int = 8,
+    txDepth: Int = 8,
+    csWidth: Int = 1,
+    delayBits: Int = 8,
+    divisorBits: Int = 12,
+    sampleDelay: Int = 2)
+  extends SPIFlashConfigBase {
+  val frameBits = 8
+  val insnAddrBytes = 4
+  val insnPadLenBits = 4
+
+  require(insnPadLenBits <= delayBits)
+  require(sampleDelay >= 0)
+}
+
+class SPIFlashTopBundle(i: Vec[Vec[Bool]], r: Vec[TLBundle], val f: Vec[TLBundle]) extends SPITopBundle(i, r)
+
+class SPIFlashTopModule[B <: SPIFlashTopBundle]
+    (c: SPIFlashConfigBase, bundle: => B, outer: TLSPIFlashBase)
+  extends SPITopModule(c, bundle, outer) {
+
+  val flash = Module(new SPIFlashMap(c))
+  val arb = Module(new SPIArbiter(c, 2))
+
+  private val f = io.tl.f.head
+  // Tie unused channels
+  f.b.valid := Bool(false)
+  f.c.ready := Bool(true)
+  f.e.ready := Bool(true)
+
+  val a = Reg(f.a.bits)
+  val a_msb = log2Ceil(c.fSize) - 1
+
+  when (f.a.fire()) {
+    a := f.a.bits
+  }
+
+  flash.io.addr.bits.next := f.a.bits.address(a_msb, 0)
+  flash.io.addr.bits.hold := a.address(a_msb, 0)
+  flash.io.addr.valid := f.a.valid
+  f.a.ready := flash.io.addr.ready
+
+  f.d.bits := outer.fnode.edgesIn.head.AccessAck(a, UInt(0), flash.io.data.bits)
+  f.d.valid := flash.io.data.valid
+  flash.io.data.ready := f.d.ready
+
+  val insn = Reg(init = SPIFlashInsn.init(c))
+  val flash_en = Reg(init = Bool(true))
+
+  flash.io.ctrl.insn := insn
+  flash.io.ctrl.fmt <> ctrl.fmt
+  flash.io.en := flash_en
+  arb.io.sel := !flash_en
+
+  protected val regmapFlash = Seq(
+    SPICRs.insnmode -> Seq(RegField(1, flash_en)),
+    SPICRs.insnfmt -> Seq(
+      RegField(1, insn.cmd.en),
+      RegField(c.insnAddrLenBits, insn.addr.len),
+      RegField(c.insnPadLenBits, insn.pad.cnt)),
+    SPICRs.insnproto -> Seq(
+      RegField(SPIProtocol.width, insn.cmd.proto),
+      RegField(SPIProtocol.width, insn.addr.proto),
+      RegField(SPIProtocol.width, insn.data.proto)),
+    SPICRs.insncmd -> Seq(RegField(c.insnCmdBits, insn.cmd.code)),
+    SPICRs.insnpad -> Seq(RegField(c.frameBits, insn.pad.code)))
+}
+
+abstract class TLSPIFlashBase(c: SPIFlashConfigBase)(implicit p: Parameters) extends TLSPIBase(c)(p) {
+  require(isPow2(c.fSize))
+  val fnode = TLManagerNode(1, TLManagerParameters(
+    address     = Seq(AddressSet(c.fAddress, c.fSize-1)),
+    regionType  = RegionType.UNCACHED,
+    executable  = true,
+    supportsGet = TransferSizes(1, 1),
+    fifoId      = Some(0)))
+}
+
+class TLSPIFlash(c: SPIFlashConfig)(implicit p: Parameters) extends TLSPIFlashBase(c)(p) {
+  lazy val module = new SPIFlashTopModule(c,
+    new SPIFlashTopBundle(intnode.bundleOut, rnode.bundleIn, fnode.bundleIn), this) {
+
+    arb.io.inner(0) <> flash.io.link
+    arb.io.inner(1) <> fifo.io.link
+    mac.io.link <> arb.io.outer
+
+    rnode.regmap(regmapBase ++ regmapFlash:_*)
+  }
+}
diff --git a/src/main/scala/devices/uart/UART.scala b/src/main/scala/devices/uart/UART.scala
new file mode 100644 (file)
index 0000000..68b47fe
--- /dev/null
@@ -0,0 +1,275 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.uart
+
+import Chisel._
+import config._
+import regmapper._
+import uncore.tilelink2._
+import junctions._
+import util._
+import rocketchip.PeripheryBusConfig
+import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
+
+case class UARTConfig(
+  address: BigInt,
+  dataBits: Int = 8,
+  stopBits: Int = 2,
+  divisorBits: Int = 16,
+  oversample: Int = 4,
+  nSamples: Int = 3,
+  nTxEntries: Int = 8,
+  nRxEntries: Int = 8)
+
+trait HasUARTParameters {
+  val c: UARTConfig
+  val uartDataBits = c.dataBits
+  val uartStopBits = c.stopBits
+  val uartDivisorBits = c.divisorBits
+
+  val uartOversample = c.oversample
+  val uartOversampleFactor = 1 << uartOversample
+  val uartNSamples = c.nSamples
+
+  val uartNTxEntries = c.nTxEntries
+  val uartNRxEntries = c.nRxEntries
+
+  require(uartDivisorBits > uartOversample)
+  require(uartOversampleFactor > uartNSamples)
+}
+
+abstract class UARTModule(val c: UARTConfig)(implicit val p: Parameters)
+    extends Module with HasUARTParameters
+
+class UARTPortIO extends Bundle {
+  val txd = Bool(OUTPUT)
+  val rxd = Bool(INPUT)
+}
+
+trait MixUARTParameters {
+  val params: (UARTConfig, Parameters)
+  val c = params._1
+  implicit val p = params._2
+}
+
+trait UARTTopBundle extends Bundle with MixUARTParameters with HasUARTParameters {
+  val port = new UARTPortIO
+}
+
+class UARTTx(c: UARTConfig)(implicit p: Parameters) extends UARTModule(c)(p) {
+  val io = new Bundle {
+    val en = Bool(INPUT)
+    val in = Decoupled(Bits(width = uartDataBits)).flip
+    val out = Bits(OUTPUT, 1)
+    val div = UInt(INPUT, uartDivisorBits)
+    val nstop = UInt(INPUT, log2Up(uartStopBits))
+  }
+
+  val prescaler = Reg(init = UInt(0, uartDivisorBits))
+  val pulse = (prescaler === UInt(0))
+
+  private val n = uartDataBits + 1
+  val counter = Reg(init = UInt(0, log2Floor(n + uartStopBits) + 1))
+  val shifter = Reg(Bits(width = n))
+  val out = Reg(init = Bits(1, 1))
+  io.out := out
+
+  val busy = (counter =/= UInt(0))
+  io.in.ready := io.en && !busy
+  when (io.in.fire()) {
+    printf("%c", io.in.bits)
+    shifter := Cat(io.in.bits, Bits(0, 1))
+    counter := Mux1H((0 until uartStopBits).map(i =>
+      (io.nstop === UInt(i)) -> UInt(n + i + 1)))
+  }
+  when (busy) {
+    prescaler := Mux(pulse, io.div, prescaler - UInt(1))
+  }
+  when (pulse && busy) {
+    counter := counter - UInt(1)
+    shifter := Cat(Bits(1, 1), shifter >> 1)
+    out := shifter(0)
+  }
+}
+
+class UARTRx(c: UARTConfig)(implicit p: Parameters) extends UARTModule(c)(p) {
+  val io = new Bundle {
+    val en = Bool(INPUT)
+    val in = Bits(INPUT, 1)
+    val out = Valid(Bits(width = uartDataBits))
+    val div = UInt(INPUT, uartDivisorBits)
+  }
+
+  val debounce = Reg(init = UInt(0, 2))
+  val debounce_max = (debounce === UInt(3))
+  val debounce_min = (debounce === UInt(0))
+
+  val prescaler = Reg(init = UInt(0, uartDivisorBits - uartOversample))
+  val start = Wire(init = Bool(false))
+  val busy = Wire(init = Bool(false))
+  val pulse = (prescaler === UInt(0)) && busy
+
+  when (busy) {
+    prescaler := prescaler - UInt(1)
+  }
+  when (start || pulse) {
+    prescaler := io.div >> uartOversample
+  }
+
+  val sample = Reg(Bits(width = uartNSamples))
+  val voter = new Majority(sample.toBools.toSet)
+  when (pulse) {
+    sample := Cat(sample, io.in)
+  }
+
+  private val delay0 = (uartOversampleFactor + uartNSamples) >> 1
+  private val delay1 = uartOversampleFactor
+
+  val timer = Reg(UInt(width = uartOversample + 1))
+  val counter = Reg(UInt(width = log2Floor(uartDataBits) + 1))
+  val shifter = Reg(Bits(width = uartDataBits))
+  val expire = (timer === UInt(0)) && pulse
+
+  val sched = Wire(init = Bool(false))
+  when (pulse) {
+    timer := timer - UInt(1)
+  }
+  when (sched) {
+    timer := UInt(delay1-1)
+  }
+
+  val valid = Reg(init = Bool(false))
+  valid := Bool(false)
+  io.out.valid := valid
+  io.out.bits := shifter
+
+  val (s_idle :: s_start :: s_data :: Nil) = Enum(UInt(), 3)
+  val state = Reg(init = s_idle)
+
+  switch (state) {
+    is (s_idle) {
+      when (!(!io.in) && !debounce_min) {
+        debounce := debounce - UInt(1)
+      }
+      when (!io.in) {
+        debounce := debounce + UInt(1)
+        when (debounce_max) {
+          state := s_start
+          start := Bool(true)
+          timer := UInt(delay0-1)
+        }
+      }
+    }
+
+    is (s_start) {
+      busy := Bool(true)
+      when (expire) {
+        sched := Bool(true)
+        when (voter.out) {
+          state := s_idle
+        } .otherwise {
+          state := s_data
+          counter := UInt(uartDataBits)
+        }
+      }
+    }
+
+    is (s_data) {
+      busy := Bool(true)
+      when (expire) {
+        counter := counter - UInt(1)
+        when (counter === UInt(0)) {
+          state := s_idle
+          valid := Bool(true)
+        } .otherwise {
+          shifter := Cat(voter.out, shifter >> 1)
+          sched := Bool(true)
+        }
+      }
+    }
+  }
+
+  when (!io.en) {
+    debounce := UInt(0)
+  }
+}
+
+class UARTInterrupts extends Bundle {
+  val rxwm = Bool()
+  val txwm = Bool()
+}
+
+trait UARTTopModule extends Module with MixUARTParameters with HasUARTParameters with HasRegMap {
+  val io: UARTTopBundle
+
+  val txm = Module(new UARTTx(c))
+  val txq = Module(new Queue(txm.io.in.bits, uartNTxEntries))
+
+  val rxm = Module(new UARTRx(c))
+  val rxq = Module(new Queue(rxm.io.out.bits, uartNRxEntries))
+
+  val divinit = 542 // (62.5MHz / 115200)
+  val div = Reg(init = UInt(divinit, uartDivisorBits))
+
+  private val stopCountBits = log2Up(uartStopBits)
+  private val txCountBits = log2Floor(uartNTxEntries) + 1
+  private val rxCountBits = log2Floor(uartNRxEntries) + 1
+
+  val txen = Reg(init = Bool(false))
+  val rxen = Reg(init = Bool(false))
+  val txwm = Reg(init = UInt(0, txCountBits))
+  val rxwm = Reg(init = UInt(0, rxCountBits))
+  val nstop = Reg(init = UInt(0, stopCountBits))
+
+  txm.io.en := txen
+  txm.io.in <> txq.io.deq
+  txm.io.div := div
+  txm.io.nstop := nstop
+  io.port.txd := txm.io.out
+
+  rxm.io.en := rxen
+  rxm.io.in := io.port.rxd
+  rxq.io.enq <> rxm.io.out
+  rxm.io.div := div
+
+  val ie = Reg(init = new UARTInterrupts().fromBits(Bits(0)))
+  val ip = Wire(new UARTInterrupts)
+
+  ip.txwm := (txq.io.count < txwm)
+  ip.rxwm := (rxq.io.count > rxwm)
+  interrupts(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
+
+  regmap(
+    UARTCtrlRegs.txfifo -> NonBlockingEnqueue(txq.io.enq),
+    UARTCtrlRegs.rxfifo -> NonBlockingDequeue(rxq.io.deq),
+
+    UARTCtrlRegs.txctrl -> Seq(
+      RegField(1, txen),
+      RegField(stopCountBits, nstop)),
+    UARTCtrlRegs.rxctrl -> Seq(RegField(1, rxen)),
+    UARTCtrlRegs.txmark -> Seq(RegField(txCountBits, txwm)),
+    UARTCtrlRegs.rxmark -> Seq(RegField(rxCountBits, rxwm)),
+
+    UARTCtrlRegs.ie -> Seq(
+      RegField(1, ie.txwm),
+      RegField(1, ie.rxwm)),
+
+    UARTCtrlRegs.ip -> Seq(
+      RegField.r(1, ip.txwm),
+      RegField.r(1, ip.rxwm)),
+
+    UARTCtrlRegs.div -> Seq(
+      RegField(uartDivisorBits, div))
+  )
+}
+
+class Majority(in: Set[Bool]) {
+  private val n = (in.size >> 1) + 1
+  private val clauses = in.subsets(n).map(_.reduce(_ && _))
+  val out = clauses.reduce(_ || _)
+}
+
+// Magic TL2 Incantation to create a TL2 Slave
+class UART(c: UARTConfig)(implicit val p: Parameters)
+  extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = p(PeripheryBusConfig).beatBytes)(
+  new TLRegBundle((c, p), _)    with UARTTopBundle)(
+  new TLRegModule((c, p), _, _) with UARTTopModule)
diff --git a/src/main/scala/devices/uart/UARTCtrlRegs.scala b/src/main/scala/devices/uart/UARTCtrlRegs.scala
new file mode 100644 (file)
index 0000000..3556583
--- /dev/null
@@ -0,0 +1,15 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.uart
+
+object UARTCtrlRegs {
+  val txfifo = 0x00
+  val rxfifo = 0x04
+  val txctrl = 0x08
+  val txmark = 0x0a
+  val rxctrl = 0x0c
+  val rxmark = 0x0e
+
+  val ie     = 0x10
+  val ip     = 0x14
+  val div    = 0x18
+}
diff --git a/src/main/scala/devices/uart/UARTPeriphery.scala b/src/main/scala/devices/uart/UARTPeriphery.scala
new file mode 100644 (file)
index 0000000..fd5bc35
--- /dev/null
@@ -0,0 +1,54 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.uart
+
+import Chisel._
+import config._
+import diplomacy._
+import uncore.tilelink2._
+import rocketchip._
+
+import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
+import sifive.blocks.util.ShiftRegisterInit
+
+trait PeripheryUART {
+  this: TopNetwork {
+    val uartConfigs: Seq[UARTConfig]
+  } =>
+  val uartDevices = uartConfigs.zipWithIndex.map { case (c, i) =>
+    val uart = LazyModule(new UART(c) { override lazy val valName = Some(s"uart$i") } )
+    uart.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+    intBus.intnode := uart.intnode
+    uart
+  }
+}
+
+trait PeripheryUARTBundle {
+  this: { val uartConfigs: Seq[UARTConfig] } =>
+  val uarts = Vec(uartConfigs.size, new UARTPortIO)
+}
+
+trait PeripheryUARTModule {
+  this: TopNetworkModule {
+    val outer: PeripheryUART
+    val io: PeripheryUARTBundle
+  } =>
+  (io.uarts zip outer.uartDevices).foreach { case (io, device) =>
+    io <> device.module.io.port
+  }
+}
+
+class UARTPinsIO extends Bundle {
+  val rxd = new GPIOPin
+  val txd = new GPIOPin
+}
+
+class UARTGPIOPort(syncStages: Int = 0) extends Module {
+  val io = new Bundle{
+    val uart = new UARTPortIO().flip()
+    val pins = new UARTPinsIO
+  }
+
+  GPIOOutputPinCtrl(io.pins.txd, io.uart.txd)
+  val rxd = GPIOInputPinCtrl(io.pins.rxd)
+  io.uart.rxd := ShiftRegisterInit(rxd, syncStages, Bool(true))
+}
diff --git a/src/main/scala/devices/xilinxvc707mig/XilinxVC707MIG.scala b/src/main/scala/devices/xilinxvc707mig/XilinxVC707MIG.scala
new file mode 100644 (file)
index 0000000..bbbfcd3
--- /dev/null
@@ -0,0 +1,158 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.xilinxvc707mig
+
+import Chisel._
+import config._
+import diplomacy._
+import uncore.tilelink2._
+import uncore.axi4._
+import rocketchip._
+import sifive.blocks.ip.xilinx.vc707mig.{VC707MIGUnidirectionalIOClocksReset, VC707MIGUnidirectionalIODDR, vc707mig}
+
+trait HasXilinxVC707MIGParameters {
+}
+
+class XilinxVC707MIGPads extends Bundle with VC707MIGUnidirectionalIODDR {
+  val _inout_ddr3_dq = Bits(OUTPUT,64)
+  val _inout_ddr3_dqs_n = Bits(OUTPUT,8)
+  val _inout_ddr3_dqs_p = Bits(OUTPUT,8)
+}
+
+class XilinxVC707MIGIO extends Bundle with VC707MIGUnidirectionalIODDR
+                                      with VC707MIGUnidirectionalIOClocksReset {
+  val _inout_ddr3_dq = Bits(OUTPUT,64)
+  val _inout_ddr3_dqs_n = Bits(OUTPUT,8)
+  val _inout_ddr3_dqs_p = Bits(OUTPUT,8)
+}
+
+class XilinxVC707MIG(implicit p: Parameters) extends LazyModule with HasXilinxVC707MIGParameters {
+  val node = TLInputNode()
+  val axi4 = AXI4InternalOutputNode(AXI4SlavePortParameters(
+    slaves = Seq(AXI4SlaveParameters(
+      address = Seq(AddressSet(p(ExtMem).base, p(ExtMem).size-1)),
+      regionType    = RegionType.UNCACHED,
+      executable    = true,
+      supportsWrite = TransferSizes(1, 256*8),
+      supportsRead  = TransferSizes(1, 256*8),
+      interleavedId = Some(0))),
+    beatBytes = 8))
+
+  val xing = LazyModule(new TLAsyncCrossing)
+  val toaxi4 = LazyModule(new TLToAXI4(idBits = 4))
+
+  xing.node := node
+  val monitor = (toaxi4.node := xing.node)
+  axi4 := toaxi4.node
+
+  lazy val module = new LazyModuleImp(this) {
+    val io = new Bundle {
+      val port = new XilinxVC707MIGIO
+      val tl = node.bundleIn
+    }
+
+    //MIG black box instantiation
+    val blackbox = Module(new vc707mig)
+
+    //pins to top level
+
+    //inouts
+    io.port._inout_ddr3_dq    := blackbox.io.ddr3_dq
+    io.port._inout_ddr3_dqs_n := blackbox.io.ddr3_dqs_n
+    io.port._inout_ddr3_dqs_p := blackbox.io.ddr3_dqs_p
+
+    //outputs
+    io.port.ddr3_addr         := blackbox.io.ddr3_addr
+    io.port.ddr3_ba           := blackbox.io.ddr3_ba
+    io.port.ddr3_ras_n        := blackbox.io.ddr3_ras_n
+    io.port.ddr3_cas_n        := blackbox.io.ddr3_cas_n
+    io.port.ddr3_we_n         := blackbox.io.ddr3_we_n
+    io.port.ddr3_reset_n      := blackbox.io.ddr3_reset_n
+    io.port.ddr3_ck_p         := blackbox.io.ddr3_ck_p
+    io.port.ddr3_ck_n         := blackbox.io.ddr3_ck_n
+    io.port.ddr3_cke          := blackbox.io.ddr3_cke
+    io.port.ddr3_cs_n         := blackbox.io.ddr3_cs_n
+    io.port.ddr3_dm           := blackbox.io.ddr3_dm
+    io.port.ddr3_odt          := blackbox.io.ddr3_odt
+
+    //inputs
+    //differential system clock
+    blackbox.io.sys_clk_n     := io.port.sys_clk_n
+    blackbox.io.sys_clk_p     := io.port.sys_clk_p
+
+    //user interface signals
+    val axi_async = axi4.bundleIn(0)
+    xing.module.io.in_clock := clock
+    xing.module.io.in_reset := reset
+    xing.module.io.out_clock := blackbox.io.ui_clk
+    xing.module.io.out_reset := blackbox.io.ui_clk_sync_rst
+    toaxi4.module.clock := blackbox.io.ui_clk
+    toaxi4.module.reset := blackbox.io.ui_clk_sync_rst
+    monitor.foreach { lm =>
+      lm.module.clock := blackbox.io.ui_clk
+      lm.module.reset := blackbox.io.ui_clk_sync_rst
+    }
+
+    io.port.ui_clk            := blackbox.io.ui_clk
+    io.port.ui_clk_sync_rst   := blackbox.io.ui_clk_sync_rst
+    io.port.mmcm_locked       := blackbox.io.mmcm_locked
+    blackbox.io.aresetn       := io.port.aresetn
+    blackbox.io.app_sr_req    := Bool(false)
+    blackbox.io.app_ref_req   := Bool(false)
+    blackbox.io.app_zq_req    := Bool(false)
+    //app_sr_active           := unconnected
+    //app_ref_ack             := unconnected
+    //app_zq_ack              := unconnected
+
+    //slave AXI interface write address ports
+    blackbox.io.s_axi_awid    := axi_async.aw.bits.id
+    blackbox.io.s_axi_awaddr  := axi_async.aw.bits.addr //truncation ??
+    blackbox.io.s_axi_awlen   := axi_async.aw.bits.len
+    blackbox.io.s_axi_awsize  := axi_async.aw.bits.size
+    blackbox.io.s_axi_awburst := axi_async.aw.bits.burst
+    blackbox.io.s_axi_awlock  := axi_async.aw.bits.lock
+    blackbox.io.s_axi_awcache := UInt("b0011")
+    blackbox.io.s_axi_awprot  := axi_async.aw.bits.prot
+    blackbox.io.s_axi_awqos   := axi_async.aw.bits.qos
+    blackbox.io.s_axi_awvalid := axi_async.aw.valid
+    axi_async.aw.ready        := blackbox.io.s_axi_awready
+
+    //slave interface write data ports
+    blackbox.io.s_axi_wdata   := axi_async.w.bits.data
+    blackbox.io.s_axi_wstrb   := axi_async.w.bits.strb
+    blackbox.io.s_axi_wlast   := axi_async.w.bits.last
+    blackbox.io.s_axi_wvalid  := axi_async.w.valid
+    axi_async.w.ready         := blackbox.io.s_axi_wready
+
+    //slave interface write response
+    blackbox.io.s_axi_bready  := axi_async.b.ready
+    axi_async.b.bits.id       := blackbox.io.s_axi_bid
+    axi_async.b.bits.resp     := blackbox.io.s_axi_bresp
+    axi_async.b.valid         := blackbox.io.s_axi_bvalid
+
+    //slave AXI interface read address ports
+    blackbox.io.s_axi_arid    := axi_async.ar.bits.id
+    blackbox.io.s_axi_araddr  := axi_async.ar.bits.addr //truncation ??
+    blackbox.io.s_axi_arlen   := axi_async.ar.bits.len
+    blackbox.io.s_axi_arsize  := axi_async.ar.bits.size
+    blackbox.io.s_axi_arburst := axi_async.ar.bits.burst
+    blackbox.io.s_axi_arlock  := axi_async.ar.bits.lock
+    blackbox.io.s_axi_arcache := UInt("b0011")
+    blackbox.io.s_axi_arprot  := axi_async.ar.bits.prot
+    blackbox.io.s_axi_arqos   := axi_async.ar.bits.qos
+    blackbox.io.s_axi_arvalid := axi_async.ar.valid
+    axi_async.ar.ready        := blackbox.io.s_axi_arready
+
+    //slace AXI interface read data ports
+    blackbox.io.s_axi_rready  := axi_async.r.ready
+    axi_async.r.bits.id       := blackbox.io.s_axi_rid
+    axi_async.r.bits.data     := blackbox.io.s_axi_rdata
+    axi_async.r.bits.resp     := blackbox.io.s_axi_rresp
+    axi_async.r.bits.last     := blackbox.io.s_axi_rlast
+    axi_async.r.valid         := blackbox.io.s_axi_rvalid
+
+    //misc
+    io.port.init_calib_complete := blackbox.io.init_calib_complete
+    blackbox.io.sys_rst       :=io.port.sys_rst
+    //mig.device_temp         :- unconnceted
+  }
+}
diff --git a/src/main/scala/devices/xilinxvc707mig/XilinxVC707MIGPeriphery.scala b/src/main/scala/devices/xilinxvc707mig/XilinxVC707MIGPeriphery.scala
new file mode 100644 (file)
index 0000000..b52b37c
--- /dev/null
@@ -0,0 +1,26 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.xilinxvc707mig
+
+import Chisel._
+import diplomacy._
+import rocketchip.{TopNetwork,TopNetworkModule,TopNetworkBundle}
+import coreplex.BankedL2Config
+
+trait PeripheryXilinxVC707MIG extends TopNetwork {
+  val module: PeripheryXilinxVC707MIGModule
+
+  val xilinxvc707mig = LazyModule(new XilinxVC707MIG)
+  require(p(BankedL2Config).nMemoryChannels == 1, "Coreplex must have 1 master memory port")
+  val mem = Seq(xilinxvc707mig.node)
+}
+
+trait PeripheryXilinxVC707MIGBundle extends TopNetworkBundle {
+  val xilinxvc707mig = new XilinxVC707MIGIO
+}
+
+trait PeripheryXilinxVC707MIGModule extends TopNetworkModule {
+  val outer: PeripheryXilinxVC707MIG
+  val io: PeripheryXilinxVC707MIGBundle
+
+  io.xilinxvc707mig <> outer.xilinxvc707mig.module.io.port
+}
diff --git a/src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1.scala b/src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1.scala
new file mode 100644 (file)
index 0000000..a795bf0
--- /dev/null
@@ -0,0 +1,52 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.xilinxvc707pciex1
+
+import Chisel._
+import config._
+import diplomacy._
+import uncore.tilelink2._
+import uncore.axi4._
+import rocketchip._
+import sifive.blocks.ip.xilinx.vc707axi_to_pcie_x1.{VC707AXIToPCIeX1, VC707AXIToPCIeX1IOClocksReset, VC707AXIToPCIeX1IOSerial}
+import sifive.blocks.ip.xilinx.ibufds_gte2.IBUFDS_GTE2
+
+class XilinxVC707PCIeX1Pads extends Bundle with VC707AXIToPCIeX1IOSerial
+
+class XilinxVC707PCIeX1IO extends Bundle with VC707AXIToPCIeX1IOSerial
+                                         with VC707AXIToPCIeX1IOClocksReset {
+  val axi_ctl_aresetn = Bool(INPUT)
+  val REFCLK_rxp = Bool(INPUT)
+  val REFCLK_rxn = Bool(INPUT)
+}
+
+class XilinxVC707PCIeX1(implicit p: Parameters) extends LazyModule {
+  val slave = TLInputNode()
+  val control = TLInputNode()
+  val master = TLOutputNode()
+  val intnode = IntSourceNode(1)
+
+  val axi_to_pcie_x1 = LazyModule(new VC707AXIToPCIeX1)
+  axi_to_pcie_x1.slave   := TLToAXI4(idBits=4)(slave)
+  axi_to_pcie_x1.control := AXI4Fragmenter(lite=true, maxInFlight=4)(TLToAXI4(idBits=0)(control))
+  master := TLWidthWidget(64)(AXI4ToTL()(AXI4Fragmenter()(axi_to_pcie_x1.master)))
+
+  lazy val module = new LazyModuleImp(this) {
+    val io = new Bundle {
+      val port = new XilinxVC707PCIeX1IO
+      val slave_in = slave.bundleIn
+      val control_in = control.bundleIn
+      val master_out = master.bundleOut
+      val interrupt = intnode.bundleOut
+    }
+
+    io.port <> axi_to_pcie_x1.module.io.port
+    io.interrupt(0)(0) := axi_to_pcie_x1.module.io.interrupt_out
+
+    //PCIe Reference Clock
+    val ibufds_gte2 = Module(new IBUFDS_GTE2)
+    axi_to_pcie_x1.module.io.REFCLK := ibufds_gte2.io.O
+    ibufds_gte2.io.CEB := UInt(0)
+    ibufds_gte2.io.I := io.port.REFCLK_rxp
+    ibufds_gte2.io.IB := io.port.REFCLK_rxn
+  }
+}
diff --git a/src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala b/src/main/scala/devices/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala
new file mode 100644 (file)
index 0000000..494d787
--- /dev/null
@@ -0,0 +1,27 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.xilinxvc707pciex1
+
+import Chisel._
+import diplomacy.LazyModule
+import rocketchip.{L2Crossbar,L2CrossbarModule,L2CrossbarBundle}
+import uncore.tilelink2.TLWidthWidget
+
+trait PeripheryXilinxVC707PCIeX1 extends L2Crossbar {
+
+  val xilinxvc707pcie = LazyModule(new XilinxVC707PCIeX1)
+  l2.node := xilinxvc707pcie.master
+  xilinxvc707pcie.slave   := TLWidthWidget(socBusConfig.beatBytes)(socBus.node)
+  xilinxvc707pcie.control := TLWidthWidget(socBusConfig.beatBytes)(socBus.node)
+  intBus.intnode := xilinxvc707pcie.intnode
+}
+
+trait PeripheryXilinxVC707PCIeX1Bundle extends L2CrossbarBundle {
+  val xilinxvc707pcie = new XilinxVC707PCIeX1IO
+}
+
+trait PeripheryXilinxVC707PCIeX1Module extends L2CrossbarModule {
+  val outer: PeripheryXilinxVC707PCIeX1
+  val io: PeripheryXilinxVC707PCIeX1Bundle
+
+  io.xilinxvc707pcie <> outer.xilinxvc707pcie.module.io.port
+}
diff --git a/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala b/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala
new file mode 100644 (file)
index 0000000..7fca6f1
--- /dev/null
@@ -0,0 +1,18 @@
+// See LICENSE for license details.
+package sifive.blocks.ip.xilinx.ibufds_gte2
+
+import Chisel._
+
+//IP : xilinx unisim IBUFDS_GTE2
+//Differential Signaling Input Buffer
+//unparameterized
+
+class IBUFDS_GTE2 extends BlackBox {
+  val io = new Bundle {
+    val O         = Bool(OUTPUT)
+    val ODIV2     = Bool(OUTPUT)
+    val CEB       = Bool(INPUT)
+    val I         = Bool(INPUT)
+    val IB        = Bool(INPUT)
+  }
+}
diff --git a/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala b/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala
new file mode 100644 (file)
index 0000000..a7cf844
--- /dev/null
@@ -0,0 +1,374 @@
+// See LICENSE for license details.
+package sifive.blocks.ip.xilinx.vc707axi_to_pcie_x1
+
+import Chisel._
+import config._
+import diplomacy._
+import uncore.axi4._
+import junctions._
+
+// IP VLNV: xilinx.com:customize_ip:vc707pcietoaxi:1.0
+// Black Box
+// Signals named _exactly_ as per Vivado generated verilog
+// s : -{lock, cache, prot, qos}
+
+trait VC707AXIToPCIeX1IOSerial extends Bundle {
+  //serial external pins
+  val pci_exp_txp           = Bits(OUTPUT,1)
+  val pci_exp_txn           = Bits(OUTPUT,1)
+  val pci_exp_rxp           = Bits(INPUT,1)
+  val pci_exp_rxn           = Bits(INPUT,1)
+}
+
+trait VC707AXIToPCIeX1IOClocksReset extends Bundle {
+  //clock, reset, control
+  val axi_aresetn           = Bool(INPUT)
+  val axi_aclk_out          = Clock(OUTPUT)
+  val axi_ctl_aclk_out      = Clock(OUTPUT)
+  val mmcm_lock             = Bool(OUTPUT)
+}
+
+//scalastyle:off
+//turn off linter: blackbox name must match verilog module 
+class vc707axi_to_pcie_x1() extends BlackBox
+{
+  val io = new Bundle with VC707AXIToPCIeX1IOSerial
+                      with VC707AXIToPCIeX1IOClocksReset {
+    //refclk
+    val REFCLK                = Bool(INPUT)
+    //clock, reset, control
+    val INTX_MSI_Request      = Bool(INPUT)
+    val INTX_MSI_Grant        = Bool(OUTPUT)
+    val MSI_enable            = Bool(OUTPUT)
+    val MSI_Vector_Num        = Bits(INPUT,5)
+    val MSI_Vector_Width      = Bits(OUTPUT,3)
+    
+    //interrupt
+    val interrupt_out         = Bool(OUTPUT)
+
+    //axi slave
+    //-{lock, cache, prot, qos}
+    //slave interface write address
+    val s_axi_awid            = Bits(INPUT,4)
+    val s_axi_awaddr          = Bits(INPUT,32)
+    val s_axi_awregion        = Bits(INPUT,4)
+    val s_axi_awlen           = Bits(INPUT,8)
+    val s_axi_awsize          = Bits(INPUT,3)
+    val s_axi_awburst         = Bits(INPUT,2)
+    //val s_axi_awlock        = Bool(INPUT)
+    //val s_axi_awcache       = Bits(INPUT,4)
+    //val s_axi_awprot        = Bits(INPUT,3)
+    //val s_axi_awqos         = Bits(INPUT,4)
+    val s_axi_awvalid         = Bool(INPUT)
+    val s_axi_awready         = Bool(OUTPUT)
+    //slave interface write data
+    val s_axi_wdata           = Bits(INPUT,64)
+    val s_axi_wstrb           = Bits(INPUT,8)
+    val s_axi_wlast           = Bool(INPUT)
+    val s_axi_wvalid          = Bool(INPUT)
+    val s_axi_wready          = Bool(OUTPUT)
+    //slave interface write response
+    val s_axi_bready          = Bool(INPUT)
+    val s_axi_bid             = Bits(OUTPUT,4)
+    val s_axi_bresp           = Bits(OUTPUT,2)
+    val s_axi_bvalid          = Bool(OUTPUT)
+    //slave interface read address
+    val s_axi_arid            = Bits(INPUT,4)
+    val s_axi_araddr          = Bits(INPUT,32)
+    val s_axi_arregion        = Bits(INPUT,4)
+    val s_axi_arlen           = Bits(INPUT,8)
+    val s_axi_arsize          = Bits(INPUT,3)
+    val s_axi_arburst         = Bits(INPUT,2)
+    //val s_axi_arlock        = Bits(INPUT,1)
+    //val s_axi_arcache       = Bits(INPUT,4)
+    //val s_axi_arprot        = Bits(INPUT,3)
+    //val s_axi_arqos         = Bits(INPUT,4)
+    val s_axi_arvalid         = Bool(INPUT)
+    val s_axi_arready         = Bool(OUTPUT)
+    //slave interface read data
+    val s_axi_rready          = Bool(INPUT)
+    val s_axi_rid             = Bits(OUTPUT,4)
+    val s_axi_rdata           = Bits(OUTPUT,64)
+    val s_axi_rresp           = Bits(OUTPUT,2)
+    val s_axi_rlast           = Bool(OUTPUT)
+    val s_axi_rvalid          = Bool(OUTPUT)
+
+    //axi master
+    //-{id,region,qos}
+    //slave interface write address ports
+    //val m_axi_awid          = Bits(OUTPUT,4)
+    val m_axi_awaddr          = Bits(OUTPUT,32)
+    //val m_axi_awregion      = Bits(OUTPUT,4)
+    val m_axi_awlen           = Bits(OUTPUT,8)
+    val m_axi_awsize          = Bits(OUTPUT,3)
+    val m_axi_awburst         = Bits(OUTPUT,2)
+    val m_axi_awlock          = Bool(OUTPUT)
+    val m_axi_awcache         = Bits(OUTPUT,4)
+    val m_axi_awprot          = Bits(OUTPUT,3)
+    //val m_axi_awqos         = Bits(OUTPUT,4)
+    val m_axi_awvalid         = Bool(OUTPUT)
+    val m_axi_awready         = Bool(INPUT)
+    //slave interface write data ports
+    val m_axi_wdata           = Bits(OUTPUT,64)
+    val m_axi_wstrb           = Bits(OUTPUT,8)
+    val m_axi_wlast           = Bool(OUTPUT)
+    val m_axi_wvalid          = Bool(OUTPUT)
+    val m_axi_wready          = Bool(INPUT)
+    //slave interface write response ports
+    val m_axi_bready          = Bool(OUTPUT)
+    //val m_axi_bid           = Bits(INPUT,4)
+    val m_axi_bresp           = Bits(INPUT,2)
+    val m_axi_bvalid          = Bool(INPUT)
+    //slave interface read address ports
+    //val m_axi_arid          = Bits(OUTPUT,4)
+    val m_axi_araddr          = Bits(OUTPUT,32)
+    //val m_axi_arregion      = Bits(OUTPUT,4)
+    val m_axi_arlen           = Bits(OUTPUT,8)
+    val m_axi_arsize          = Bits(OUTPUT,3)
+    val m_axi_arburst         = Bits(OUTPUT,2)
+    val m_axi_arlock          = Bits(OUTPUT,1)
+    val m_axi_arcache         = Bits(OUTPUT,4)
+    val m_axi_arprot          = Bits(OUTPUT,3)
+    //val m_axi_arqos         = Bits(OUTPUT,4)
+    val m_axi_arvalid         = Bool(OUTPUT)
+    val m_axi_arready         = Bool(INPUT)
+    //slave interface read data ports
+    val m_axi_rready          = Bool(OUTPUT)
+    //val m_axi_rid           = Bits(INPUT,4)
+    val m_axi_rdata           = Bits(INPUT,64)
+    val m_axi_rresp           = Bits(INPUT,2)
+    val m_axi_rlast           = Bool(INPUT)
+    val m_axi_rvalid          = Bool(INPUT)
+
+    //axi lite slave for control
+    val s_axi_ctl_awaddr      = Bits(INPUT,32)
+    val s_axi_ctl_awvalid     = Bool(INPUT)
+    val s_axi_ctl_awready     = Bool(OUTPUT)
+    val s_axi_ctl_wdata       = Bits(INPUT,32)
+    val s_axi_ctl_wstrb       = Bits(INPUT,4)
+    val s_axi_ctl_wvalid      = Bool(INPUT)
+    val s_axi_ctl_wready      = Bool(OUTPUT)
+    val s_axi_ctl_bresp       = Bits(OUTPUT,2)
+    val s_axi_ctl_bvalid      = Bool(OUTPUT)
+    val s_axi_ctl_bready      = Bool(INPUT)
+    val s_axi_ctl_araddr      = Bits(INPUT,32)
+    val s_axi_ctl_arvalid     = Bool(INPUT)
+    val s_axi_ctl_arready     = Bool(OUTPUT)
+    val s_axi_ctl_rdata       = Bits(OUTPUT,32)
+    val s_axi_ctl_rresp       = Bits(OUTPUT,2)
+    val s_axi_ctl_rvalid      = Bool(OUTPUT)
+    val s_axi_ctl_rready      = Bool(INPUT)
+ }
+}
+//scalastyle:off
+
+//wrap vc707_axi_to_pcie_x1 black box in Nasti Bundles
+
+class VC707AXIToPCIeX1(implicit p:Parameters) extends LazyModule
+{
+  val slave = AXI4SlaveNode(AXI4SlavePortParameters(
+    slaves = Seq(AXI4SlaveParameters(
+      address       = List(AddressSet(0x60000000L, 0x1fffffffL)),
+      executable    = true,
+      supportsWrite = TransferSizes(1, 256),
+      supportsRead  = TransferSizes(1, 256),
+      interleavedId = Some(0))), // the Xilinx IP is friendly
+    beatBytes = 8))
+
+  val control = AXI4SlaveNode(AXI4SlavePortParameters(
+    slaves = Seq(AXI4SlaveParameters(
+      address       = List(AddressSet(0x50000000L, 0x03ffffffL)),
+      supportsWrite = TransferSizes(1, 4),
+      supportsRead  = TransferSizes(1, 4),
+      interleavedId = Some(0))), // no read interleaving b/c AXI-lite
+    beatBytes = 4))
+
+  val master = AXI4MasterNode(AXI4MasterPortParameters(
+    masters = Seq(AXI4MasterParameters(
+      id      = IdRange(0, 1),
+      aligned = false))))
+
+  lazy val module = new LazyModuleImp(this) {
+    // The master on the control port must be AXI-lite
+    require (control.edgesIn(0).master.endId == 1)
+    // Must have exactly the right number of idBits
+    require (slave.edgesIn(0).bundle.idBits == 4)
+
+    class VC707AXIToPCIeX1IOBundle extends Bundle with VC707AXIToPCIeX1IOSerial
+                                                  with VC707AXIToPCIeX1IOClocksReset;
+
+    val io = new Bundle {
+      val port = new VC707AXIToPCIeX1IOBundle
+      val slave_in = slave.bundleIn
+      val control_in = control.bundleIn
+      val master_out = master.bundleOut
+      val REFCLK = Bool(INPUT)
+      val interrupt_out = Bool(OUTPUT)
+    }
+
+    val blackbox = Module(new vc707axi_to_pcie_x1)
+
+    val s = io.slave_in(0)
+    val c = io.control_in(0)
+    val m = io.master_out(0)
+
+    //to top level
+    blackbox.io.axi_aresetn         := io.port.axi_aresetn
+    io.port.axi_aclk_out            := blackbox.io.axi_aclk_out
+    io.port.axi_ctl_aclk_out        := blackbox.io.axi_ctl_aclk_out
+    io.port.mmcm_lock               := blackbox.io.mmcm_lock
+    io.port.pci_exp_txp             := blackbox.io.pci_exp_txp
+    io.port.pci_exp_txn             := blackbox.io.pci_exp_txn
+    blackbox.io.pci_exp_rxp         := io.port.pci_exp_rxp
+    blackbox.io.pci_exp_rxn         := io.port.pci_exp_rxn
+    io.interrupt_out                := blackbox.io.interrupt_out
+    blackbox.io.REFCLK              := io.REFCLK
+
+    //s
+    //AXI4 signals ordered as per AXI4 Specification (Release D) Section A.2
+    //-{lock, cache, prot, qos} 
+    //-{aclk, aresetn, awuser, wid, wuser, buser, ruser}
+    //global signals
+    //aclk                          :=
+    //aresetn                       :=
+    //slave interface write address
+    blackbox.io.s_axi_awid          := s.aw.bits.id
+    blackbox.io.s_axi_awaddr        := s.aw.bits.addr
+    blackbox.io.s_axi_awlen         := s.aw.bits.len
+    blackbox.io.s_axi_awsize        := s.aw.bits.size
+    blackbox.io.s_axi_awburst       := s.aw.bits.burst
+    //blackbox.io.s_axi_awlock      := s.aw.bits.lock
+    //blackbox.io.s_axi_awcache     := s.aw.bits.cache
+    //blackbox.io.s_axi_awprot      := s.aw.bits.prot
+    //blackbox.io.s_axi_awqos       := s.aw.bits.qos
+    blackbox.io.s_axi_awregion      := UInt(0)
+    //blackbox.io.awuser            := s.aw.bits.user
+    blackbox.io.s_axi_awvalid       := s.aw.valid
+    s.aw.ready                   := blackbox.io.s_axi_awready
+    //slave interface write data ports
+    //blackbox.io.s_axi_wid         := s.w.bits.id
+    blackbox.io.s_axi_wdata         := s.w.bits.data
+    blackbox.io.s_axi_wstrb         := s.w.bits.strb
+    blackbox.io.s_axi_wlast         := s.w.bits.last
+    //blackbox.io.s_axi_wuser       := s.w.bits.user
+    blackbox.io.s_axi_wvalid        := s.w.valid
+    s.w.ready                    := blackbox.io.s_axi_wready
+    //slave interface write response
+    s.b.bits.id                  := blackbox.io.s_axi_bid
+    s.b.bits.resp                := blackbox.io.s_axi_bresp
+    //s.b.bits.user              := blackbox.io.s_axi_buser
+    s.b.valid                    := blackbox.io.s_axi_bvalid
+    blackbox.io.s_axi_bready        := s.b.ready
+    //slave AXI interface read address ports
+    blackbox.io.s_axi_arid          := s.ar.bits.id
+    blackbox.io.s_axi_araddr        := s.ar.bits.addr
+    blackbox.io.s_axi_arlen         := s.ar.bits.len
+    blackbox.io.s_axi_arsize        := s.ar.bits.size
+    blackbox.io.s_axi_arburst       := s.ar.bits.burst
+    //blackbox.io.s_axi_arlock      := s.ar.bits.lock
+    //blackbox.io.s_axi_arcache     := s.ar.bits.cache
+    //blackbox.io.s_axi_arprot      := s.ar.bits.prot
+    //blackbox.io.s_axi_arqos       := s.ar.bits.qos
+    blackbox.io.s_axi_arregion      := UInt(0)
+    //blackbox.io.s_axi_aruser      := s.ar.bits.user
+    blackbox.io.s_axi_arvalid       := s.ar.valid
+    s.ar.ready                   := blackbox.io.s_axi_arready
+    //slave AXI interface read data ports
+    s.r.bits.id                  := blackbox.io.s_axi_rid
+    s.r.bits.data                := blackbox.io.s_axi_rdata
+    s.r.bits.resp                := blackbox.io.s_axi_rresp
+    s.r.bits.last                := blackbox.io.s_axi_rlast
+    //s.r.bits.ruser             := blackbox.io.s_axi_ruser
+    s.r.valid                    := blackbox.io.s_axi_rvalid
+    blackbox.io.s_axi_rready        := s.r.ready
+
+    //ctl
+    //axi-lite slave interface write address
+    blackbox.io.s_axi_ctl_awaddr    := c.aw.bits.addr
+    blackbox.io.s_axi_ctl_awvalid   := c.aw.valid
+    c.aw.ready                 := blackbox.io.s_axi_ctl_awready
+    //axi-lite slave interface write data ports
+    blackbox.io.s_axi_ctl_wdata     := c.w.bits.data
+    blackbox.io.s_axi_ctl_wstrb     := c.w.bits.strb
+    blackbox.io.s_axi_ctl_wvalid    := c.w.valid
+    c.w.ready                  := blackbox.io.s_axi_ctl_wready
+    //axi-lite slave interface write response
+    blackbox.io.s_axi_ctl_bready    := c.b.ready
+    c.b.bits.id                := UInt(0)
+    c.b.bits.resp              := blackbox.io.s_axi_ctl_bresp
+    c.b.valid                  := blackbox.io.s_axi_ctl_bvalid
+    //axi-lite slave AXI interface read address ports
+    blackbox.io.s_axi_ctl_araddr    := c.ar.bits.addr
+    blackbox.io.s_axi_ctl_arvalid   := c.ar.valid
+    c.ar.ready                 := blackbox.io.s_axi_ctl_arready
+    //slave AXI interface read data ports
+    blackbox.io.s_axi_ctl_rready    := c.r.ready
+    c.r.bits.id                := UInt(0)
+    c.r.bits.data              := blackbox.io.s_axi_ctl_rdata
+    c.r.bits.resp              := blackbox.io.s_axi_ctl_rresp
+    c.r.bits.last              := Bool(true)
+    c.r.valid                  := blackbox.io.s_axi_ctl_rvalid
+
+    //m
+    //AXI4 signals ordered per AXI4 Specification (Release D) Section A.2
+    //-{id,region,qos}
+    //-{aclk, aresetn, awuser, wid, wuser, buser, ruser}
+    //global signals
+    //aclk                          :=
+    //aresetn                       :=
+    //master interface write address
+    m.aw.bits.id                 := UInt(0)
+    m.aw.bits.addr               := blackbox.io.m_axi_awaddr
+    m.aw.bits.len                := blackbox.io.m_axi_awlen
+    m.aw.bits.size               := blackbox.io.m_axi_awsize
+    m.aw.bits.burst              := blackbox.io.m_axi_awburst
+    m.aw.bits.lock               := blackbox.io.m_axi_awlock
+    m.aw.bits.cache              := blackbox.io.m_axi_awcache
+    m.aw.bits.prot               := blackbox.io.m_axi_awprot
+    m.aw.bits.qos                := UInt(0)
+    //m.aw.bits.region           := blackbox.io.m_axi_awregion
+    //m.aw.bits.user             := blackbox.io.m_axi_awuser
+    m.aw.valid                   := blackbox.io.m_axi_awvalid
+    blackbox.io.m_axi_awready    := m.aw.ready
+
+    //master interface write data ports
+    m.w.bits.data                := blackbox.io.m_axi_wdata
+    m.w.bits.strb                := blackbox.io.m_axi_wstrb
+    m.w.bits.last                := blackbox.io.m_axi_wlast
+    //m.w.bits.user              := blackbox.io.m_axi_wuser
+    m.w.valid                    := blackbox.io.m_axi_wvalid
+    blackbox.io.m_axi_wready     := m.w.ready
+
+    //master interface write response
+    //blackbox.io.m_axi_bid      := m.b.bits.id
+    blackbox.io.m_axi_bresp      := m.b.bits.resp
+    //blackbox.io.m_axi_buser    := m.b.bits.user
+    blackbox.io.m_axi_bvalid     := m.b.valid
+    m.b.ready                    := blackbox.io.m_axi_bready
+
+    //master AXI interface read address ports
+    m.ar.bits.id                 := UInt(0)
+    m.ar.bits.addr               := blackbox.io.m_axi_araddr
+    m.ar.bits.len                := blackbox.io.m_axi_arlen
+    m.ar.bits.size               := blackbox.io.m_axi_arsize
+    m.ar.bits.burst              := blackbox.io.m_axi_arburst
+    m.ar.bits.lock               := blackbox.io.m_axi_arlock
+    m.ar.bits.cache              := blackbox.io.m_axi_arcache
+    m.ar.bits.prot               := blackbox.io.m_axi_arprot
+    m.ar.bits.qos                := UInt(0)
+    //m.ar.bits.region           := blackbox.io.m_axi_arregion
+    //m.ar.bits.user             := blackbox.io.s_axi_aruser
+    m.ar.valid                   := blackbox.io.m_axi_arvalid
+    blackbox.io.m_axi_arready    := m.ar.ready
+
+    //master AXI interface read data ports
+    //blackbox.io.m_axi_rid      := m.r.bits.id
+    blackbox.io.m_axi_rdata      := m.r.bits.data
+    blackbox.io.m_axi_rresp      := m.r.bits.resp
+    blackbox.io.m_axi_rlast      := m.r.bits.last
+    //blackbox.io.s_axi_ruser    := s.bits.ruser
+    blackbox.io.m_axi_rvalid     := m.r.valid
+    m.r.ready                    := blackbox.io.m_axi_rready
+  }
+}
diff --git a/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala b/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala
new file mode 100644 (file)
index 0000000..923956b
--- /dev/null
@@ -0,0 +1,110 @@
+// See LICENSE for license details.
+package sifive.blocks.ip.xilinx.vc707mig
+
+import Chisel._
+import config._
+import junctions._
+
+// IP VLNV: xilinx.com:customize_ip:vc707mig:1.0
+// Black Box
+// Signals named _exactly_ as per MIG generated verilog
+
+trait VC707MIGUnidirectionalIODDR extends Bundle {
+  //outputs
+  val ddr3_addr             = Bits(OUTPUT,14)
+  val ddr3_ba               = Bits(OUTPUT,3)
+  val ddr3_ras_n            = Bool(OUTPUT)
+  val ddr3_cas_n            = Bool(OUTPUT)
+  val ddr3_we_n             = Bool(OUTPUT)
+  val ddr3_reset_n          = Bool(OUTPUT)
+  val ddr3_ck_p             = Bits(OUTPUT,1)
+  val ddr3_ck_n             = Bits(OUTPUT,1)
+  val ddr3_cke              = Bits(OUTPUT,1)
+  val ddr3_cs_n             = Bits(OUTPUT,1)
+  val ddr3_dm               = Bits(OUTPUT,8)
+  val ddr3_odt              = Bits(OUTPUT,1)
+}
+
+//reused directly in io bundle for sifive.blocks.devices.xilinxvc707mig
+trait VC707MIGUnidirectionalIOClocksReset extends Bundle {
+  //inputs
+  //differential system clocks
+  val sys_clk_n             = Bool(INPUT)
+  val sys_clk_p             = Bool(INPUT)
+  //user interface signals
+  val ui_clk                = Clock(OUTPUT)
+  val ui_clk_sync_rst       = Bool(OUTPUT)
+  val mmcm_locked           = Bool(OUTPUT)
+  val aresetn               = Bool(INPUT)
+  //misc
+  val init_calib_complete   = Bool(OUTPUT)
+  val sys_rst               = Bool(INPUT)
+}
+
+//scalastyle:off
+//turn off linter: blackbox name must match verilog module 
+class vc707mig(implicit val p:Parameters) extends BlackBox
+{
+  val io = new Bundle with VC707MIGUnidirectionalIODDR
+                      with VC707MIGUnidirectionalIOClocksReset {
+    // bidirectional signals on blackbox interface
+    // defined here as an output so "__inout" signal name does not have to be used
+    // verilog does not check the
+    val ddr3_dq               = Bits(OUTPUT,64)
+    val ddr3_dqs_n            = Bits(OUTPUT,8)
+    val ddr3_dqs_p            = Bits(OUTPUT,8)
+    // User interface signals
+    val app_sr_req            = Bool(INPUT)
+    val app_ref_req           = Bool(INPUT)
+    val app_zq_req            = Bool(INPUT)
+    val app_sr_active         = Bool(OUTPUT)
+    val app_ref_ack           = Bool(OUTPUT)
+    val app_zq_ack            = Bool(OUTPUT)
+    //axi_s
+    //slave interface write address ports
+    val s_axi_awid            = Bits(INPUT,4)
+    val s_axi_awaddr          = Bits(INPUT,30)
+    val s_axi_awlen           = Bits(INPUT,8)
+    val s_axi_awsize          = Bits(INPUT,3)
+    val s_axi_awburst         = Bits(INPUT,2)
+    val s_axi_awlock          = Bits(INPUT,1)
+    val s_axi_awcache         = Bits(INPUT,4)
+    val s_axi_awprot          = Bits(INPUT,3)
+    val s_axi_awqos           = Bits(INPUT,4)
+    val s_axi_awvalid         = Bool(INPUT)
+    val s_axi_awready         = Bool(OUTPUT)
+    //slave interface write data ports
+    val s_axi_wdata           = Bits(INPUT,64)
+    val s_axi_wstrb           = Bits(INPUT,8)
+    val s_axi_wlast           = Bool(INPUT)
+    val s_axi_wvalid          = Bool(INPUT)
+    val s_axi_wready          = Bool(OUTPUT)
+    //slave interface write response ports
+    val s_axi_bready          = Bool(INPUT)
+    val s_axi_bid             = Bits(OUTPUT,4)
+    val s_axi_bresp           = Bits(OUTPUT,2)
+    val s_axi_bvalid          = Bool(OUTPUT)
+    //slave interface read address ports
+    val s_axi_arid            = Bits(INPUT,4)
+    val s_axi_araddr          = Bits(INPUT,30)
+    val s_axi_arlen           = Bits(INPUT,8)
+    val s_axi_arsize          = Bits(INPUT,3)
+    val s_axi_arburst         = Bits(INPUT,2)
+    val s_axi_arlock          = Bits(INPUT,1)
+    val s_axi_arcache         = Bits(INPUT,4)
+    val s_axi_arprot          = Bits(INPUT,3)
+    val s_axi_arqos           = Bits(INPUT,4)
+    val s_axi_arvalid         = Bool(INPUT)
+    val s_axi_arready         = Bool(OUTPUT)
+    //slave interface read data ports
+    val s_axi_rready          = Bool(INPUT)
+    val s_axi_rid             = Bits(OUTPUT,4)
+    val s_axi_rdata           = Bits(OUTPUT,64)
+    val s_axi_rresp           = Bits(OUTPUT,2)
+    val s_axi_rlast           = Bool(OUTPUT)
+    val s_axi_rvalid          = Bool(OUTPUT)
+    //misc
+    val device_temp           = Bits(OUTPUT,12)
+  }
+}
+//scalastyle:on
diff --git a/src/main/scala/util/DeglitchShiftRegister.scala b/src/main/scala/util/DeglitchShiftRegister.scala
new file mode 100644 (file)
index 0000000..e40de96
--- /dev/null
@@ -0,0 +1,28 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+
+//Allows us to specify a different clock for a shift register
+// and to force input to be high for > 1 cycle.
+class DeglitchShiftRegister(shift: Int) extends Module {
+  val io = new Bundle {
+    val d = Bool(INPUT)
+    val q = Bool(OUTPUT)
+  }
+  val sync = ShiftRegister(io.d, shift)
+  val last = ShiftRegister(sync, 1)
+  io.q := sync & last
+}
+
+object DeglitchShiftRegister {
+  def apply (shift: Int, d: Bool, clock: Clock,
+    name: Option[String] = None): Bool = {
+    val deglitch = Module (new DeglitchShiftRegister(shift))
+    name.foreach(deglitch.suggestName(_))
+    deglitch.clock := clock
+    deglitch.reset := Bool(false)
+    deglitch.io.d := d
+    deglitch.io.q
+  }
+}
diff --git a/src/main/scala/util/RegMapFIFO.scala b/src/main/scala/util/RegMapFIFO.scala
new file mode 100644 (file)
index 0000000..aaeba59
--- /dev/null
@@ -0,0 +1,41 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+import regmapper._
+
+// MSB indicates full status
+object NonBlockingEnqueue {
+  def apply(enq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
+    val enqWidth = enq.bits.getWidth
+    require(enqWidth > 0)
+    require(regWidth > enqWidth)
+    Seq(
+      RegField(enqWidth,
+        RegReadFn(UInt(0)),
+        RegWriteFn((valid, data) => {
+          enq.valid := valid
+          enq.bits := data
+          Bool(true)
+        })),
+      RegField(regWidth - enqWidth - 1),
+      RegField.r(1, !enq.ready))
+  }
+}
+
+// MSB indicates empty status
+object NonBlockingDequeue {
+  def apply(deq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
+    val deqWidth = deq.bits.getWidth
+    require(deqWidth > 0)
+    require(regWidth > deqWidth)
+    Seq(
+      RegField.r(deqWidth,
+        RegReadFn(ready => {
+          deq.ready := ready
+          (Bool(true), deq.bits)
+        })),
+      RegField(regWidth - deqWidth - 1),
+      RegField.r(1, !deq.valid))
+  }
+}
diff --git a/src/main/scala/util/ResetCatchAndSync.scala b/src/main/scala/util/ResetCatchAndSync.scala
new file mode 100644 (file)
index 0000000..cc35686
--- /dev/null
@@ -0,0 +1,42 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+import util.AsyncResetRegVec
+
+/** Reset: asynchronous assert,
+  *  synchronous de-assert
+  *
+  */
+
+class ResetCatchAndSync (sync: Int = 3) extends Module {
+
+  val io = new Bundle {
+    val sync_reset = Bool(OUTPUT)
+  }
+
+  val reset_n_catch_reg = Module (new AsyncResetRegVec(sync, 0))
+
+  reset_n_catch_reg.io.en := Bool(true)
+  reset_n_catch_reg.io.d  := Cat(Bool(true), reset_n_catch_reg.io.q >> 1)
+
+  io.sync_reset := ~reset_n_catch_reg.io.q(0)
+
+}
+
+object ResetCatchAndSync {
+
+  def apply(clk: Clock, rst: Bool, sync: Int = 3, name: Option[String] = None): Bool = {
+
+    val catcher = Module (new ResetCatchAndSync(sync))
+    if (name.isDefined) {catcher.suggestName(name.get)}
+    catcher.clock := clk
+    catcher.reset := rst
+
+    catcher.io.sync_reset
+  }
+
+  def apply(clk: Clock, rst: Bool, sync: Int, name: String): Bool = apply(clk, rst, sync, Some(name))
+  def apply(clk: Clock, rst: Bool, name: String): Bool = apply(clk, rst, name = Some(name))
+
+}
diff --git a/src/main/scala/util/SRLatch.scala b/src/main/scala/util/SRLatch.scala
new file mode 100644 (file)
index 0000000..95fae4f
--- /dev/null
@@ -0,0 +1,12 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+
+class SRLatch extends BlackBox {
+  val io = new Bundle {
+    val set = Bool(INPUT)
+    val reset = Bool(INPUT)
+    val q = Bool(OUTPUT)
+  }
+}
diff --git a/src/main/scala/util/ShiftReg.scala b/src/main/scala/util/ShiftReg.scala
new file mode 100644 (file)
index 0000000..53bb29e
--- /dev/null
@@ -0,0 +1,11 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+
+object ShiftRegisterInit {
+  def apply[T <: Data](in: T, n: Int, init: T): T =
+    (0 until n).foldLeft(in) {
+      case (next, _) => Reg(next, next = next, init = init)
+    }
+}
diff --git a/src/main/scala/util/Timer.scala b/src/main/scala/util/Timer.scala
new file mode 100644 (file)
index 0000000..e0cba87
--- /dev/null
@@ -0,0 +1,104 @@
+// See LICENSE for license details.
+package sifive.blocks.util
+
+import Chisel._
+import Chisel.ImplicitConversions._
+import regmapper._
+import util.WideCounter
+
+class SlaveRegIF(w: Int) extends Bundle {
+  val write = Valid(UInt(width = w)).flip
+  val read = UInt(OUTPUT, w)
+
+  override def cloneType: this.type = new SlaveRegIF(w).asInstanceOf[this.type]
+
+  def toRegField(dummy: Int = 0): RegField = {
+    def writeFn(valid: Bool, data: UInt): Bool = {
+      write.valid := valid
+      write.bits := data
+      Bool(true)
+    }
+    RegField(w, RegReadFn(read), RegWriteFn((v, d) => writeFn(v, d)))
+  }
+}
+
+
+abstract class GenericTimer extends Module {
+  protected def countWidth: Int
+  protected def cmpWidth: Int
+  protected def ncmp: Int
+  protected def countAlways: Bool
+  protected def countEn: Bool
+  protected def feed: Bool
+  protected def ip: UInt
+  protected def countAwake: Bool = Bool(false)
+  protected def unlocked: Bool = Bool(true)
+  protected def rsten: Bool = Bool(false)
+  protected def deglitch: Bool = Bool(false)
+  protected def sticky: Bool = Bool(false)
+  protected def oneShot: Bool = Bool(false)
+  protected def center: UInt = UInt(0)
+  protected def gang: UInt = UInt(0)
+  protected val scaleWidth = 4
+  protected val regWidth = 32
+  val maxcmp = 4
+  require(ncmp <= maxcmp)
+
+  class GenericTimerIO extends Bundle {
+    val regs = new Bundle {
+      val cfg = new SlaveRegIF(regWidth)
+      val countLo = new SlaveRegIF(regWidth)
+      val countHi = new SlaveRegIF(regWidth)
+      val s = new SlaveRegIF(cmpWidth)
+      val cmp = Vec(ncmp, new SlaveRegIF(cmpWidth))
+      val feed = new SlaveRegIF(regWidth)
+      val key = new SlaveRegIF(regWidth)
+    }
+    val ip = Vec(ncmp, Bool()).asOutput
+  }
+
+  def io: GenericTimerIO
+
+  protected val scale = RegEnable(io.regs.cfg.write.bits(scaleWidth-1, 0), io.regs.cfg.write.valid && unlocked)
+  protected lazy val zerocmp = RegEnable(io.regs.cfg.write.bits(9), io.regs.cfg.write.valid && unlocked)
+  protected val cmp = io.regs.cmp.map(c => RegEnable(c.write.bits, c.write.valid && unlocked))
+
+  protected val count = WideCounter(countWidth, countEn, reset = false)
+  when (io.regs.countLo.write.valid && unlocked) { count := Cat(count >> regWidth, io.regs.countLo.write.bits) }
+  if (countWidth > regWidth) when (io.regs.countHi.write.valid && unlocked) { count := Cat(io.regs.countHi.write.bits, count(regWidth-1, 0)) }
+
+  // generate periodic interrupt
+  protected val s = (count >> scale)(cmpWidth-1, 0)
+  // reset counter when fed or elapsed
+  protected val elapsed =
+    for (i <- 0 until ncmp)
+      yield Mux(s(cmpWidth-1) && center(i), ~s, s) >= cmp(i)
+  protected val countReset = feed || (zerocmp && elapsed(0))
+  when (countReset) { count := 0 }
+
+  io.regs.cfg.read := Cat(ip, gang | UInt(0, maxcmp), UInt(0, maxcmp), center | UInt(0, maxcmp),
+                          UInt(0, 2), countAwake || oneShot, countAlways, UInt(0, 1), deglitch, zerocmp, rsten || sticky, UInt(0, 8-scaleWidth), scale)
+  io.regs.countLo.read := count
+  io.regs.countHi.read := count >> regWidth
+  io.regs.s.read := s
+  (io.regs.cmp zip cmp) map { case (r, c) => r.read := c }
+  io.regs.feed.read := 0
+  io.regs.key.read := unlocked
+  io.ip := io.ip.fromBits(ip)
+}
+
+
+object GenericTimer {
+  def timerRegMap(t: GenericTimer, offset: Int, regBytes: Int): Seq[(Int, Seq[RegField])] = {
+    val regs = Seq(
+      0 -> t.io.regs.cfg,
+      2 -> t.io.regs.countLo,
+      3 -> t.io.regs.countHi,
+      4 -> t.io.regs.s,
+      6 -> t.io.regs.feed,
+      7 -> t.io.regs.key)
+    val cmpRegs = t.io.regs.cmp.zipWithIndex map { case (r, i) => (8 + i) -> r }
+    for ((i, r) <- (regs ++ cmpRegs))
+      yield (offset + regBytes*i) -> Seq(r.toRegField())
+  }
+}
diff --git a/vsrc/SRLatch.v b/vsrc/SRLatch.v
new file mode 100644 (file)
index 0000000..d4849a1
--- /dev/null
@@ -0,0 +1,22 @@
+// See LICENSE for license details.
+module SRLatch (
+  input set,
+  input reset,
+  output q
+);
+
+  reg latch;
+
+  // synopsys async_set_reset "set"
+  // synopsys one_hot "set, reset"
+  always @(set or reset)
+  begin
+    if (set)
+      latch <= 1'b1;
+    else if (reset)
+      latch <= 1'b0;
+  end
+
+  assign q = latch;
+
+endmodule
diff --git a/vsrc/vc707reset.v b/vsrc/vc707reset.v
new file mode 100644 (file)
index 0000000..8501027
--- /dev/null
@@ -0,0 +1,78 @@
+// See LICENSE for license details.
+`timescale 1ns/1ps
+`default_nettype none
+`define RESET_SYNC 4
+`define DEBOUNCE_BITS 8
+
+module vc707reset(
+  // Asynchronous reset input, should be held high until
+  // all clocks are locked and power is stable.
+  input  wire areset,
+  // Clock domains are brought up in increasing order
+  // All clocks are reset for at least 2^DEBOUNCE_BITS * period(clock1)
+  input  wire clock1,
+  output wire reset1,
+  input  wire clock2,
+  output wire reset2,
+  input  wire clock3,
+  output wire reset3,
+  input  wire clock4,
+  output wire reset4
+);
+  sifive_reset_hold hold_clock0(areset, clock1, reset1);
+  sifive_reset_sync sync_clock2(reset1, clock2, reset2);
+  sifive_reset_sync sync_clock3(reset2, clock3, reset3);
+  sifive_reset_sync sync_clock4(reset3, clock4, reset4);
+endmodule
+
+// Assumes that areset is held for more than one clock
+// Allows areset to be deasserted asynchronously
+module sifive_reset_sync(
+  input  wire areset,
+  input  wire clock,
+  output wire reset
+);
+  reg [`RESET_SYNC-1:0] gen_reset = {`RESET_SYNC{1'b1}};
+  always @(posedge clock, posedge areset) begin
+    if (areset) begin
+      gen_reset <= {`RESET_SYNC{1'b1}};
+    end else begin
+      gen_reset <= {1'b0,gen_reset[`RESET_SYNC-1:1]};
+    end
+  end
+  assign reset = gen_reset[0];
+endmodule
+
+module sifive_reset_hold(
+  input  wire areset,
+  input  wire clock,
+  output wire reset
+);
+  wire raw_reset;
+  reg [`RESET_SYNC-1:0] sync_reset = {`RESET_SYNC{1'b1}};
+  reg [`DEBOUNCE_BITS:0] debounce_reset = {`DEBOUNCE_BITS{1'b1}};
+  wire out_reset;
+
+  // Captures reset even if clock is not running
+  sifive_reset_sync capture(areset, clock, raw_reset);
+
+  // Remove any glitches due to runt areset
+  always @(posedge clock) begin
+    sync_reset <= {raw_reset,sync_reset[`RESET_SYNC-1:1]};
+  end
+
+  // Debounce the reset
+  assign out_reset = debounce_reset[`DEBOUNCE_BITS];
+  always @(posedge clock) begin
+    if (sync_reset[0]) begin
+      debounce_reset <= {(`DEBOUNCE_BITS+1){1'b1}};
+    end else begin
+      debounce_reset <= debounce_reset - out_reset;
+    end
+  end
+
+  assign reset = out_reset;
+
+endmodule
+
+`default_nettype wire