"Fix" false combinational loop through SPIArbiter
[sifive-blocks.git] / src / main / scala / devices / spi / SPIArbiter.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.spi
3
4 import Chisel._
5
6 class SPIInnerIO(c: SPIParamsBase) extends SPILinkIO(c) {
7 val lock = Bool(OUTPUT)
8 }
9
10 class SPIArbiter(c: SPIParamsBase, n: Int) extends Module {
11 val io = new Bundle {
12 val inner = Vec(n, new SPIInnerIO(c)).flip
13 val outer = new SPILinkIO(c)
14 val sel = UInt(INPUT, log2Up(n))
15 }
16
17 val sel = Reg(init = Vec(Bool(true) +: Seq.fill(n-1)(Bool(false))))
18
19 io.outer.tx.valid := Mux1H(sel, io.inner.map(_.tx.valid))
20 io.outer.tx.bits := Mux1H(sel, io.inner.map(_.tx.bits))
21 io.outer.cnt := Mux1H(sel, io.inner.map(_.cnt))
22 io.outer.fmt := Mux1H(sel, io.inner.map(_.fmt))
23 // Workaround for overzealous combinational loop detection
24 io.outer.cs := Mux(sel(1), io.inner(0).cs, io.inner(1).cs)
25 require(n == 2, "SPIArbiter currently only supports 2 clients")
26
27 (io.inner zip sel).foreach { case (inner, s) =>
28 inner.tx.ready := io.outer.tx.ready && s
29 inner.rx.valid := io.outer.rx.valid && s
30 inner.rx.bits := io.outer.rx.bits
31 inner.active := io.outer.active && s
32 }
33
34 val nsel = Vec.tabulate(n)(io.sel === UInt(_))
35 val lock = Mux1H(sel, io.inner.map(_.lock))
36 when (!lock) {
37 sel := nsel
38 when (sel.asUInt =/= nsel.asUInt) {
39 io.outer.cs.clear := Bool(true)
40 }
41 }
42 }