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

158 lines
4.1 KiB
Scala

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