From 4b77b850cefd2c9cdf427464fb33b4066ea74652 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Jan 2017 12:31:26 +0100 Subject: [PATCH] add SpiFlashSingle and rename SpiFlash to SpiFlashDualQuad --- litex/soc/cores/flash/spi_flash.py | 136 ++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/litex/soc/cores/flash/spi_flash.py b/litex/soc/cores/flash/spi_flash.py index 5bbec0b39..10190ae8a 100644 --- a/litex/soc/cores/flash/spi_flash.py +++ b/litex/soc/cores/flash/spi_flash.py @@ -25,23 +25,19 @@ def _format_cmd(cmd, spi_width): return c -class SpiFlash(Module, AutoCSR): - def __init__(self, pads, dummy=15, div=2, with_bitbang=True): +class SpiFlashDualQuad(Module, AutoCSR): + def __init__(self, pads, dummy=15, div=2): """ - Simple SPI flash, e.g. N25Q128 on the LX9 Microboard. - + Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). Optionally supports software bitbanging (for write, erase, or other commands). """ self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) - if with_bitbang: - self.bitbang = CSRStorage(4) - self.miso = CSRStatus() - self.bitbang_en = CSRStorage() + assert spi_width >= 2 - ### + # # # cs_n = Signal(reset=1) clk = Signal() @@ -57,52 +53,19 @@ class SpiFlash(Module, AutoCSR): read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 - pads.cs_n.reset = 1 - dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) self.comb += bus.dat_r.eq(sr) - hw_read_logic = [ + self.comb += [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] - if with_bitbang: - bitbang_logic = [ - pads.clk.eq(self.bitbang.storage[1]), - pads.cs_n.eq(self.bitbang.storage[2]), - If(self.bitbang.storage[3], - dq.oe.eq(0) - ).Else( - dq.oe.eq(1) - ), - If(self.bitbang.storage[1], - self.miso.status.eq(dq.i[1]) - ) - ] - if spi_width > 1: - bitbang_logic += [ - dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1))) - ] - else: - bitbang_logic += [ - dq.o.eq(self.bitbang.storage[0]) - ] - - self.comb += \ - If(self.bitbang_en.storage, - bitbang_logic - ).Else( - hw_read_logic - ) - else: - self.comb += hw_read_logic - if div < 2: raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) else: @@ -147,3 +110,90 @@ class SpiFlash(Module, AutoCSR): t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) + + +class SpiFlashSingle(Module, AutoCSR): + def __init__(self, pads, dummy=15, div=2): + """ + Simple SPI flash. + Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0). + Optionally supports software bitbanging (for write, erase, or other commands). + """ + self.bus = bus = wishbone.Interface() + + # # # + + if hasattr(pads, "wp"): + self.comb += pads.wp.eq(1) + + if hasattr(pads, "hold"): + self.comb += pads.hold.eq(1) + + cs_n = Signal(reset=1) + clk = Signal() + wbone_width = len(bus.dat_r) + + read_cmd = _FAST_READ + cmd_width = 8 + addr_width = 24 + + sr = Signal(max(cmd_width, addr_width, wbone_width)) + self.comb += bus.dat_r.eq(sr) + + self.comb += [ + pads.clk.eq(clk), + pads.cs_n.eq(cs_n), + pads.mosi.eq(sr[-1:]) + ] + + if div < 2: + raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) + else: + i = Signal(max=div) + miso = Signal() + self.sync += [ + If(i == div//2 - 1, + clk.eq(1), + miso.eq(pads.miso), + ), + If(i == div - 1, + i.eq(0), + clk.eq(0), + sr.eq(Cat(miso, sr[:-1])) + ).Else( + i.eq(i + 1), + ), + ] + + # spi is byte-addressed, prefix by zeros + z = Replicate(0, log2_int(wbone_width//8)) + + seq = [ + (cmd_width*div, + [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), + (addr_width*div, + [sr[-addr_width:].eq(Cat(z, bus.adr))]), + ((dummy + wbone_width)*div, + []), + (1, + [bus.ack.eq(1), cs_n.eq(1)]), + (div, # tSHSL! + [bus.ack.eq(0)]), + (0, + []), + ] + + # accumulate timeline deltas + t, tseq = 0, [] + for dt, a in seq: + tseq.append((t, a)) + t += dt + + self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) + + +def SpiFlash(pads, *args, **kw): + if hasattr(pads, "mosi"): + return SpiFlashSingle(pads, *args, **kw) + else: + return SpiFlashDualQuad(pads, *args, **kw)