foboot/hw/rtl/picorvspi.py
Sean Cross 45e3b5b617 rtl: break foboot modules into their own files
These are all independent modules, so break each one out into its own
file.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-11-23 10:03:56 +08:00

127 lines
4.5 KiB
Python

from migen import Module, Signal, Cat, TSTriple, bits_for, ResetSignal, If, ClockSignal, Instance
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage, CSRField
from litex.soc.interconnect import wishbone
class PicoRVSpi(Module, AutoCSR):
def __init__(self, platform, pads, size=2*1024*1024):
self.size = size
self.bus = bus = wishbone.Interface()
self.reset = Signal()
self.cfg1 = CSRStorage(fields=[
CSRField("bb_out", size=4, description="Output bits in bit-bang mode"),
CSRField("bb_clk", description="Serial clock line in bit-bang mode"),
CSRField("bb_cs", description="Chip select line in bit-bang mode"),
])
self.cfg2 = CSRStorage(fields=[
CSRField("bb_oe", size=4, description="Output Enable bits in bit-bang mode"),
])
self.cfg3 = CSRStorage(fields=[
CSRField("rlat", size=4, description="Read latency/dummy cycle count"),
CSRField("crm", description="Continuous Read Mode enable bit"),
CSRField("qspi", description="Quad-SPI enable bit"),
CSRField("ddr", description="Double Data Rate enable bit"),
])
self.cfg4 = CSRStorage(fields=[
CSRField("memio", offset=7, reset=1, description="Enable memory-mapped mode (set to 0 to enable bit-bang mode)")
])
self.stat1 = CSRStatus(fields=[
CSRField("bb_in", size=4, description="Input bits in bit-bang mode"),
])
self.stat2 = CSRStatus(1, fields=[], description="Reserved")
self.stat3 = CSRStatus(1, fields=[], description="Reserved")
self.stat4 = CSRStatus(1, fields=[], description="Reserved")
cfg = Signal(32)
cfg_we = Signal(4)
cfg_out = Signal(32)
self.comb += [
cfg.eq(Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage, self.cfg4.storage)),
cfg_we.eq(Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)),
self.stat1.status.eq(cfg_out[0:8]),
self.stat2.status.eq(cfg_out[8:16]),
self.stat3.status.eq(cfg_out[16:24]),
self.stat4.status.eq(cfg_out[24:32]),
]
mosi_pad = TSTriple()
miso_pad = TSTriple()
cs_n_pad = TSTriple()
clk_pad = TSTriple()
wp_pad = TSTriple()
hold_pad = TSTriple()
self.specials += mosi_pad.get_tristate(pads.mosi)
self.specials += miso_pad.get_tristate(pads.miso)
self.specials += cs_n_pad.get_tristate(pads.cs_n)
self.specials += clk_pad.get_tristate(pads.clk)
self.specials += wp_pad.get_tristate(pads.wp)
self.specials += hold_pad.get_tristate(pads.hold)
reset = Signal()
self.comb += [
reset.eq(ResetSignal() | self.reset),
cs_n_pad.oe.eq(~reset),
clk_pad.oe.eq(~reset),
]
flash_addr = Signal(24)
# size/4 because data bus is 32 bits wide, -1 for base 0
mem_bits = bits_for(int(size/4)-1)
pad = Signal(2)
self.comb += flash_addr.eq(Cat(pad, bus.adr[0:mem_bits-1]))
read_active = Signal()
spi_ready = Signal()
self.sync += [
If(bus.stb & bus.cyc & ~read_active,
read_active.eq(1),
bus.ack.eq(0),
)
.Elif(read_active & spi_ready,
read_active.eq(0),
bus.ack.eq(1),
)
.Else(
bus.ack.eq(0),
read_active.eq(0),
)
]
o_rdata = Signal(32)
self.comb += bus.dat_r.eq(o_rdata)
self.specials += Instance("spimemio",
o_flash_io0_oe = mosi_pad.oe,
o_flash_io1_oe = miso_pad.oe,
o_flash_io2_oe = wp_pad.oe,
o_flash_io3_oe = hold_pad.oe,
o_flash_io0_do = mosi_pad.o,
o_flash_io1_do = miso_pad.o,
o_flash_io2_do = wp_pad.o,
o_flash_io3_do = hold_pad.o,
o_flash_csb = cs_n_pad.o,
o_flash_clk = clk_pad.o,
i_flash_io0_di = mosi_pad.i,
i_flash_io1_di = miso_pad.i,
i_flash_io2_di = wp_pad.i,
i_flash_io3_di = hold_pad.i,
i_resetn = ~reset,
i_clk = ClockSignal(),
i_valid = bus.stb & bus.cyc,
o_ready = spi_ready,
i_addr = flash_addr,
o_rdata = o_rdata,
i_cfgreg_we = cfg_we,
i_cfgreg_di = cfg,
o_cfgreg_do = cfg_out,
)
platform.add_source("rtl/spimemio.v")