add SpiFlashSingle and rename SpiFlash to SpiFlashDualQuad
This commit is contained in:
parent
f043a4f5ab
commit
4b77b850ce
|
@ -25,23 +25,19 @@ 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()
|
|
||||||
|
|
||||||
###
|
# # #
|
||||||
|
|
||||||
cs_n = Signal(reset=1)
|
cs_n = Signal(reset=1)
|
||||||
clk = Signal()
|
clk = Signal()
|
||||||
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue