Initial commit.
[sifive-blocks.git] / src / main / scala / devices / spi / SPIFIFO.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.spi
3
4 import Chisel._
5
6 class SPIFIFOControl(c: SPIConfigBase) extends SPIBundle(c) {
7 val fmt = new SPIFormat(c) with HasSPILength
8 val cs = new Bundle with HasSPICSMode
9 val wm = new SPIWatermark(c)
10 }
11
12 class SPIFIFO(c: SPIConfigBase) extends Module {
13 val io = new Bundle {
14 val ctrl = new SPIFIFOControl(c).asInput
15 val link = new SPIInnerIO(c)
16 val tx = Decoupled(Bits(width = c.frameBits)).flip
17 val rx = Decoupled(Bits(width = c.frameBits))
18 val ip = new SPIInterrupts().asOutput
19 }
20
21 val txq = Module(new Queue(io.tx.bits, c.txDepth))
22 val rxq = Module(new Queue(io.rx.bits, c.rxDepth))
23
24 txq.io.enq <> io.tx
25 io.link.tx <> txq.io.deq
26
27 val fire_tx = io.link.tx.fire()
28 val fire_rx = io.link.rx.fire()
29 val rxen = Reg(init = Bool(false))
30
31 rxq.io.enq.valid := io.link.rx.valid && rxen
32 rxq.io.enq.bits := io.link.rx.bits
33 io.rx <> rxq.io.deq
34
35 when (fire_rx) {
36 rxen := Bool(false)
37 }
38 when (fire_tx) {
39 rxen := (io.link.fmt.iodir === SPIDirection.Rx)
40 }
41
42 val proto = SPIProtocol.decode(io.link.fmt.proto).zipWithIndex
43 val cnt_quot = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len >> i) })
44 val cnt_rmdr = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len(i, 0).orR) })
45 io.link.fmt <> io.ctrl.fmt
46 io.link.cnt := cnt_quot + cnt_rmdr
47
48 val cs_mode = RegNext(io.ctrl.cs.mode, SPICSMode.Auto)
49 val cs_mode_hold = (cs_mode === SPICSMode.Hold)
50 val cs_mode_off = (cs_mode === SPICSMode.Off)
51 val cs_update = (cs_mode =/= io.ctrl.cs.mode)
52 val cs_clear = !(cs_mode_hold || cs_mode_off)
53
54 io.link.cs.set := !cs_mode_off
55 io.link.cs.clear := cs_update || (fire_tx && cs_clear)
56 io.link.cs.hold := Bool(false)
57
58 io.link.lock := io.link.tx.valid || rxen
59
60 io.ip.txwm := (txq.io.count < io.ctrl.wm.tx)
61 io.ip.rxwm := (rxq.io.count > io.ctrl.wm.rx)
62 }