1
0
Fork 0
sifive-blocks/src/main/scala/devices/spi/SPIMedia.scala

122 lines
3.1 KiB
Scala

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