Initial commit.
This commit is contained in:
40
src/main/scala/devices/spi/SPIArbiter.scala
Normal file
40
src/main/scala/devices/spi/SPIArbiter.scala
Normal file
@ -0,0 +1,40 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIInnerIO(c: SPIConfigBase) extends SPILinkIO(c) {
|
||||
val lock = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
class SPIArbiter(c: SPIConfigBase, n: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val inner = Vec(n, new SPIInnerIO(c)).flip
|
||||
val outer = new SPILinkIO(c)
|
||||
val sel = UInt(INPUT, log2Up(n))
|
||||
}
|
||||
|
||||
val sel = Reg(init = Vec(Bool(true) +: Seq.fill(n-1)(Bool(false))))
|
||||
|
||||
io.outer.tx.valid := Mux1H(sel, io.inner.map(_.tx.valid))
|
||||
io.outer.tx.bits := Mux1H(sel, io.inner.map(_.tx.bits))
|
||||
io.outer.cnt := Mux1H(sel, io.inner.map(_.cnt))
|
||||
io.outer.fmt := Mux1H(sel, io.inner.map(_.fmt))
|
||||
io.outer.cs := Mux1H(sel, io.inner.map(_.cs))
|
||||
|
||||
(io.inner zip sel).foreach { case (inner, s) =>
|
||||
inner.tx.ready := io.outer.tx.ready && s
|
||||
inner.rx.valid := io.outer.rx.valid && s
|
||||
inner.rx.bits := io.outer.rx.bits
|
||||
inner.active := io.outer.active && s
|
||||
}
|
||||
|
||||
val nsel = Vec.tabulate(n)(io.sel === UInt(_))
|
||||
val lock = Mux1H(sel, io.inner.map(_.lock))
|
||||
when (!lock) {
|
||||
sel := nsel
|
||||
when (sel.asUInt =/= nsel.asUInt) {
|
||||
io.outer.cs.clear := Bool(true)
|
||||
}
|
||||
}
|
||||
}
|
106
src/main/scala/devices/spi/SPIBundle.scala
Normal file
106
src/main/scala/devices/spi/SPIBundle.scala
Normal file
@ -0,0 +1,106 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
abstract class SPIBundle(val c: SPIConfigBase) extends Bundle {
|
||||
override def cloneType: SPIBundle.this.type =
|
||||
this.getClass.getConstructors.head.newInstance(c).asInstanceOf[this.type]
|
||||
}
|
||||
|
||||
class SPIDataIO extends Bundle {
|
||||
val i = Bool(INPUT)
|
||||
val o = Bool(OUTPUT)
|
||||
val oe = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
class SPIPortIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = Bool(OUTPUT)
|
||||
val dq = Vec(4, new SPIDataIO)
|
||||
val cs = Vec(c.csWidth, Bool(OUTPUT))
|
||||
}
|
||||
|
||||
trait HasSPIProtocol {
|
||||
val proto = Bits(width = SPIProtocol.width)
|
||||
}
|
||||
trait HasSPIEndian {
|
||||
val endian = Bits(width = SPIEndian.width)
|
||||
}
|
||||
class SPIFormat(c: SPIConfigBase) extends SPIBundle(c)
|
||||
with HasSPIProtocol
|
||||
with HasSPIEndian {
|
||||
val iodir = Bits(width = SPIDirection.width)
|
||||
}
|
||||
|
||||
trait HasSPILength extends SPIBundle {
|
||||
val len = UInt(width = c.lengthBits)
|
||||
}
|
||||
|
||||
class SPIClocking(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val div = UInt(width = c.divisorBits)
|
||||
val pol = Bool()
|
||||
val pha = Bool()
|
||||
}
|
||||
|
||||
class SPIChipSelect(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val id = UInt(width = c.csIdBits)
|
||||
val dflt = Vec(c.csWidth, Bool())
|
||||
|
||||
def toggle(en: Bool): Vec[Bool] = {
|
||||
val mask = en << id
|
||||
val out = Cat(dflt.reverse) ^ mask
|
||||
Vec.tabulate(c.csWidth)(out(_))
|
||||
}
|
||||
}
|
||||
|
||||
trait HasSPICSMode {
|
||||
val mode = Bits(width = SPICSMode.width)
|
||||
}
|
||||
|
||||
class SPIDelay(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val cssck = UInt(width = c.delayBits)
|
||||
val sckcs = UInt(width = c.delayBits)
|
||||
val intercs = UInt(width = c.delayBits)
|
||||
val interxfr = UInt(width = c.delayBits)
|
||||
}
|
||||
|
||||
class SPIWatermark(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val tx = UInt(width = c.txDepthBits)
|
||||
val rx = UInt(width = c.rxDepthBits)
|
||||
}
|
||||
|
||||
class SPIControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fmt = new SPIFormat(c) with HasSPILength
|
||||
val sck = new SPIClocking(c)
|
||||
val cs = new SPIChipSelect(c) with HasSPICSMode
|
||||
val dla = new SPIDelay(c)
|
||||
val wm = new SPIWatermark(c)
|
||||
}
|
||||
|
||||
object SPIControl {
|
||||
def init(c: SPIConfigBase): SPIControl = {
|
||||
val ctrl = Wire(new SPIControl(c))
|
||||
ctrl.fmt.proto := SPIProtocol.Single
|
||||
ctrl.fmt.iodir := SPIDirection.Rx
|
||||
ctrl.fmt.endian := SPIEndian.MSB
|
||||
ctrl.fmt.len := UInt(math.min(c.frameBits, 8))
|
||||
ctrl.sck.div := UInt(3)
|
||||
ctrl.sck.pol := Bool(false)
|
||||
ctrl.sck.pha := Bool(false)
|
||||
ctrl.cs.id := UInt(0)
|
||||
ctrl.cs.dflt.foreach { _ := Bool(true) }
|
||||
ctrl.cs.mode := SPICSMode.Auto
|
||||
ctrl.dla.cssck := UInt(1)
|
||||
ctrl.dla.sckcs := UInt(1)
|
||||
ctrl.dla.intercs := UInt(1)
|
||||
ctrl.dla.interxfr := UInt(0)
|
||||
ctrl.wm.tx := UInt(0)
|
||||
ctrl.wm.rx := UInt(0)
|
||||
ctrl
|
||||
}
|
||||
}
|
||||
|
||||
class SPIInterrupts extends Bundle {
|
||||
val txwm = Bool()
|
||||
val rxwm = Bool()
|
||||
}
|
33
src/main/scala/devices/spi/SPIConsts.scala
Normal file
33
src/main/scala/devices/spi/SPIConsts.scala
Normal file
@ -0,0 +1,33 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
object SPIProtocol {
|
||||
val width = 2
|
||||
val Single = UInt(0, width)
|
||||
val Dual = UInt(1, width)
|
||||
val Quad = UInt(2, width)
|
||||
|
||||
val cases = Seq(Single, Dual, Quad)
|
||||
def decode(x: UInt): Seq[Bool] = cases.map(_ === x)
|
||||
}
|
||||
|
||||
object SPIDirection {
|
||||
val width = 1
|
||||
val Rx = UInt(0, width)
|
||||
val Tx = UInt(1, width)
|
||||
}
|
||||
|
||||
object SPIEndian {
|
||||
val width = 1
|
||||
val MSB = UInt(0, width)
|
||||
val LSB = UInt(1, width)
|
||||
}
|
||||
|
||||
object SPICSMode {
|
||||
val width = 2
|
||||
val Auto = UInt(0, width)
|
||||
val Hold = UInt(2, width)
|
||||
val Off = UInt(3, width)
|
||||
}
|
62
src/main/scala/devices/spi/SPIFIFO.scala
Normal file
62
src/main/scala/devices/spi/SPIFIFO.scala
Normal file
@ -0,0 +1,62 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIFIFOControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fmt = new SPIFormat(c) with HasSPILength
|
||||
val cs = new Bundle with HasSPICSMode
|
||||
val wm = new SPIWatermark(c)
|
||||
}
|
||||
|
||||
class SPIFIFO(c: SPIConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val ctrl = new SPIFIFOControl(c).asInput
|
||||
val link = new SPIInnerIO(c)
|
||||
val tx = Decoupled(Bits(width = c.frameBits)).flip
|
||||
val rx = Decoupled(Bits(width = c.frameBits))
|
||||
val ip = new SPIInterrupts().asOutput
|
||||
}
|
||||
|
||||
val txq = Module(new Queue(io.tx.bits, c.txDepth))
|
||||
val rxq = Module(new Queue(io.rx.bits, c.rxDepth))
|
||||
|
||||
txq.io.enq <> io.tx
|
||||
io.link.tx <> txq.io.deq
|
||||
|
||||
val fire_tx = io.link.tx.fire()
|
||||
val fire_rx = io.link.rx.fire()
|
||||
val rxen = Reg(init = Bool(false))
|
||||
|
||||
rxq.io.enq.valid := io.link.rx.valid && rxen
|
||||
rxq.io.enq.bits := io.link.rx.bits
|
||||
io.rx <> rxq.io.deq
|
||||
|
||||
when (fire_rx) {
|
||||
rxen := Bool(false)
|
||||
}
|
||||
when (fire_tx) {
|
||||
rxen := (io.link.fmt.iodir === SPIDirection.Rx)
|
||||
}
|
||||
|
||||
val proto = SPIProtocol.decode(io.link.fmt.proto).zipWithIndex
|
||||
val cnt_quot = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len >> i) })
|
||||
val cnt_rmdr = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len(i, 0).orR) })
|
||||
io.link.fmt <> io.ctrl.fmt
|
||||
io.link.cnt := cnt_quot + cnt_rmdr
|
||||
|
||||
val cs_mode = RegNext(io.ctrl.cs.mode, SPICSMode.Auto)
|
||||
val cs_mode_hold = (cs_mode === SPICSMode.Hold)
|
||||
val cs_mode_off = (cs_mode === SPICSMode.Off)
|
||||
val cs_update = (cs_mode =/= io.ctrl.cs.mode)
|
||||
val cs_clear = !(cs_mode_hold || cs_mode_off)
|
||||
|
||||
io.link.cs.set := !cs_mode_off
|
||||
io.link.cs.clear := cs_update || (fire_tx && cs_clear)
|
||||
io.link.cs.hold := Bool(false)
|
||||
|
||||
io.link.lock := io.link.tx.valid || rxen
|
||||
|
||||
io.ip.txwm := (txq.io.count < io.ctrl.wm.tx)
|
||||
io.ip.rxwm := (rxq.io.count > io.ctrl.wm.rx)
|
||||
}
|
162
src/main/scala/devices/spi/SPIFlash.scala
Normal file
162
src/main/scala/devices/spi/SPIFlash.scala
Normal file
@ -0,0 +1,162 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPIFlashInsn(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val cmd = new Bundle with HasSPIProtocol {
|
||||
val code = Bits(width = c.insnCmdBits)
|
||||
val en = Bool()
|
||||
}
|
||||
val addr = new Bundle with HasSPIProtocol {
|
||||
val len = UInt(width = c.insnAddrLenBits)
|
||||
}
|
||||
val pad = new Bundle {
|
||||
val code = Bits(width = c.frameBits)
|
||||
val cnt = Bits(width = c.insnPadLenBits)
|
||||
}
|
||||
val data = new Bundle with HasSPIProtocol
|
||||
}
|
||||
|
||||
class SPIFlashControl(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val insn = new SPIFlashInsn(c)
|
||||
val fmt = new Bundle with HasSPIEndian
|
||||
}
|
||||
|
||||
object SPIFlashInsn {
|
||||
def init(c: SPIFlashConfigBase): SPIFlashInsn = {
|
||||
val insn = Wire(new SPIFlashInsn(c))
|
||||
insn.cmd.en := Bool(true)
|
||||
insn.cmd.code := Bits(0x03)
|
||||
insn.cmd.proto := SPIProtocol.Single
|
||||
insn.addr.len := UInt(3)
|
||||
insn.addr.proto := SPIProtocol.Single
|
||||
insn.pad.cnt := UInt(0)
|
||||
insn.pad.code := Bits(0)
|
||||
insn.data.proto := SPIProtocol.Single
|
||||
insn
|
||||
}
|
||||
}
|
||||
|
||||
class SPIFlashAddr(c: SPIFlashConfigBase) extends SPIBundle(c) {
|
||||
val next = UInt(width = c.insnAddrBits)
|
||||
val hold = UInt(width = c.insnAddrBits)
|
||||
}
|
||||
|
||||
class SPIFlashMap(c: SPIFlashConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val en = Bool(INPUT)
|
||||
val ctrl = new SPIFlashControl(c).asInput
|
||||
val addr = Decoupled(new SPIFlashAddr(c)).flip
|
||||
val data = Decoupled(UInt(width = c.frameBits))
|
||||
val link = new SPIInnerIO(c)
|
||||
}
|
||||
|
||||
val addr = io.addr.bits.hold + UInt(1)
|
||||
val merge = io.link.active && (io.addr.bits.next === addr)
|
||||
|
||||
private val insn = io.ctrl.insn
|
||||
io.link.tx.valid := Bool(true)
|
||||
io.link.fmt.proto := insn.addr.proto
|
||||
io.link.fmt.iodir := SPIDirection.Tx
|
||||
io.link.fmt.endian := io.ctrl.fmt.endian
|
||||
io.link.cnt := Mux1H(
|
||||
SPIProtocol.decode(io.link.fmt.proto).zipWithIndex.map {
|
||||
case (s, i) => (s -> UInt(c.frameBits >> i))
|
||||
})
|
||||
io.link.cs.set := Bool(true)
|
||||
io.link.cs.clear := Bool(false)
|
||||
io.link.cs.hold := Bool(true)
|
||||
io.link.lock := Bool(true)
|
||||
|
||||
io.addr.ready := Bool(false)
|
||||
io.data.valid := Bool(false)
|
||||
io.data.bits := io.link.rx.bits
|
||||
|
||||
val cnt = Reg(UInt(width = math.max(c.insnPadLenBits, c.insnAddrLenBits)))
|
||||
val cnt_en = Wire(init = Bool(false))
|
||||
val cnt_cmp = (0 to c.insnAddrBytes).map(cnt === UInt(_))
|
||||
val cnt_zero = cnt_cmp(0)
|
||||
val cnt_last = cnt_cmp(1) && io.link.tx.ready
|
||||
val cnt_done = cnt_last || cnt_zero
|
||||
when (cnt_en) {
|
||||
io.link.tx.valid := !cnt_zero
|
||||
when (io.link.tx.fire()) {
|
||||
cnt := cnt - UInt(1)
|
||||
}
|
||||
}
|
||||
|
||||
val (s_idle :: s_cmd :: s_addr :: s_pad :: s_data_pre :: s_data_post :: Nil) = Enum(UInt(), 6)
|
||||
val state = Reg(init = s_idle)
|
||||
|
||||
switch (state) {
|
||||
is (s_idle) {
|
||||
io.link.tx.valid := Bool(false)
|
||||
when (io.en) {
|
||||
io.addr.ready := Bool(true)
|
||||
when (io.addr.valid) {
|
||||
when (merge) {
|
||||
state := s_data_pre
|
||||
} .otherwise {
|
||||
state := Mux(insn.cmd.en, s_cmd, s_addr)
|
||||
io.link.cs.clear := Bool(true)
|
||||
}
|
||||
} .otherwise {
|
||||
io.link.lock := Bool(false)
|
||||
}
|
||||
} .otherwise {
|
||||
io.data.valid := io.addr.valid
|
||||
io.addr.ready := io.data.ready
|
||||
io.data.bits := UInt(0)
|
||||
io.link.lock := Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
is (s_cmd) {
|
||||
io.link.fmt.proto := insn.cmd.proto
|
||||
io.link.tx.bits := insn.cmd.code
|
||||
when (io.link.tx.ready) {
|
||||
state := s_addr
|
||||
cnt := insn.addr.len
|
||||
}
|
||||
}
|
||||
|
||||
is (s_addr) {
|
||||
io.link.tx.bits := Mux1H(cnt_cmp.tail.zipWithIndex.map {
|
||||
case (s, i) =>
|
||||
val n = i * c.frameBits
|
||||
val m = n + (c.frameBits - 1)
|
||||
s -> io.addr.bits.hold(m, n)
|
||||
})
|
||||
|
||||
cnt_en := Bool(true)
|
||||
when (cnt_done) {
|
||||
state := s_pad
|
||||
}
|
||||
}
|
||||
|
||||
is (s_pad) {
|
||||
io.link.cnt := insn.pad.cnt
|
||||
io.link.tx.bits := insn.pad.code
|
||||
when (io.link.tx.ready) {
|
||||
state := s_data_pre
|
||||
}
|
||||
}
|
||||
|
||||
is (s_data_pre) {
|
||||
io.link.fmt.proto := insn.data.proto
|
||||
io.link.fmt.iodir := SPIDirection.Rx
|
||||
when (io.link.tx.ready) {
|
||||
state := s_data_post
|
||||
}
|
||||
}
|
||||
|
||||
is (s_data_post) {
|
||||
io.link.tx.valid := Bool(false)
|
||||
io.data.valid := io.link.rx.valid
|
||||
when (io.data.fire()) {
|
||||
state := s_idle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
121
src/main/scala/devices/spi/SPIMedia.scala
Normal file
121
src/main/scala/devices/spi/SPIMedia.scala
Normal file
@ -0,0 +1,121 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SPILinkIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val tx = Decoupled(Bits(width = c.frameBits))
|
||||
val rx = Valid(Bits(width = c.frameBits)).flip
|
||||
|
||||
val cnt = UInt(OUTPUT, c.countBits)
|
||||
val fmt = new SPIFormat(c).asOutput
|
||||
val cs = new Bundle {
|
||||
val set = Bool(OUTPUT)
|
||||
val clear = Bool(OUTPUT) // Deactivate CS
|
||||
val hold = Bool(OUTPUT) // Supress automatic CS deactivation
|
||||
}
|
||||
val active = Bool(INPUT)
|
||||
}
|
||||
|
||||
class SPIMedia(c: SPIConfigBase) extends Module {
|
||||
val io = new Bundle {
|
||||
val port = new SPIPortIO(c)
|
||||
val ctrl = new Bundle {
|
||||
val sck = new SPIClocking(c).asInput
|
||||
val dla = new SPIDelay(c).asInput
|
||||
val cs = new SPIChipSelect(c).asInput
|
||||
}
|
||||
val link = new SPILinkIO(c).flip
|
||||
}
|
||||
|
||||
val phy = Module(new SPIPhysical(c))
|
||||
phy.io.ctrl.sck := io.ctrl.sck
|
||||
phy.io.ctrl.fmt := io.link.fmt
|
||||
|
||||
private val op = phy.io.op
|
||||
op.valid := Bool(true)
|
||||
op.bits.fn := SPIMicroOp.Delay
|
||||
op.bits.stb := Bool(false)
|
||||
op.bits.cnt := io.link.cnt
|
||||
op.bits.data := io.link.tx.bits
|
||||
|
||||
val cs = Reg(io.ctrl.cs)
|
||||
val cs_set = Reg(Bool())
|
||||
val cs_active = io.ctrl.cs.toggle(io.link.cs.set)
|
||||
val cs_update = (cs_active.asUInt =/= cs.dflt.asUInt)
|
||||
|
||||
val clear = Reg(init = Bool(false))
|
||||
val cs_assert = Reg(init = Bool(false))
|
||||
val cs_deassert = clear || (cs_update && !io.link.cs.hold)
|
||||
|
||||
clear := clear || (io.link.cs.clear && cs_assert)
|
||||
|
||||
val continuous = (io.ctrl.dla.interxfr === UInt(0))
|
||||
|
||||
io.port.sck := phy.io.port.sck
|
||||
io.port.dq <> phy.io.port.dq
|
||||
io.port.cs := cs.dflt
|
||||
|
||||
io.link.rx := phy.io.rx
|
||||
io.link.tx.ready := Bool(false)
|
||||
io.link.active := cs_assert
|
||||
|
||||
val (s_main :: s_interxfr :: s_intercs :: Nil) = Enum(UInt(), 3)
|
||||
val state = Reg(init = s_main)
|
||||
|
||||
switch (state) {
|
||||
is (s_main) {
|
||||
when (cs_assert) {
|
||||
when (cs_deassert) {
|
||||
op.bits.cnt := io.ctrl.dla.sckcs
|
||||
when (op.ready) {
|
||||
state := s_intercs
|
||||
}
|
||||
} .otherwise {
|
||||
op.bits.fn := SPIMicroOp.Transfer
|
||||
op.bits.stb := Bool(true)
|
||||
|
||||
op.valid := io.link.tx.valid
|
||||
io.link.tx.ready := op.ready
|
||||
when (op.fire()) {
|
||||
state := s_interxfr
|
||||
}
|
||||
}
|
||||
} .elsewhen (io.link.tx.valid) {
|
||||
// Assert CS
|
||||
op.bits.cnt := io.ctrl.dla.cssck
|
||||
when (op.ready) {
|
||||
cs_assert := Bool(true)
|
||||
cs_set := io.link.cs.set
|
||||
cs.dflt := cs_active
|
||||
}
|
||||
} .otherwise {
|
||||
// Idle
|
||||
op.bits.cnt := UInt(0)
|
||||
op.bits.stb := Bool(true)
|
||||
cs := io.ctrl.cs
|
||||
}
|
||||
}
|
||||
|
||||
is (s_interxfr) {
|
||||
// Skip if interxfr delay is zero
|
||||
op.valid := !continuous
|
||||
op.bits.cnt := io.ctrl.dla.interxfr
|
||||
when (op.ready || continuous) {
|
||||
state := s_main
|
||||
}
|
||||
}
|
||||
|
||||
is (s_intercs) {
|
||||
// Deassert CS
|
||||
op.bits.cnt := io.ctrl.dla.intercs
|
||||
op.bits.stb := Bool(true)
|
||||
cs_assert := Bool(false)
|
||||
clear := Bool(false)
|
||||
when (op.ready) {
|
||||
cs.dflt := cs.toggle(cs_set)
|
||||
state := s_main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/main/scala/devices/spi/SPIPeriphery.scala
Normal file
57
src/main/scala/devices/spi/SPIPeriphery.scala
Normal file
@ -0,0 +1,57 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import uncore.tilelink2._
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
|
||||
trait PeripherySPI {
|
||||
this: TopNetwork { val spiConfigs: Seq[SPIConfig] } =>
|
||||
val spiDevices = (spiConfigs.zipWithIndex) map {case (c, i) =>
|
||||
val spi = LazyModule(new TLSPI(c) { override lazy val valName = Some(s"spi$i") } )
|
||||
spi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
intBus.intnode := spi.intnode
|
||||
spi
|
||||
}
|
||||
}
|
||||
|
||||
trait PeripherySPIBundle {
|
||||
this: { val spiConfigs: Seq[SPIConfig] } =>
|
||||
val spi_bc = spiConfigs.map(_.bc).reduce(_.union(_))
|
||||
val spis = Vec(spiConfigs.size, new SPIPortIO(spi_bc.toSPIConfig))
|
||||
}
|
||||
|
||||
trait PeripherySPIModule {
|
||||
this: TopNetworkModule {
|
||||
val spiConfigs: Seq[SPIConfig]
|
||||
val outer: PeripherySPI
|
||||
val io: PeripherySPIBundle
|
||||
} =>
|
||||
(io.spis zip outer.spiDevices).foreach { case (io, device) =>
|
||||
io <> device.module.io.port
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait PeripherySPIFlash {
|
||||
this: TopNetwork { val spiFlashConfig: SPIFlashConfig } =>
|
||||
val qspi = LazyModule(new TLSPIFlash(spiFlashConfig))
|
||||
qspi.rnode := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
qspi.fnode := TLFragmenter(1, cacheBlockBytes)(TLWidthWidget(peripheryBusConfig.beatBytes)(peripheryBus.node))
|
||||
intBus.intnode := qspi.intnode
|
||||
}
|
||||
|
||||
trait PeripherySPIFlashBundle {
|
||||
this: { val spiFlashConfig: SPIFlashConfig } =>
|
||||
val qspi = new SPIPortIO(spiFlashConfig)
|
||||
}
|
||||
|
||||
trait PeripherySPIFlashModule {
|
||||
this: TopNetworkModule {
|
||||
val spiConfigs: Seq[SPIConfig]
|
||||
val outer: PeripherySPIFlash
|
||||
val io: PeripherySPIFlashBundle
|
||||
} =>
|
||||
io.qspi <> outer.qspi.module.io.port
|
||||
}
|
157
src/main/scala/devices/spi/SPIPhysical.scala
Normal file
157
src/main/scala/devices/spi/SPIPhysical.scala
Normal file
@ -0,0 +1,157 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import sifive.blocks.util.ShiftRegisterInit
|
||||
|
||||
class SPIMicroOp(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val fn = Bits(width = 1)
|
||||
val stb = Bool()
|
||||
val cnt = UInt(width = c.countBits)
|
||||
val data = Bits(width = c.frameBits)
|
||||
}
|
||||
|
||||
object SPIMicroOp {
|
||||
val Transfer = UInt(0, 1)
|
||||
val Delay = UInt(1, 1)
|
||||
}
|
||||
|
||||
class SPIPhyControl(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = new SPIClocking(c)
|
||||
val fmt = new SPIFormat(c)
|
||||
}
|
||||
|
||||
class SPIPhysical(c: SPIConfigBase) extends Module {
|
||||
val io = new SPIBundle(c) {
|
||||
val port = new SPIPortIO(c)
|
||||
val ctrl = new SPIPhyControl(c).asInput
|
||||
val op = Decoupled(new SPIMicroOp(c)).flip
|
||||
val rx = Valid(Bits(width = c.frameBits))
|
||||
}
|
||||
|
||||
private val op = io.op.bits
|
||||
val ctrl = Reg(io.ctrl)
|
||||
val proto = SPIProtocol.decode(ctrl.fmt.proto)
|
||||
|
||||
val accept = Wire(init = Bool(false))
|
||||
val sample = Wire(init = Bool(false))
|
||||
val setup = Wire(init = Bool(false))
|
||||
val last = Wire(init = Bool(false))
|
||||
// Delayed versions
|
||||
val setup_d = Reg(next = setup)
|
||||
val sample_d = ShiftRegisterInit(sample, c.sampleDelay, Bool(false))
|
||||
val last_d = ShiftRegisterInit(last, c.sampleDelay, Bool(false))
|
||||
|
||||
val scnt = Reg(init = UInt(0, c.countBits))
|
||||
val tcnt = Reg(io.ctrl.sck.div)
|
||||
|
||||
val stop = (scnt === UInt(0))
|
||||
val beat = (tcnt === UInt(0))
|
||||
val decr = Mux(beat, scnt, tcnt) - UInt(1)
|
||||
val sched = Wire(init = beat)
|
||||
tcnt := Mux(sched, ctrl.sck.div, decr)
|
||||
|
||||
val sck = Reg(Bool())
|
||||
val cref = Reg(init = Bool(true))
|
||||
val cinv = ctrl.sck.pha ^ ctrl.sck.pol
|
||||
|
||||
private def convert(data: UInt, fmt: SPIFormat) =
|
||||
Mux(fmt.endian === SPIEndian.MSB, data, Cat(data.toBools))
|
||||
|
||||
val rxd = Cat(io.port.dq.reverse.map(_.i))
|
||||
val samples = Seq(rxd(1), rxd(1, 0), rxd)
|
||||
|
||||
val buffer = Reg(op.data)
|
||||
val buffer_in = convert(io.op.bits.data, io.ctrl.fmt)
|
||||
val shift = if (c.sampleDelay > 0) setup_d || (sample_d && stop) else sample_d
|
||||
buffer := Mux1H(proto, samples.zipWithIndex.map { case (data, i) =>
|
||||
val n = 1 << i
|
||||
val m = c.frameBits -1
|
||||
Cat(Mux(shift, buffer(m-n, 0), buffer(m, n)),
|
||||
Mux(sample_d, data, buffer(n-1, 0)))
|
||||
})
|
||||
|
||||
private def upper(x: UInt, n: Int) = x(c.frameBits-1, c.frameBits-n)
|
||||
|
||||
val txd = Reg(init = Bits(0, io.port.dq.size))
|
||||
val txd_in = Mux(accept, upper(buffer_in, 4), upper(buffer, 4))
|
||||
val txd_sel = SPIProtocol.decode(Mux(accept, io.ctrl.fmt.proto, ctrl.fmt.proto))
|
||||
val txd_shf = (0 until txd_sel.size).map(i => txd_in(3, 4-(1<<i)))
|
||||
when (setup) {
|
||||
txd := Mux1H(txd_sel, txd_shf)
|
||||
}
|
||||
|
||||
val tx = (ctrl.fmt.iodir === SPIDirection.Tx)
|
||||
val txen_in = (proto.head +: proto.tail.map(_ && tx)).scanRight(Bool(false))(_ || _)
|
||||
val txen = txen_in :+ txen_in.last
|
||||
|
||||
io.port.sck := sck
|
||||
io.port.cs := Vec.fill(io.port.cs.size)(Bool(true)) // dummy
|
||||
(io.port.dq zip (txd.toBools zip txen)).foreach {
|
||||
case (dq, (o, oe)) =>
|
||||
dq.o := o
|
||||
dq.oe := oe
|
||||
}
|
||||
io.op.ready := Bool(false)
|
||||
|
||||
val done = Reg(init = Bool(true))
|
||||
done := done || last_d
|
||||
|
||||
io.rx.valid := done
|
||||
io.rx.bits := convert(buffer, ctrl.fmt)
|
||||
|
||||
val xfr = Reg(Bool())
|
||||
|
||||
when (stop) {
|
||||
sched := Bool(true)
|
||||
accept := Bool(true)
|
||||
} .otherwise {
|
||||
when (beat) {
|
||||
cref := !cref
|
||||
when (xfr) {
|
||||
sck := cref ^ cinv
|
||||
sample := cref
|
||||
setup := !cref
|
||||
}
|
||||
when (!cref) {
|
||||
scnt := decr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (scnt === UInt(1)) {
|
||||
last := beat && cref && xfr // Final sample
|
||||
when (beat && !cref) { // Final shift
|
||||
accept := Bool(true)
|
||||
setup := Bool(false)
|
||||
sck := ctrl.sck.pol
|
||||
}
|
||||
}
|
||||
|
||||
when (accept && done) {
|
||||
io.op.ready := Bool(true)
|
||||
when (io.op.valid) {
|
||||
scnt := op.cnt
|
||||
when (op.stb) {
|
||||
ctrl.fmt := io.ctrl.fmt
|
||||
}
|
||||
|
||||
xfr := Bool(false)
|
||||
switch (op.fn) {
|
||||
is (SPIMicroOp.Transfer) {
|
||||
buffer := buffer_in
|
||||
sck := cinv
|
||||
setup := Bool(true)
|
||||
done := (op.cnt === UInt(0))
|
||||
xfr := Bool(true)
|
||||
}
|
||||
is (SPIMicroOp.Delay) {
|
||||
when (op.stb) {
|
||||
sck := io.ctrl.sck.pol
|
||||
ctrl.sck := io.ctrl.sck
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/main/scala/devices/spi/SPIPins.scala
Normal file
34
src/main/scala/devices/spi/SPIPins.scala
Normal file
@ -0,0 +1,34 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
|
||||
|
||||
class SPIPinsIO(c: SPIConfigBase) extends SPIBundle(c) {
|
||||
val sck = new GPIOPin
|
||||
val dq = Vec(4, new GPIOPin)
|
||||
val cs = Vec(c.csWidth, new GPIOPin)
|
||||
}
|
||||
|
||||
class SPIGPIOPort(c: SPIConfigBase, syncStages: Int = 0, driveStrength: Bool = Bool(false)) extends Module {
|
||||
val io = new SPIBundle(c) {
|
||||
val spi = new SPIPortIO(c).flip
|
||||
val pins = new SPIPinsIO(c)
|
||||
}
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.sck, io.spi.sck, ds = driveStrength)
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.dq, Bits(0, io.spi.dq.size))
|
||||
(io.pins.dq zip io.spi.dq).foreach {
|
||||
case (p, s) =>
|
||||
p.o.oval := s.o
|
||||
p.o.oe := s.oe
|
||||
p.o.ie := ~s.oe
|
||||
p.o.pue := Bool(true)
|
||||
p.o.ds := driveStrength
|
||||
s.i := ShiftRegister(p.i.ival, syncStages)
|
||||
}
|
||||
|
||||
GPIOOutputPinCtrl(io.pins.cs, io.spi.cs.asUInt)
|
||||
io.pins.cs.foreach(_.o.ds := driveStrength)
|
||||
}
|
30
src/main/scala/devices/spi/SPIRegs.scala
Normal file
30
src/main/scala/devices/spi/SPIRegs.scala
Normal file
@ -0,0 +1,30 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
object SPICRs {
|
||||
val sckdiv = 0x00
|
||||
val sckmode = 0x04
|
||||
val csid = 0x10
|
||||
val csdef = 0x14
|
||||
val csmode = 0x18
|
||||
val dcssck = 0x28
|
||||
val dsckcs = 0x2a
|
||||
val dintercs = 0x2c
|
||||
val dinterxfr = 0x2e
|
||||
|
||||
val fmt = 0x40
|
||||
val len = 0x42
|
||||
val txfifo = 0x48
|
||||
val rxfifo = 0x4c
|
||||
val txmark = 0x50
|
||||
val rxmark = 0x54
|
||||
|
||||
val insnmode = 0x60
|
||||
val insnfmt = 0x64
|
||||
val insnproto = 0x65
|
||||
val insncmd = 0x66
|
||||
val insnpad = 0x67
|
||||
|
||||
val ie = 0x70
|
||||
val ip = 0x74
|
||||
}
|
132
src/main/scala/devices/spi/TLSPI.scala
Normal file
132
src/main/scala/devices/spi/TLSPI.scala
Normal file
@ -0,0 +1,132 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import uncore.tilelink2._
|
||||
import diplomacy._
|
||||
import regmapper._
|
||||
import junctions._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
|
||||
|
||||
trait SPIConfigBase {
|
||||
val rAddress: BigInt
|
||||
val rSize: BigInt
|
||||
val rxDepth: Int
|
||||
val txDepth: Int
|
||||
|
||||
val csWidth: Int
|
||||
val frameBits: Int
|
||||
val delayBits: Int
|
||||
val divisorBits: Int
|
||||
|
||||
val sampleDelay: Int
|
||||
|
||||
lazy val csIdBits = log2Up(csWidth)
|
||||
lazy val lengthBits = log2Floor(frameBits) + 1
|
||||
lazy val countBits = math.max(lengthBits, delayBits)
|
||||
|
||||
lazy val txDepthBits = log2Floor(txDepth) + 1
|
||||
lazy val rxDepthBits = log2Floor(rxDepth) + 1
|
||||
|
||||
lazy val bc = new SPIBundleConfig(csWidth)
|
||||
}
|
||||
|
||||
case class SPIConfig(
|
||||
rAddress: BigInt,
|
||||
rSize: BigInt = 0x1000,
|
||||
rxDepth: Int = 8,
|
||||
txDepth: Int = 8,
|
||||
csWidth: Int = 1,
|
||||
frameBits: Int = 8,
|
||||
delayBits: Int = 8,
|
||||
divisorBits: Int = 12,
|
||||
sampleDelay: Int = 2)
|
||||
extends SPIConfigBase {
|
||||
|
||||
require(frameBits >= 4)
|
||||
require(sampleDelay >= 0)
|
||||
}
|
||||
|
||||
case class SPIBundleConfig(csWidth: Int)
|
||||
{
|
||||
def union(that: SPIBundleConfig): SPIBundleConfig =
|
||||
SPIBundleConfig(scala.math.max(csWidth, that.csWidth))
|
||||
|
||||
def toSPIConfig: SPIConfig = new SPIConfig(rAddress = -1,
|
||||
csWidth = csWidth)
|
||||
}
|
||||
|
||||
class SPITopBundle(val i: Vec[Vec[Bool]], val r: Vec[TLBundle]) extends Bundle
|
||||
|
||||
class SPITopModule[B <: SPITopBundle](c: SPIConfigBase, bundle: => B, outer: TLSPIBase)
|
||||
extends LazyModuleImp(outer) {
|
||||
|
||||
val io = new Bundle {
|
||||
val port = new SPIPortIO(c)
|
||||
val tl = bundle
|
||||
}
|
||||
|
||||
val ctrl = Reg(init = SPIControl.init(c))
|
||||
|
||||
val fifo = Module(new SPIFIFO(c))
|
||||
val mac = Module(new SPIMedia(c))
|
||||
io.port <> mac.io.port
|
||||
|
||||
fifo.io.ctrl.fmt := ctrl.fmt
|
||||
fifo.io.ctrl.cs <> ctrl.cs
|
||||
fifo.io.ctrl.wm := ctrl.wm
|
||||
mac.io.ctrl.sck := ctrl.sck
|
||||
mac.io.ctrl.dla := ctrl.dla
|
||||
mac.io.ctrl.cs <> ctrl.cs
|
||||
|
||||
val ie = Reg(init = new SPIInterrupts().fromBits(Bits(0)))
|
||||
val ip = fifo.io.ip
|
||||
io.tl.i(0)(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
|
||||
|
||||
protected val regmapBase = Seq(
|
||||
SPICRs.sckdiv -> Seq(RegField(c.divisorBits, ctrl.sck.div)),
|
||||
SPICRs.sckmode -> Seq(
|
||||
RegField(1, ctrl.sck.pha),
|
||||
RegField(1, ctrl.sck.pol)),
|
||||
SPICRs.csid -> Seq(RegField(c.csIdBits, ctrl.cs.id)),
|
||||
SPICRs.csdef -> ctrl.cs.dflt.map(x => RegField(1, x)),
|
||||
SPICRs.csmode -> Seq(RegField(SPICSMode.width, ctrl.cs.mode)),
|
||||
SPICRs.dcssck -> Seq(RegField(c.delayBits, ctrl.dla.cssck)),
|
||||
SPICRs.dsckcs -> Seq(RegField(c.delayBits, ctrl.dla.sckcs)),
|
||||
SPICRs.dintercs -> Seq(RegField(c.delayBits, ctrl.dla.intercs)),
|
||||
SPICRs.dinterxfr -> Seq(RegField(c.delayBits, ctrl.dla.interxfr)),
|
||||
|
||||
SPICRs.fmt -> Seq(
|
||||
RegField(SPIProtocol.width, ctrl.fmt.proto),
|
||||
RegField(SPIEndian.width, ctrl.fmt.endian),
|
||||
RegField(SPIDirection.width, ctrl.fmt.iodir)),
|
||||
SPICRs.len -> Seq(RegField(c.lengthBits, ctrl.fmt.len)),
|
||||
|
||||
SPICRs.txfifo -> NonBlockingEnqueue(fifo.io.tx),
|
||||
SPICRs.rxfifo -> NonBlockingDequeue(fifo.io.rx),
|
||||
|
||||
SPICRs.txmark -> Seq(RegField(c.txDepthBits, ctrl.wm.tx)),
|
||||
SPICRs.rxmark -> Seq(RegField(c.rxDepthBits, ctrl.wm.rx)),
|
||||
|
||||
SPICRs.ie -> Seq(
|
||||
RegField(1, ie.txwm),
|
||||
RegField(1, ie.rxwm)),
|
||||
SPICRs.ip -> Seq(
|
||||
RegField.r(1, ip.txwm),
|
||||
RegField.r(1, ip.rxwm)))
|
||||
}
|
||||
|
||||
abstract class TLSPIBase(c: SPIConfigBase)(implicit val p: Parameters) extends LazyModule {
|
||||
require(isPow2(c.rSize))
|
||||
val rnode = TLRegisterNode(address = AddressSet(c.rAddress, c.rSize-1), beatBytes = p(PeripheryBusConfig).beatBytes)
|
||||
val intnode = IntSourceNode(1)
|
||||
}
|
||||
|
||||
class TLSPI(c: SPIConfig)(implicit p: Parameters) extends TLSPIBase(c)(p) {
|
||||
lazy val module = new SPITopModule(c, new SPITopBundle(intnode.bundleOut, rnode.bundleIn), this) {
|
||||
mac.io.link <> fifo.io.link
|
||||
rnode.regmap(regmapBase:_*)
|
||||
}
|
||||
}
|
114
src/main/scala/devices/spi/TLSPIFlash.scala
Normal file
114
src/main/scala/devices/spi/TLSPIFlash.scala
Normal file
@ -0,0 +1,114 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.spi
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
|
||||
trait SPIFlashConfigBase extends SPIConfigBase {
|
||||
val fAddress: BigInt
|
||||
val fSize: BigInt
|
||||
|
||||
val insnAddrBytes: Int
|
||||
val insnPadLenBits: Int
|
||||
lazy val insnCmdBits = frameBits
|
||||
lazy val insnAddrBits = insnAddrBytes * frameBits
|
||||
lazy val insnAddrLenBits = log2Floor(insnAddrBytes) + 1
|
||||
}
|
||||
|
||||
case class SPIFlashConfig(
|
||||
rAddress: BigInt,
|
||||
fAddress: BigInt,
|
||||
rSize: BigInt = 0x1000,
|
||||
fSize: BigInt = 0x20000000,
|
||||
rxDepth: Int = 8,
|
||||
txDepth: Int = 8,
|
||||
csWidth: Int = 1,
|
||||
delayBits: Int = 8,
|
||||
divisorBits: Int = 12,
|
||||
sampleDelay: Int = 2)
|
||||
extends SPIFlashConfigBase {
|
||||
val frameBits = 8
|
||||
val insnAddrBytes = 4
|
||||
val insnPadLenBits = 4
|
||||
|
||||
require(insnPadLenBits <= delayBits)
|
||||
require(sampleDelay >= 0)
|
||||
}
|
||||
|
||||
class SPIFlashTopBundle(i: Vec[Vec[Bool]], r: Vec[TLBundle], val f: Vec[TLBundle]) extends SPITopBundle(i, r)
|
||||
|
||||
class SPIFlashTopModule[B <: SPIFlashTopBundle]
|
||||
(c: SPIFlashConfigBase, bundle: => B, outer: TLSPIFlashBase)
|
||||
extends SPITopModule(c, bundle, outer) {
|
||||
|
||||
val flash = Module(new SPIFlashMap(c))
|
||||
val arb = Module(new SPIArbiter(c, 2))
|
||||
|
||||
private val f = io.tl.f.head
|
||||
// Tie unused channels
|
||||
f.b.valid := Bool(false)
|
||||
f.c.ready := Bool(true)
|
||||
f.e.ready := Bool(true)
|
||||
|
||||
val a = Reg(f.a.bits)
|
||||
val a_msb = log2Ceil(c.fSize) - 1
|
||||
|
||||
when (f.a.fire()) {
|
||||
a := f.a.bits
|
||||
}
|
||||
|
||||
flash.io.addr.bits.next := f.a.bits.address(a_msb, 0)
|
||||
flash.io.addr.bits.hold := a.address(a_msb, 0)
|
||||
flash.io.addr.valid := f.a.valid
|
||||
f.a.ready := flash.io.addr.ready
|
||||
|
||||
f.d.bits := outer.fnode.edgesIn.head.AccessAck(a, UInt(0), flash.io.data.bits)
|
||||
f.d.valid := flash.io.data.valid
|
||||
flash.io.data.ready := f.d.ready
|
||||
|
||||
val insn = Reg(init = SPIFlashInsn.init(c))
|
||||
val flash_en = Reg(init = Bool(true))
|
||||
|
||||
flash.io.ctrl.insn := insn
|
||||
flash.io.ctrl.fmt <> ctrl.fmt
|
||||
flash.io.en := flash_en
|
||||
arb.io.sel := !flash_en
|
||||
|
||||
protected val regmapFlash = Seq(
|
||||
SPICRs.insnmode -> Seq(RegField(1, flash_en)),
|
||||
SPICRs.insnfmt -> Seq(
|
||||
RegField(1, insn.cmd.en),
|
||||
RegField(c.insnAddrLenBits, insn.addr.len),
|
||||
RegField(c.insnPadLenBits, insn.pad.cnt)),
|
||||
SPICRs.insnproto -> Seq(
|
||||
RegField(SPIProtocol.width, insn.cmd.proto),
|
||||
RegField(SPIProtocol.width, insn.addr.proto),
|
||||
RegField(SPIProtocol.width, insn.data.proto)),
|
||||
SPICRs.insncmd -> Seq(RegField(c.insnCmdBits, insn.cmd.code)),
|
||||
SPICRs.insnpad -> Seq(RegField(c.frameBits, insn.pad.code)))
|
||||
}
|
||||
|
||||
abstract class TLSPIFlashBase(c: SPIFlashConfigBase)(implicit p: Parameters) extends TLSPIBase(c)(p) {
|
||||
require(isPow2(c.fSize))
|
||||
val fnode = TLManagerNode(1, TLManagerParameters(
|
||||
address = Seq(AddressSet(c.fAddress, c.fSize-1)),
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = true,
|
||||
supportsGet = TransferSizes(1, 1),
|
||||
fifoId = Some(0)))
|
||||
}
|
||||
|
||||
class TLSPIFlash(c: SPIFlashConfig)(implicit p: Parameters) extends TLSPIFlashBase(c)(p) {
|
||||
lazy val module = new SPIFlashTopModule(c,
|
||||
new SPIFlashTopBundle(intnode.bundleOut, rnode.bundleIn, fnode.bundleIn), this) {
|
||||
|
||||
arb.io.inner(0) <> flash.io.link
|
||||
arb.io.inner(1) <> fifo.io.link
|
||||
mac.io.link <> arb.io.outer
|
||||
|
||||
rnode.regmap(regmapBase ++ regmapFlash:_*)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user