Initial commit.
[sifive-blocks.git] / src / main / scala / devices / spi / SPIMedia.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.spi
3
4 import Chisel._
5
6 class SPILinkIO(c: SPIConfigBase) extends SPIBundle(c) {
7 val tx = Decoupled(Bits(width = c.frameBits))
8 val rx = Valid(Bits(width = c.frameBits)).flip
9
10 val cnt = UInt(OUTPUT, c.countBits)
11 val fmt = new SPIFormat(c).asOutput
12 val cs = new Bundle {
13 val set = Bool(OUTPUT)
14 val clear = Bool(OUTPUT) // Deactivate CS
15 val hold = Bool(OUTPUT) // Supress automatic CS deactivation
16 }
17 val active = Bool(INPUT)
18 }
19
20 class SPIMedia(c: SPIConfigBase) extends Module {
21 val io = new Bundle {
22 val port = new SPIPortIO(c)
23 val ctrl = new Bundle {
24 val sck = new SPIClocking(c).asInput
25 val dla = new SPIDelay(c).asInput
26 val cs = new SPIChipSelect(c).asInput
27 }
28 val link = new SPILinkIO(c).flip
29 }
30
31 val phy = Module(new SPIPhysical(c))
32 phy.io.ctrl.sck := io.ctrl.sck
33 phy.io.ctrl.fmt := io.link.fmt
34
35 private val op = phy.io.op
36 op.valid := Bool(true)
37 op.bits.fn := SPIMicroOp.Delay
38 op.bits.stb := Bool(false)
39 op.bits.cnt := io.link.cnt
40 op.bits.data := io.link.tx.bits
41
42 val cs = Reg(io.ctrl.cs)
43 val cs_set = Reg(Bool())
44 val cs_active = io.ctrl.cs.toggle(io.link.cs.set)
45 val cs_update = (cs_active.asUInt =/= cs.dflt.asUInt)
46
47 val clear = Reg(init = Bool(false))
48 val cs_assert = Reg(init = Bool(false))
49 val cs_deassert = clear || (cs_update && !io.link.cs.hold)
50
51 clear := clear || (io.link.cs.clear && cs_assert)
52
53 val continuous = (io.ctrl.dla.interxfr === UInt(0))
54
55 io.port.sck := phy.io.port.sck
56 io.port.dq <> phy.io.port.dq
57 io.port.cs := cs.dflt
58
59 io.link.rx := phy.io.rx
60 io.link.tx.ready := Bool(false)
61 io.link.active := cs_assert
62
63 val (s_main :: s_interxfr :: s_intercs :: Nil) = Enum(UInt(), 3)
64 val state = Reg(init = s_main)
65
66 switch (state) {
67 is (s_main) {
68 when (cs_assert) {
69 when (cs_deassert) {
70 op.bits.cnt := io.ctrl.dla.sckcs
71 when (op.ready) {
72 state := s_intercs
73 }
74 } .otherwise {
75 op.bits.fn := SPIMicroOp.Transfer
76 op.bits.stb := Bool(true)
77
78 op.valid := io.link.tx.valid
79 io.link.tx.ready := op.ready
80 when (op.fire()) {
81 state := s_interxfr
82 }
83 }
84 } .elsewhen (io.link.tx.valid) {
85 // Assert CS
86 op.bits.cnt := io.ctrl.dla.cssck
87 when (op.ready) {
88 cs_assert := Bool(true)
89 cs_set := io.link.cs.set
90 cs.dflt := cs_active
91 }
92 } .otherwise {
93 // Idle
94 op.bits.cnt := UInt(0)
95 op.bits.stb := Bool(true)
96 cs := io.ctrl.cs
97 }
98 }
99
100 is (s_interxfr) {
101 // Skip if interxfr delay is zero
102 op.valid := !continuous
103 op.bits.cnt := io.ctrl.dla.interxfr
104 when (op.ready || continuous) {
105 state := s_main
106 }
107 }
108
109 is (s_intercs) {
110 // Deassert CS
111 op.bits.cnt := io.ctrl.dla.intercs
112 op.bits.stb := Bool(true)
113 cs_assert := Bool(false)
114 clear := Bool(false)
115 when (op.ready) {
116 cs.dflt := cs.toggle(cs_set)
117 state := s_main
118 }
119 }
120 }
121 }