Initial commit.
[sifive-blocks.git] / src / main / scala / devices / spi / SPIPhysical.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.spi
3
4 import Chisel._
5 import sifive.blocks.util.ShiftRegisterInit
6
7 class SPIMicroOp(c: SPIConfigBase) extends SPIBundle(c) {
8 val fn = Bits(width = 1)
9 val stb = Bool()
10 val cnt = UInt(width = c.countBits)
11 val data = Bits(width = c.frameBits)
12 }
13
14 object SPIMicroOp {
15 val Transfer = UInt(0, 1)
16 val Delay = UInt(1, 1)
17 }
18
19 class SPIPhyControl(c: SPIConfigBase) extends SPIBundle(c) {
20 val sck = new SPIClocking(c)
21 val fmt = new SPIFormat(c)
22 }
23
24 class SPIPhysical(c: SPIConfigBase) extends Module {
25 val io = new SPIBundle(c) {
26 val port = new SPIPortIO(c)
27 val ctrl = new SPIPhyControl(c).asInput
28 val op = Decoupled(new SPIMicroOp(c)).flip
29 val rx = Valid(Bits(width = c.frameBits))
30 }
31
32 private val op = io.op.bits
33 val ctrl = Reg(io.ctrl)
34 val proto = SPIProtocol.decode(ctrl.fmt.proto)
35
36 val accept = Wire(init = Bool(false))
37 val sample = Wire(init = Bool(false))
38 val setup = Wire(init = Bool(false))
39 val last = Wire(init = Bool(false))
40 // Delayed versions
41 val setup_d = Reg(next = setup)
42 val sample_d = ShiftRegisterInit(sample, c.sampleDelay, Bool(false))
43 val last_d = ShiftRegisterInit(last, c.sampleDelay, Bool(false))
44
45 val scnt = Reg(init = UInt(0, c.countBits))
46 val tcnt = Reg(io.ctrl.sck.div)
47
48 val stop = (scnt === UInt(0))
49 val beat = (tcnt === UInt(0))
50 val decr = Mux(beat, scnt, tcnt) - UInt(1)
51 val sched = Wire(init = beat)
52 tcnt := Mux(sched, ctrl.sck.div, decr)
53
54 val sck = Reg(Bool())
55 val cref = Reg(init = Bool(true))
56 val cinv = ctrl.sck.pha ^ ctrl.sck.pol
57
58 private def convert(data: UInt, fmt: SPIFormat) =
59 Mux(fmt.endian === SPIEndian.MSB, data, Cat(data.toBools))
60
61 val rxd = Cat(io.port.dq.reverse.map(_.i))
62 val samples = Seq(rxd(1), rxd(1, 0), rxd)
63
64 val buffer = Reg(op.data)
65 val buffer_in = convert(io.op.bits.data, io.ctrl.fmt)
66 val shift = if (c.sampleDelay > 0) setup_d || (sample_d && stop) else sample_d
67 buffer := Mux1H(proto, samples.zipWithIndex.map { case (data, i) =>
68 val n = 1 << i
69 val m = c.frameBits -1
70 Cat(Mux(shift, buffer(m-n, 0), buffer(m, n)),
71 Mux(sample_d, data, buffer(n-1, 0)))
72 })
73
74 private def upper(x: UInt, n: Int) = x(c.frameBits-1, c.frameBits-n)
75
76 val txd = Reg(init = Bits(0, io.port.dq.size))
77 val txd_in = Mux(accept, upper(buffer_in, 4), upper(buffer, 4))
78 val txd_sel = SPIProtocol.decode(Mux(accept, io.ctrl.fmt.proto, ctrl.fmt.proto))
79 val txd_shf = (0 until txd_sel.size).map(i => txd_in(3, 4-(1<<i)))
80 when (setup) {
81 txd := Mux1H(txd_sel, txd_shf)
82 }
83
84 val tx = (ctrl.fmt.iodir === SPIDirection.Tx)
85 val txen_in = (proto.head +: proto.tail.map(_ && tx)).scanRight(Bool(false))(_ || _)
86 val txen = txen_in :+ txen_in.last
87
88 io.port.sck := sck
89 io.port.cs := Vec.fill(io.port.cs.size)(Bool(true)) // dummy
90 (io.port.dq zip (txd.toBools zip txen)).foreach {
91 case (dq, (o, oe)) =>
92 dq.o := o
93 dq.oe := oe
94 }
95 io.op.ready := Bool(false)
96
97 val done = Reg(init = Bool(true))
98 done := done || last_d
99
100 io.rx.valid := done
101 io.rx.bits := convert(buffer, ctrl.fmt)
102
103 val xfr = Reg(Bool())
104
105 when (stop) {
106 sched := Bool(true)
107 accept := Bool(true)
108 } .otherwise {
109 when (beat) {
110 cref := !cref
111 when (xfr) {
112 sck := cref ^ cinv
113 sample := cref
114 setup := !cref
115 }
116 when (!cref) {
117 scnt := decr
118 }
119 }
120 }
121
122 when (scnt === UInt(1)) {
123 last := beat && cref && xfr // Final sample
124 when (beat && !cref) { // Final shift
125 accept := Bool(true)
126 setup := Bool(false)
127 sck := ctrl.sck.pol
128 }
129 }
130
131 when (accept && done) {
132 io.op.ready := Bool(true)
133 when (io.op.valid) {
134 scnt := op.cnt
135 when (op.stb) {
136 ctrl.fmt := io.ctrl.fmt
137 }
138
139 xfr := Bool(false)
140 switch (op.fn) {
141 is (SPIMicroOp.Transfer) {
142 buffer := buffer_in
143 sck := cinv
144 setup := Bool(true)
145 done := (op.cnt === UInt(0))
146 xfr := Bool(true)
147 }
148 is (SPIMicroOp.Delay) {
149 when (op.stb) {
150 sck := io.ctrl.sck.pol
151 ctrl.sck := io.ctrl.sck
152 }
153 }
154 }
155 }
156 }
157 }