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