1 // See LICENSE for license details.
2 package sifive.blocks.devices.spi
6 class SPIFlashInsn(c: SPIFlashParamsBase) extends SPIBundle(c) {
7 val cmd = new Bundle with HasSPIProtocol {
8 val code = Bits(width = c.insnCmdBits)
11 val addr = new Bundle with HasSPIProtocol {
12 val len = UInt(width = c.insnAddrLenBits)
14 val pad = new Bundle {
15 val code = Bits(width = c.frameBits)
16 val cnt = Bits(width = c.insnPadLenBits)
18 val data = new Bundle with HasSPIProtocol
21 class SPIFlashControl(c: SPIFlashParamsBase) extends SPIBundle(c) {
22 val insn = new SPIFlashInsn(c)
23 val fmt = new Bundle with HasSPIEndian
27 def init(c: SPIFlashParamsBase): SPIFlashInsn = {
28 val insn = Wire(new SPIFlashInsn(c))
29 insn.cmd.en := Bool(true)
30 insn.cmd.code := Bits(0x03)
31 insn.cmd.proto := SPIProtocol.Single
32 insn.addr.len := UInt(3)
33 insn.addr.proto := SPIProtocol.Single
34 insn.pad.cnt := UInt(0)
35 insn.pad.code := Bits(0)
36 insn.data.proto := SPIProtocol.Single
41 class SPIFlashAddr(c: SPIFlashParamsBase) extends SPIBundle(c) {
42 val next = UInt(width = c.insnAddrBits)
43 val hold = UInt(width = c.insnAddrBits)
46 class SPIFlashMap(c: SPIFlashParamsBase) extends Module {
49 val ctrl = new SPIFlashControl(c).asInput
50 val addr = Decoupled(new SPIFlashAddr(c)).flip
51 val data = Decoupled(UInt(width = c.frameBits))
52 val link = new SPIInnerIO(c)
55 val addr = io.addr.bits.hold + UInt(1)
56 val merge = io.link.active && (io.addr.bits.next === addr)
58 private val insn = io.ctrl.insn
59 io.link.tx.valid := Bool(true)
60 io.link.fmt.proto := insn.addr.proto
61 io.link.fmt.iodir := SPIDirection.Tx
62 io.link.fmt.endian := io.ctrl.fmt.endian
64 SPIProtocol.decode(io.link.fmt.proto).zipWithIndex.map {
65 case (s, i) => (s -> UInt(c.frameBits >> i))
67 io.link.cs.set := Bool(true)
68 io.link.cs.clear := Bool(false)
69 io.link.cs.hold := Bool(true)
70 io.link.lock := Bool(true)
72 io.addr.ready := Bool(false)
73 io.data.valid := Bool(false)
74 io.data.bits := io.link.rx.bits
76 val cnt = Reg(UInt(width = math.max(c.insnPadLenBits, c.insnAddrLenBits)))
77 val cnt_en = Wire(init = Bool(false))
78 val cnt_cmp = (0 to c.insnAddrBytes).map(cnt === UInt(_))
79 val cnt_zero = cnt_cmp(0)
80 val cnt_last = cnt_cmp(1) && io.link.tx.ready
81 val cnt_done = cnt_last || cnt_zero
83 io.link.tx.valid := !cnt_zero
84 when (io.link.tx.fire()) {
89 val (s_idle :: s_cmd :: s_addr :: s_pad :: s_data_pre :: s_data_post :: Nil) = Enum(UInt(), 6)
90 val state = Reg(init = s_idle)
94 io.link.tx.valid := Bool(false)
96 io.addr.ready := Bool(true)
97 when (io.addr.valid) {
101 state := Mux(insn.cmd.en, s_cmd, s_addr)
102 io.link.cs.clear := Bool(true)
105 io.link.lock := Bool(false)
108 io.data.valid := io.addr.valid
109 io.addr.ready := io.data.ready
110 io.data.bits := UInt(0)
111 io.link.lock := Bool(false)
116 io.link.fmt.proto := insn.cmd.proto
117 io.link.tx.bits := insn.cmd.code
118 when (io.link.tx.ready) {
125 io.link.tx.bits := Mux1H(cnt_cmp.tail.zipWithIndex.map {
127 val n = i * c.frameBits
128 val m = n + (c.frameBits - 1)
129 s -> io.addr.bits.hold(m, n)
139 io.link.cnt := insn.pad.cnt
140 io.link.tx.bits := insn.pad.code
141 when (io.link.tx.ready) {
147 io.link.fmt.proto := insn.data.proto
148 io.link.fmt.iodir := SPIDirection.Rx
149 when (io.link.tx.ready) {
155 io.link.tx.valid := Bool(false)
156 io.data.valid := io.link.rx.valid
157 when (io.data.fire()) {