add SpiFlashSingle and rename SpiFlash to SpiFlashDualQuad

This commit is contained in:
Florent Kermarrec 2017-01-26 12:31:26 +01:00
parent f043a4f5ab
commit 4b77b850ce
1 changed files with 93 additions and 43 deletions

View File

@ -25,21 +25,17 @@ def _format_cmd(cmd, spi_width):
return c return c
class SpiFlash(Module, AutoCSR): class SpiFlashDualQuad(Module, AutoCSR):
def __init__(self, pads, dummy=15, div=2, with_bitbang=True): 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 Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
Read). Only supports mode0 (cpol=0, cpha=0). Read). Only supports mode0 (cpol=0, cpha=0).
Optionally supports software bitbanging (for write, erase, or other commands). Optionally supports software bitbanging (for write, erase, or other commands).
""" """
self.bus = bus = wishbone.Interface() self.bus = bus = wishbone.Interface()
spi_width = len(pads.dq) spi_width = len(pads.dq)
if with_bitbang: assert spi_width >= 2
self.bitbang = CSRStorage(4)
self.miso = CSRStatus()
self.bitbang_en = CSRStorage()
# # # # # #
@ -57,52 +53,19 @@ class SpiFlash(Module, AutoCSR):
read_cmd, cmd_width = read_cmd_params[spi_width] read_cmd, cmd_width = read_cmd_params[spi_width]
addr_width = 24 addr_width = 24
pads.cs_n.reset = 1
dq = TSTriple(spi_width) dq = TSTriple(spi_width)
self.specials.dq = dq.get_tristate(pads.dq) self.specials.dq = dq.get_tristate(pads.dq)
sr = Signal(max(cmd_width, addr_width, wbone_width)) sr = Signal(max(cmd_width, addr_width, wbone_width))
self.comb += bus.dat_r.eq(sr) self.comb += bus.dat_r.eq(sr)
hw_read_logic = [ self.comb += [
pads.clk.eq(clk), pads.clk.eq(clk),
pads.cs_n.eq(cs_n), pads.cs_n.eq(cs_n),
dq.o.eq(sr[-spi_width:]), dq.o.eq(sr[-spi_width:]),
dq.oe.eq(dq_oe) 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: if div < 2:
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
else: else:
@ -147,3 +110,90 @@ class SpiFlash(Module, AutoCSR):
t += dt t += dt
self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) 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)