spiflash: add read-only variable data width spi flash
Signed-off-by: Robert Jordens <jordens@gmail.com>
This commit is contained in:
parent
b49e6f07b2
commit
5953f901c8
|
@ -0,0 +1,131 @@
|
|||
from migen.fhdl.std import *
|
||||
from migen.bus.transactions import *
|
||||
from migen.bus import wishbone
|
||||
from migen.genlib.misc import timeline
|
||||
from migen.genlib.record import Record
|
||||
|
||||
|
||||
class SpiFlash(Module):
|
||||
def __init__(self, pads, cmd=0xfffefeff, cmd_width=32, addr_width=24,
|
||||
dummy=15, div=2):
|
||||
"""
|
||||
Simple read-only SPI flash, e.g. N25Q128 on the LX9 Microboard.
|
||||
|
||||
Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
|
||||
Read). Only supports mode0 (cpol=0, cpha=0).
|
||||
|
||||
`cmd` is the read instruction. Since everything is transmitted on all
|
||||
dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq
|
||||
width even if dq1-dq3 are don't care during the command phase:
|
||||
For example, for N25Q128, 0xeb is the quad i/o fast read, and
|
||||
extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff
|
||||
"""
|
||||
self.bus = bus = wishbone.Interface()
|
||||
|
||||
##
|
||||
|
||||
wbone_width = flen(bus.dat_r)
|
||||
spi_width = flen(pads.dq)
|
||||
|
||||
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[:wbone_width]),
|
||||
dq.o.eq(sr[-spi_width:]),
|
||||
]
|
||||
|
||||
if div == 1:
|
||||
i = 0
|
||||
self.comb += pads.clk.eq(~ClockSignal())
|
||||
self.sync += sr.eq(Cat(dq.i, sr[:-spi_width]))
|
||||
else:
|
||||
i = Signal(max=div)
|
||||
dqi = Signal(spi_width)
|
||||
self.sync += [
|
||||
If(i == div//2 - 1,
|
||||
pads.clk.eq(1),
|
||||
dqi.eq(dq.i),
|
||||
),
|
||||
If(i == div - 1,
|
||||
i.eq(0),
|
||||
pads.clk.eq(0),
|
||||
sr.eq(Cat(dqi, sr[:-spi_width]))
|
||||
).Else(
|
||||
i.eq(i + 1),
|
||||
),
|
||||
]
|
||||
|
||||
# spi is byte-addressed, prefix by zeros
|
||||
z = Replicate(0, log2_int(wbone_width//8))
|
||||
|
||||
seq = [
|
||||
(cmd_width//spi_width*div,
|
||||
[dq.oe.eq(1), pads.cs_n.eq(0), sr[-cmd_width:].eq(cmd)]),
|
||||
(addr_width//spi_width*div,
|
||||
[sr[-addr_width:].eq(Cat(z, bus.adr))]),
|
||||
((dummy + wbone_width//spi_width)*div,
|
||||
[dq.oe.eq(0)]),
|
||||
(1,
|
||||
[bus.ack.eq(1), pads.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)
|
||||
|
||||
|
||||
|
||||
class SpiFlashTB(Module):
|
||||
def __init__(self):
|
||||
self.submodules.master = wishbone.Initiator(self.gen_reads())
|
||||
self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
|
||||
self.submodules.slave = SpiFlash(self.pads)
|
||||
self.submodules.tap = wishbone.Tap(self.slave.bus)
|
||||
self.submodules.intercon = wishbone.InterconnectPointToPoint(
|
||||
self.master.bus, self.slave.bus)
|
||||
self.cycle = 0
|
||||
|
||||
def gen_reads(self):
|
||||
for a in range(10):
|
||||
t = TRead(a)
|
||||
yield t
|
||||
print("read {} in {} cycles(s)".format(t.data, t.latency))
|
||||
|
||||
def do_simulation(self, s):
|
||||
if s.rd(self.pads.cs_n):
|
||||
self.cycle = 0
|
||||
else:
|
||||
self.cycle += 1
|
||||
if not s.rd(self.slave.dq.oe):
|
||||
s.wr(self.slave.dq.i, self.cycle & 0xf)
|
||||
s.interrupt = self.master.done
|
||||
|
||||
|
||||
def _main():
|
||||
from migen.sim.generic import Simulator, TopLevel
|
||||
from migen.fhdl import verilog
|
||||
|
||||
pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)])
|
||||
s = SpiFlash(pads)
|
||||
print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr,
|
||||
s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb}))
|
||||
|
||||
tb = SpiFlashTB()
|
||||
sim = Simulator(tb, TopLevel("spiflash.vcd"))
|
||||
sim.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
Loading…
Reference in New Issue