litex/misoclib/mem/flash/norflash16.py

104 lines
2.9 KiB
Python
Raw Normal View History

2013-11-30 14:37:56 -05:00
from migen.fhdl.std import *
from migen.bus import wishbone
from migen.genlib.fsm import FSM, NextState
2015-04-13 10:47:22 -04:00
2013-11-30 14:37:56 -05:00
class NorFlash16(Module):
def __init__(self, pads, rd_timing, wr_timing):
self.bus = wishbone.Interface()
2013-11-30 14:37:56 -05:00
###
2013-11-30 14:37:56 -05:00
data = TSTriple(16)
lsb = Signal()
2013-11-30 14:37:56 -05:00
self.specials += data.get_tristate(pads.d)
self.comb += [
data.oe.eq(pads.oe_n),
pads.ce_n.eq(0)
]
2013-11-30 14:37:56 -05:00
load_lo = Signal()
load_hi = Signal()
store = Signal()
2013-11-30 14:37:56 -05:00
pads.oe_n.reset, pads.we_n.reset = 1, 1
self.sync += [
pads.oe_n.eq(1),
pads.we_n.eq(1),
2013-11-30 14:37:56 -05:00
# Register data/address to avoid off-chip glitches
If(self.bus.cyc & self.bus.stb,
pads.adr.eq(Cat(lsb, self.bus.adr)),
If(self.bus.we,
# Only 16-bit writes are supported. Assume sel=0011 or 1100.
If(self.bus.sel[0],
data.o.eq(self.bus.dat_w[:16])
).Else(
data.o.eq(self.bus.dat_w[16:])
)
).Else(
pads.oe_n.eq(0)
)
),
2013-11-30 14:37:56 -05:00
If(load_lo, self.bus.dat_r[:16].eq(data.i)),
If(load_hi, self.bus.dat_r[16:].eq(data.i)),
If(store, pads.we_n.eq(0))
]
2013-11-30 14:37:56 -05:00
# Typical timing of the flash chips:
# - 110ns address to output
# - 50ns write pulse width
counter = Signal(max=max(rd_timing, wr_timing)+1)
counter_en = Signal()
counter_wr_mode = Signal()
counter_done = Signal()
self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing))
self.sync += If(counter_en & ~counter_done,
counter.eq(counter + 1)
).Else(
counter.eq(0)
)
2013-11-30 14:37:56 -05:00
fsm = FSM()
self.submodules += fsm
2013-11-30 14:37:56 -05:00
fsm.act("IDLE",
If(self.bus.cyc & self.bus.stb,
If(self.bus.we,
NextState("WR")
).Else(
NextState("RD_HI")
)
)
)
fsm.act("RD_HI",
lsb.eq(0),
counter_en.eq(1),
If(counter_done,
load_hi.eq(1),
NextState("RD_LO")
)
)
fsm.act("RD_LO",
lsb.eq(1),
counter_en.eq(1),
If(counter_done,
load_lo.eq(1),
NextState("ACK")
)
)
fsm.act("WR",
# supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0]
lsb.eq(self.bus.sel[0]),
counter_wr_mode.eq(1),
counter_en.eq(1),
store.eq(1),
If(counter_done, NextState("ACK"))
)
fsm.act("ACK",
self.bus.ack.eq(1),
NextState("IDLE")
)